diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..3eac7de8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 + +# Secrets and defaults should not have a newline at their eof. +[secrets/*,defaults/*] +end_of_line = lf +insert_final_newline = false +indent_size = 0 diff --git a/.env b/.env new file mode 100644 index 00000000..f215e66a --- /dev/null +++ b/.env @@ -0,0 +1,34 @@ +# Provide environment variables for configuring docker-compose, *not* the +# containers themselves. +# +# Note that this is simple string assignment, quotes should *not* be used. +# Multiple lines or commands, or bash syntax will not work. +# +# References: +# - https://docs.docker.com/compose/env-file/ +# - https://docs.docker.com/compose/reference/envvars/ +COMPOSE_PROJECT_NAME=isle-buildkit + +# Use buildkit when building images. +COMPOSE_DOCKER_CLI_BUILD=1 +DOCKER_BUILDKIT=1 + +# Required for traefik on OSX (inconsistent behavior). +DOCKER_CLIENT_TIMEOUT=120 +COMPOSE_HTTP_TIMEOUT=120 + +# The consistency requirements for bind mounts; one of: +# +# - consistent: Full consistency. The container runtime and the host maintain an identical view of the mount at all times. +# - cached: The host's view of the mount is authoritative. There may be delays before updates made on the host are visible within a container. +# - delegated: The container runtime's view of the mount is authoritative. There may be delays before updates made in a container are visible on the host. +# +# Note that using 'consistent' can be very slow. +CONSISTENCY=delegated + +# The Docker image repository, to use for isle-buildkit images. +# +REPOSITORY=islandora + +# The version of the isle-buildkit images to use. +TAG=local diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..07982fcb --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,58 @@ +name: Build +on: + workflow_call: + inputs: + repository: + required: true + type: string + image: + required: true + type: string + tags: + required: true + type: string + contexts: + required: false + type: string + outputs: + digest: + description: "Digest argument for Gradle" + value: ${{ jobs.build.outputs.digest }} + context: + description: "Context to use in dependent images" + value: ${{ jobs.build.outputs.context }} + secrets: + registry_user: + required: true + registry_password: + required: true +jobs: + build: + runs-on: ubuntu-latest + outputs: + digest: ${{ steps.build.outputs.digest }} + context: ${{ steps.build.outputs.context }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + with: + driver-opts: | + image=moby/buildkit:v0.11.1 + network=host + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + - id: build + name: Build and push + run: | + set -ex + make push manifest "PROGRESS=plain" "BUILDER=${{ steps.buildx.outputs.name }}" "TARGET=${{ inputs.image }}-ci" "TAGS=${{ inputs.tags }}" "CONTEXTS=${{ inputs.contexts }}" + echo "digest=-Pisle.${{ inputs.image }}.digest=${{ inputs.repository }}/${{ inputs.image }}@sha256:$(cat build/${{ inputs.image }}.digest)" >> $GITHUB_OUTPUT + echo "context=docker-image://${{ inputs.repository }}/${{ inputs.image }}@sha256:$(cat build/${{ inputs.image }}.digest)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml new file mode 100644 index 00000000..a1c3f485 --- /dev/null +++ b/.github/workflows/cleanup.yml @@ -0,0 +1,21 @@ +name: Delete old DockerHub tags +on: + schedule: + - cron: "0 13 * * 0" # Every Sunday at 1PM UTC (9AM EST) +jobs: + clean: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + arguments: | + deleteEligibleDockerHubTags + '-Pisle.dockerhub.personal.access.token=${{ secrets.registry_token }}' + --no-parallel diff --git a/.github/workflows/description.yml b/.github/workflows/description.yml new file mode 100644 index 00000000..101d1d59 --- /dev/null +++ b/.github/workflows/description.yml @@ -0,0 +1,219 @@ +name: Update Docker Hub Description +on: + push: + branches: + - main + paths: + - "**/README.md" + - "**/README.dockerhub.md" + - ".github/workflows/dockerhub-description.yml" +jobs: + description: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Fix Relative Paths + run: | + find . -maxdepth 2 -mindepth 2 -type f -name "README*.md" -exec sed -i 's/](\.\.\/\([^/]*\).*)/](.\/\1)/g' {} \; + + - name: ActiveMQ - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/activemq + readme-filepath: ./activemq/README.md + + - name: Alpaca - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/alpaca + readme-filepath: ./alpaca/README.md + + - name: Base - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/base + readme-filepath: ./base/README.md + + - name: Blazegraph - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/blazegraph + readme-filepath: ./blazegraph/README.md + + - name: cantaloupe - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/cantaloupe + readme-filepath: ./cantaloupe/README.dockerhub.md + + - name: Code-Server - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/code-server + readme-filepath: ./code-server/README.md + + - name: Crayfish - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/crayfish + readme-filepath: ./crayfish/README.md + + - name: CrayFits - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/crayfits + readme-filepath: ./crayfits/README.md + + - name: Drupal - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/drupal + readme-filepath: ./drupal/README.md + + - name: Fcrepo6 - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/fcrepo6 + readme-filepath: ./fcrepo6/README.md + + - name: Fits - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/fits + readme-filepath: ./fits/README.md + + - name: Handle - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/handle + readme-filepath: ./handle/README.md + + - name: Homarus - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/homarus + readme-filepath: ./homarus/README.md + + - name: Houdini - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/houdini + readme-filepath: ./houdini/README.md + + - name: hypercube - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/hypercube + readme-filepath: ./hypercube/README.md + + - name: Java - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/java + readme-filepath: ./java/README.md + + - name: MariaDB - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/mariadb + readme-filepath: ./mariadb/README.md + + - name: Matomo - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/matomo + readme-filepath: ./matomo/README.md + + - name: Milliner - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/milliner + readme-filepath: ./milliner/README.md + + - name: Nginx - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/nginx + readme-filepath: ./nginx/README.md + + - name: PostgreSQL - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/postgresql + readme-filepath: ./postgresql/README.md + + - name: RipRap - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/riprap + readme-filepath: ./riprap/README.md + + - name: Solr - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/solr + readme-filepath: ./solr/README.md + + - name: Test - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/tomcat + readme-filepath: ./test/README.md + + - name: Tomcat - Update Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + repository: islandora/tomcat + readme-filepath: ./tomcat/README.md diff --git a/.github/workflows/grype.yml b/.github/workflows/grype.yml new file mode 100644 index 00000000..c0b643b8 --- /dev/null +++ b/.github/workflows/grype.yml @@ -0,0 +1,40 @@ +name: Grype +on: + workflow_call: + inputs: + image: + required: true + type: string + digest: + required: true + type: string + secrets: + registry_user: + required: true + registry_password: + required: true +jobs: + grype: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + cache-read-only: false + arguments: ${{ inputs.image }}:grype ${{ inputs.digest }} --info + - uses: actions/upload-artifact@v3 + if: always() + with: + name: Grype Reports + path: build/**/*-grype.* diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 09961f4c..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: CI -on: - push: - branches: - - main -jobs: - build: - name: Build and Push Docker Images - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 8 - - name: Setup Gradle Cache - uses: actions/cache@v1 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Log in to Docker Hub - run: docker login -u '${{ secrets.REGISTRY_USER }}' -p '${{ secrets.REGISTRY_PASS }}' '${{ secrets.REGISTRY_URL }}' - - name: Enable buildkit - shell: bash - run: | - echo '{"experimental": "enabled"}' > ~/.docker/config.json - - name: Build Docker images - uses: eskatos/gradle-command-action@v1 - with: - arguments: build '-Prepository=${{ secrets.REPOSITORY }}' --info - - name: Push Docker images - uses: eskatos/gradle-command-action@v1 - with: - arguments: push '-Prepository=${{ secrets.REPOSITORY }}' '-PregistryUrl=${{ secrets.REGISTRY_URL }}' '-PregistryUsername=${{ secrets.REGISTRY_USER }}' '-PregistryPassword=${{ secrets.REGISTRY_PASS }}' --info - # @todo add tests. diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 7bfce633..3e0722ee 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,29 +1,656 @@ -name: CI +name: Build and Push Docker Images on: - pull_request: - branches: - - main + push: +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true jobs: - build: - name: Build Docker Images - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Java - uses: actions/setup-java@v1 - with: - java-version: 8 - - name: Setup Gradle Cache - uses: actions/cache@v1 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Build Docker images - uses: eskatos/gradle-command-action@v1 - with: - arguments: build --info - # @todo add tests. + ############################################################################# + ## Build. + ############################################################################# + tags: + uses: ./.github/workflows/tags.yml + with: + tag: ${{ github.ref_name }} + secrets: inherit + base: + uses: ./.github/workflows/build.yml + with: + image: base + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: tags + activemq: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.java.outputs.context }} + image: activemq + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, java] + alpaca: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.java.outputs.context }} + image: alpaca + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, java] + blazegraph: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.tomcat.outputs.context }} + image: blazegraph + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, tomcat] + cantaloupe: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.java.outputs.context }} + image: cantaloupe + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, java] + code-server: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.drupal.outputs.context }} + image: code-server + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, drupal] + crayfish: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.nginx.outputs.context }} + image: crayfish + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, nginx] + crayfits: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.nginx.outputs.context }} + image: crayfits + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, nginx] + drupal: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.nginx.outputs.context }} + image: drupal + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, nginx] + fcrepo6: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.tomcat.outputs.context }} + image: fcrepo6 + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, tomcat] + fits: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.tomcat.outputs.context }} + image: fits + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, tomcat] + handle: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.java.outputs.context }} + image: handle + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, java] + homarus: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.crayfish.outputs.context }} + image: homarus + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, crayfish] + houdini: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.crayfish.outputs.context }} + image: houdini + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, crayfish] + hypercube: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.crayfish.outputs.context }} + image: hypercube + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, crayfish] + java: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.base.outputs.context }} + image: java + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, base] + mariadb: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.base.outputs.context }} + image: mariadb + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, base] + matomo: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.nginx.outputs.context }} + image: matomo + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, nginx] + milliner: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.crayfish.outputs.context }} + image: milliner + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, crayfish] + nginx: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.base.outputs.context }} + image: nginx + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, base] + postgresql: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.base.outputs.context }} + image: postgresql + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, base] + riprap: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.nginx.outputs.context }} + image: riprap + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, nginx] + solr: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.java.outputs.context }} + image: solr + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, java] + test: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.drupal.outputs.context }} + image: test + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, drupal] + tomcat: + uses: ./.github/workflows/build.yml + with: + contexts: ${{ needs.java.outputs.context }} + image: tomcat + repository: ${{ vars.repository }} + tags: ${{ needs.tags.outputs.tags }} + secrets: inherit + needs: [tags, java] + ############################################################################# + ## Tests. + ############################################################################# + test-base: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.base.outputs.digest }} + image: base + secrets: inherit + needs: [base] + test-activemq: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.activemq.outputs.digest }} + image: activemq + secrets: inherit + needs: [activemq] + test-alpaca: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.activemq.outputs.digest }} + ${{ needs.alpaca.outputs.digest }} + image: alpaca + secrets: inherit + needs: + - activemq + - alpaca + test-blazegraph: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.blazegraph.outputs.digest }} + image: blazegraph + secrets: inherit + needs: [blazegraph] + test-cantaloupe: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.cantaloupe.outputs.digest }} + image: cantaloupe + secrets: inherit + needs: [cantaloupe] + test-code-server: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.code-server.outputs.digest }} + image: code-server + secrets: inherit + needs: [code-server] + test-crayfish: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.crayfish.outputs.digest }} + image: crayfish + secrets: inherit + needs: [crayfish] + test-crayfits: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.crayfits.outputs.digest }} + image: crayfits + secrets: inherit + needs: [crayfits] + test-drupal: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.drupal.outputs.digest }} + ${{ needs.mariadb.outputs.digest }} + ${{ needs.postgresql.outputs.digest }} + image: drupal + secrets: inherit + needs: + - drupal + - mariadb + - postgresql + test-fcrepo6: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.activemq.outputs.digest }} + ${{ needs.fcrepo6.outputs.digest }} + ${{ needs.mariadb.outputs.digest }} + ${{ needs.postgresql.outputs.digest }} + image: fcrepo6 + secrets: inherit + needs: + - activemq + - fcrepo6 + - mariadb + - postgresql + test-fits: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.fits.outputs.digest }} + image: fits + secrets: inherit + needs: [fits] + test-handle: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.handle.outputs.digest }} + ${{ needs.mariadb.outputs.digest }} + ${{ needs.postgresql.outputs.digest }} + image: handle + secrets: inherit + needs: + - handle + - mariadb + - postgresql + test-homarus: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.homarus.outputs.digest }} + image: homarus + secrets: inherit + needs: [homarus] + test-houdini: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.houdini.outputs.digest }} + image: houdini + secrets: inherit + needs: [houdini] + test-hypercube: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.hypercube.outputs.digest }} + image: hypercube + secrets: inherit + needs: [hypercube] + test-java: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.java.outputs.digest }} + image: java + secrets: inherit + needs: [java] + test-mariadb: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.mariadb.outputs.digest }} + image: mariadb + secrets: inherit + needs: [mariadb] + test-matomo: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.mariadb.outputs.digest }} + ${{ needs.matomo.outputs.digest }} + image: matomo + secrets: inherit + needs: + - mariadb + - matomo + test-milliner: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.milliner.outputs.digest }} + image: milliner + secrets: inherit + needs: [milliner] + test-nginx: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.nginx.outputs.digest }} + image: nginx + secrets: inherit + needs: [nginx] + test-postgresql: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.postgresql.outputs.digest }} + image: postgresql + secrets: inherit + needs: [postgresql] + test-riprap: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.riprap.outputs.digest }} + ${{ needs.mariadb.outputs.digest }} + ${{ needs.postgresql.outputs.digest }} + image: riprap + secrets: inherit + needs: + - riprap + - mariadb + - postgresql + test-solr: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.solr.outputs.digest }} + image: solr + secrets: inherit + needs: [solr] + test-test: + uses: ./.github/workflows/test.yml + with: + digests: >- + ${{ needs.activemq.outputs.digest }} + ${{ needs.alpaca.outputs.digest }} + ${{ needs.blazegraph.outputs.digest }} + ${{ needs.crayfits.outputs.digest }} + ${{ needs.fcrepo6.outputs.digest }} + ${{ needs.fits.outputs.digest }} + ${{ needs.homarus.outputs.digest }} + ${{ needs.houdini.outputs.digest }} + ${{ needs.hypercube.outputs.digest }} + ${{ needs.mariadb.outputs.digest }} + ${{ needs.milliner.outputs.digest }} + ${{ needs.solr.outputs.digest }} + ${{ needs.test.outputs.digest }} + image: test + secrets: inherit + needs: + - activemq + - alpaca + - blazegraph + - crayfits + - fcrepo6 + - fits + - homarus + - houdini + - hypercube + - mariadb + - milliner + - solr + - test + test-tomcat: + uses: ./.github/workflows/test.yml + with: + digests: ${{ needs.tomcat.outputs.digest }} + image: tomcat + secrets: inherit + needs: [tomcat] + ############################################################################# + ## Grype. + ############################################################################# + grype-base: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.base.outputs.digest }} + image: base + secrets: inherit + needs: [base] + grype-activemq: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.activemq.outputs.digest }} + image: activemq + secrets: inherit + needs: [activemq] + grype-alpaca: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.alpaca.outputs.digest }} + image: alpaca + secrets: inherit + needs: [alpaca] + grype-blazegraph: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.blazegraph.outputs.digest }} + image: blazegraph + secrets: inherit + needs: [blazegraph] + grype-cantaloupe: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.cantaloupe.outputs.digest }} + image: cantaloupe + secrets: inherit + needs: [cantaloupe] + grype-code-server: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.code-server.outputs.digest }} + image: code-server + secrets: inherit + needs: [code-server] + grype-crayfish: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.crayfish.outputs.digest }} + image: crayfish + secrets: inherit + needs: [crayfish] + grype-crayfits: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.crayfits.outputs.digest }} + image: crayfits + secrets: inherit + needs: [crayfits] + grype-drupal: + uses: ./.github/workflows/grype.yml + with: + digest: >- + ${{ needs.drupal.outputs.digest }} + image: drupal + secrets: inherit + needs: [drupal] + grype-fcrepo6: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.fcrepo6.outputs.digest }} + image: fcrepo6 + secrets: inherit + needs: [fcrepo6] + grype-fits: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.fits.outputs.digest }} + image: fits + secrets: inherit + needs: [fits] + grype-handle: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.handle.outputs.digest }} + image: handle + secrets: inherit + needs: [handle] + grype-homarus: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.homarus.outputs.digest }} + image: homarus + secrets: inherit + needs: [homarus] + grype-houdini: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.houdini.outputs.digest }} + image: houdini + secrets: inherit + needs: [houdini] + grype-hypercube: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.hypercube.outputs.digest }} + image: hypercube + secrets: inherit + needs: [hypercube] + grype-java: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.java.outputs.digest }} + image: java + secrets: inherit + needs: [java] + grype-mariadb: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.mariadb.outputs.digest }} + image: mariadb + secrets: inherit + needs: [mariadb] + grype-matomo: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.matomo.outputs.digest }} + image: matomo + secrets: inherit + needs: [matomo] + grype-milliner: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.milliner.outputs.digest }} + image: milliner + secrets: inherit + needs: [milliner] + grype-nginx: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.nginx.outputs.digest }} + image: nginx + secrets: inherit + needs: [nginx] + grype-postgresql: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.postgresql.outputs.digest }} + image: postgresql + secrets: inherit + needs: [postgresql] + grype-riprap: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.riprap.outputs.digest }} + image: riprap + secrets: inherit + needs: [riprap] + grype-solr: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.solr.outputs.digest }} + image: solr + secrets: inherit + needs: [solr] + grype-test: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.test.outputs.digest }} + image: test + secrets: inherit + needs: [test] + grype-tomcat: + uses: ./.github/workflows/grype.yml + with: + digest: ${{ needs.tomcat.outputs.digest }} + image: tomcat + secrets: inherit + needs: [tomcat] diff --git a/.github/workflows/tags.yml b/.github/workflows/tags.yml new file mode 100644 index 00000000..c59023b2 --- /dev/null +++ b/.github/workflows/tags.yml @@ -0,0 +1,34 @@ +name: Build +on: + workflow_call: + inputs: + tag: + required: true + type: string + outputs: + tags: + description: "Image Tags" + value: ${{ jobs.tags.outputs.tags }} +jobs: + tags: + runs-on: ubuntu-latest + outputs: + tags: ${{ steps.tags.outputs.tags }} + steps: + - id: tags + name: Set TAGS Environment Variable + run: | + TAG="${{ inputs.tag }}" + if awk '/^[0-9]+\.[0-9]+\.[0-9]+$/ { rc = 1; print $NF }; END { exit !rc }' <<< "${TAG}"; then + VERSION=( ${TAG//./ } ) # replace points, split into array + MAJOR=${VERSION[0]} + MINOR=${VERSION[1]} + TAGS="${TAG} ${MAJOR}.${MINOR} ${MAJOR}" + LATEST=$(git tag -l '*.*.*' --sort=version:refname | grep -v '-' | tail -n 1) + if [[ "${TAG}" == "${LATEST_TAG}" ]]; then + TAGS="${TAGS} latest" + fi + echo "tags=${TAGS}" >> $GITHUB_OUTPUT + else + echo "tags=${TAG}" >> $GITHUB_OUTPUT + fi diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..72767157 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,40 @@ +name: Test +on: + workflow_call: + inputs: + image: + required: true + type: string + digests: + required: true + type: string + secrets: + registry_user: + required: true + registry_password: + required: true +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.registry_user }} + password: ${{ secrets.registry_password }} + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + cache-read-only: false + arguments: ${{ inputs.image }}:test -Pisle.test.pull=true ${{ inputs.digests }} --info + - uses: actions/upload-artifact@v3 + if: always() + with: + name: Test Logs + path: build/**/*.log diff --git a/.gitignore b/.gitignore index cd8fe820..1407193f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ -.idea/ .gradle/ +.idea/ +.secrets /build scratch scratch.md -volumes -docker-compose.yml \ No newline at end of file + +# Used for adding platform / user specific changes. +docker-compose.override.yml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..f5105684 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +# We do not want to modify whitespace or add newlines to specific files, namely: +# - Certs +# - Keys +# - Patches (Should match 100% the source from which they were derived) +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: check-case-conflict + - id: check-json + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-yaml + - id: end-of-file-fixer + exclude: &format-exclude secrets/.*|defaults/.*|cert.pem.tmpl|private.key.tmpl|rootCA.pem.tmpl|admin.private.key.tmpl|admin.public.key.tmpl|private.key.tmpl|public.key.tmpl|.patch + - id: mixed-line-ending + - id: trailing-whitespace + exclude: *format-exclude + - repo: https://github.com/gruntwork-io/pre-commit + rev: v0.1.17 + hooks: + - id: shellcheck + exclude: &shell-exclude gradlew|.patch + - repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shfmt + files: finish + exclude: *shell-exclude diff --git a/.secrets b/.secrets new file mode 100644 index 00000000..e69de29b diff --git a/.vscode/settings.json b/.vscode/settings.json index 7d2d2398..9116903f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,5 +12,65 @@ "*.xml.tmpl": "xml", "drush": "shellscript", "composer": "shellscript" - } -} \ No newline at end of file + }, + "cSpell.words": [ + "abuild", + "anchore", + "autoconfigure", + "autowire", + "binarystorage", + "Blazegraph", + "buildkit", + "buildx", + "CAROOT", + "catchable", + "classpath", + "Confd", + "confdir", + "contenv", + "crayfits", + "crond", + "DOCKERHUB", + "elif", + "execline", + "execlineb", + "fastcgi", + "FCREPO", + "filesize", + "getenv", + "gradlew", + "grype", + "homarus", + "islandora", + "JNA", + "jsonld", + "karaf", + "KEEPALIVE", + "libc", + "Matomo", + "mkcert", + "MODESHAPE", + "mysqld", + "nativeplatform", + "noarch", + "nocopy", + "oneshot", + "Pisle", + "POSTGRESQL", + "proxied", + "ripgrep", + "rootfs", + "servlet", + "shellcheck", + "shfmt", + "SIGTERM", + "subsite", + "svwait", + "Syft", + "temurin", + "tmpl", + "traefik", + "triplestore", + "xdebug" + ] +} diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..6affc5c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,325 @@ +# Display help by default. +.DEFAULT_GOAL := help + +# Require bash to use foreach loops. +SHELL := bash + +# For text display in the shell. +RESET = $(shell tput sgr0) +RED = $(shell tput setaf 9) +BLUE = $(shell tput setaf 6) +TARGET_MAX_CHAR_NUM = 30 + +# Some targets will only be included if the appropriate condition is met. +SSH_AGENT_RUNNING := $(shell test -S "$${SSH_AUTH_SOCK}" && echo "true") + +# For some commands we must invoke a Windows executable if in the context of WSL. +IS_WSL := $(shell grep -q WSL /proc/version 2>/dev/null && echo "true") + +# Use the host mkcert.exe if executing make from WSL context. +MKCERT := $(if $(filter true,$(IS_WSL)),mkcert.exe,mkcert) + +# The location of root certificates. +CAROOT := $(if $(filter true,$(IS_WSL)),$(shell $(MKCERT) -CAROOT | xargs -0 wslpath -u),$(shell $(MKCERT) -CAROOT)) + +# Display text for requirements. +README_MESSAGE = ${BLUE}Consult the README.md for how to install requirements.${RESET}\n + +# Bash snippet to check for the existance an executable. +define executable-exists + @if ! command -v $(1) >/dev/null; \ + then \ + printf "${RED}Could not find executable: %s${RESET}\n${README_MESSAGE}" $(1); \ + exit 1; \ + fi +endef + +# Used to include host-platform specific docker compose files. +OS := $(shell uname -s | tr A-Z a-z) + +# Used to determine set TAGS when no explicit value provided, +# as well as to fetch branch specific remote caches when building. +BRANCH = $(shell git rev-parse --abbrev-ref HEAD) + +# The buildkit builder to use. +BUILDER ?= default + +# Were to push/pull from. +REPOSITORY ?= islandora + +PROGRESS ?= auto + +# Were to push/pull cache from. +CACHE_FROM_REPOSITORY ?= $(REPOSITORY) +CACHE_TO_REPOSITORY ?= $(REPOSITORY) + +# Tags to apply to all images loaded or pushed, space delimited. +TAGS ?= local + +# Targets in `docker-bake.hcl` to build if requested. +TARGET ?= default + +# Contexts can be used to override bake contexts when building +# reducing build times, etc. See the GitHub actions for an example. +CONTEXTS ?= + +# All images should be included in the bake files default target. +# It is the source of truth. +ALL_IMAGES = $(shell docker buildx bake --print default 2>/dev/null | jq -r '.target[].context') +TARGET_IMAGES = $(shell docker buildx bake --print $(TARGET) 2>/dev/null | jq -r '.target[].context') + +build: + mkdir -p build + +# This is a catch all target that is used to check for existance of an +# executable when declared as a dependency. +.PHONY: % +%: + $(call executable-exists,$@) + +# Checks for docker compose plugin. +.PHONY: docker-compose +docker-compose: MISSING_DOCKER_PLUGIN_MESSAGE = ${RED}docker compose plugin is not installed${RESET}\n${README_MESSAGE} +docker-compose: | docker + # Check for `docker compose` as compose version 2+ is used is assumed. + @if ! docker compose version &>/dev/null; \ + then \ + printf "$(MISSING_DOCKER_PLUGIN_MESSAGE)"; \ + exit 1; \ + fi + +# Checks for docker buildx plugin. +.PHONY: docker-buildx +docker-buildx: MISSING_DOCKER_BUILDX_PLUGIN_MESSAGE = ${RED}docker buildx plugin is not installed${RESET}\n${README_MESSAGE} +docker-buildx: | docker + # Check for `docker buildx` as we do not support building without it. + @if ! docker buildx version &>/dev/null; \ + then \ + printf "$(MISSING_DOCKER_BUILDX_PLUGIN_MESSAGE)"; \ + exit 1; \ + fi + +.git/hooks/pre-commit: | pre-commit +.git/hooks/pre-commit: + pre-commit install + +.PHONY: login +login: REGISTRIES = https://index.docker.io/v1/ +login: | docker jq +login: + @for registry in $(REGISTRIES); \ + do \ + if ! jq -e ".auths|keys|any(. == \"$$registry\")" ~/.docker/config.json &>/dev/null; \ + then \ + printf "Log into $$registry\n"; \ + docker login $$registry; \ + fi \ + done + +$(CAROOT)/rootCA-key.pem $(CAROOT)/rootCA.pem &: | $(MKCERT) + # Requires mkcert to be installed first (It may fail on some systems due to how Java is configured, but this can be ignored). + -$(MKCERT) -install + +# Using mkcert to generate local certificates rather than traefik certs +# as they often get revoked. +build/certs/cert.pem build/certs/privkey.pem build/certs/rootCA.pem build/certs/rootCA-key.pem &: $(CAROOT)/rootCA-key.pem $(CAROOT)/rootCA.pem | $(MKCERT) build + mkdir -p build/certs + $(MKCERT) -cert-file build/certs/cert.pem -key-file build/certs/privkey.pem \ + "*.islandora.dev" \ + "islandora.dev" \ + "*.islandora.io" \ + "islandora.io" \ + "*.islandora.info" \ + "islandora.info" \ + "localhost" \ + "127.0.0.1" \ + "::1" + cp "$(CAROOT)/rootCA-key.pem" build/certs/rootCA-key.pem + cp "$(CAROOT)/rootCA.pem" build/certs/rootCA.pem + +build/certs/tls.crt: build/certs/rootCA.pem + cp build/certs/rootCA.pem build/certs/tls.crt + +build/certs/tls.key: build/certs/rootCA-key.pem + cp build/certs/rootCA-key.pem build/certs/tls.key + +.PHONY: certs +## Generate certificates required for using docker compose. +certs: build/certs/tls.crt build/certs/tls.key + +# When doing local development it is preferable to have the containers nginx +# user have the same uid/gid as the host machine to prevent permission issues. +build/secrets/UID build/secrets/GID &: | id build + mkdir -p build/secrets + id -u > build/secrets/UID + id -g > build/secrets/GID + +# Mounting SSH-Agent socket is platform dependent. +docker-compose.override.yml: + @if [[ -S "$${SSH_AUTH_SOCK}" ]]; then \ + cp docker-compose.$(OS).yml docker-compose.override.yml; \ + fi + +# Prior to building we export the plan and then update it to include contexts, +# etc provided by the environment / user. +# Despite being a real target we make it PHONY so it is run everytime as $(TARGET) can change. +.PHONY: build/bake.json +.SILENT: build/bake.json +build/bake.json: | docker-buildx jq build + # Generate build plan for the given target and update the contexts if provided by the CI. + BRANCH=$(BRANCH) \ + CACHE_FROM_REPOSITORY=$(CACHE_FROM_REPOSITORY) \ + CACHE_TO_REPOSITORY=$(CACHE_TO_REPOSITORY) \ + REPOSITORY=$(REPOSITORY) \ + TAGS="$(TAGS)" \ + docker buildx bake --print $(TARGET) 2>/dev/null > build/bake.json; \ + for context in $(CONTEXTS); \ + do \ + context_image=$$(sed 's/^docker-image:\/\/[^\/]*\/\([^\/@:]*\).*/\1/' <<< $${context}); \ + jq "walk(if type == \"object\" and .contexts.$${context_image} then .contexts.$${context_image} = \"$${context}\" else . end)" build/bake.json > build/tmp.bake.json; \ + cp build/tmp.bake.json build/bake.json; \ + rm build/tmp.bake.json; \ + done + # Remove unreferenced targets, as they complicate generating the manifest, etc. + docker buildx bake --print -f build/bake.json 2>/dev/null > build/tmp.bake.json + cp build/tmp.bake.json build/bake.json + rm build/tmp.bake.json + +.SILENT: build/manifests.json +build/manifests.json: build/bake.json + jq '[.target[].tags[]] | reduce .[] as $$i ({}; .[$$i | sub("-(arm64|amd64)$$"; "")] = ([$$i] + .[$$i | sub("-(arm64|amd64)$$"; "")] | sort))' build/bake.json > build/manifests.json + +.PHONY: bake +## Builds and loads the target(s) into the local docker context. +bake: build/bake.json + docker buildx bake --builder $(BUILDER) -f build/bake.json --progress=$(PROGRESS) --load + +.PHONY: push +## Builds and pushes the target(s) into remote repository. +push: build/bake.json login +push: + docker buildx bake --builder $(BUILDER) -f build/bake.json --progress=$(PROGRESS) --push + +.PHONY: manifest +## Creates manifest for multi-arch images. +manifest: build/manifests.json $(filter push,$(MAKECMDGOALS)) | jq + # Since this is only really used by the Github Actions it's built to assume a single target at a time. + MANIFESTS=(); \ + while IFS= read -r line; do \ + MANIFESTS+=( "$$line" ); \ + done < <(jq -r '. | to_entries | reduce .[] as $$i ([]; . + ["\($$i.key) \($$i.value | join(" "))"]) | .[]' build/manifests.json); \ + for args in "$${MANIFESTS[@]}"; \ + do \ + docker buildx imagetools create -t $${args}; \ + done + # After creating the manifests we can fetch the digests to use as contexts in later builds. + DIGESTS=(); \ + while IFS= read -r line; do \ + DIGESTS+=( "$$line" ); \ + done < <(jq -r 'keys | reduce .[] as $$i ({}; .[$$i | sub("^[^/]+/(?[^@:]+).*$$"; "\(.x)")] = $$i) | to_entries[] | "\(.key) \(.value)"' build/manifests.json); \ + for digest in "$${DIGESTS[@]}"; \ + do \ + args=($${digest}); \ + context=$${args[0]}; \ + image=$${args[1]}; \ + docker buildx imagetools inspect --raw $${image} | shasum -a 256 | cut -f1 -d' ' | tr -d '\n' > build/$${context}.digest; \ + done + +.PHONY: up +## Starts up the local development environment. +up: build/certs/cert.pem build/certs/privkey.pem build/certs/rootCA.pem +up: build/secrets/UID build/secrets/GID +up: $(if $(filter true,$(SSH_AGENT_RUNNING)),docker-compose.override.yml) +up: $(filter down,$(MAKECMDGOALS)) +up: bake | docker-compose + # jetbrains cache / config is created externally so it will persist indefinitely. + docker volume create jetbrains-cache + docker volume create jetbrains-config + docker compose up -d + @printf "Waiting for installation..." + @docker compose exec drupal timeout 600 bash -c "while ! test -f /installed; do sleep 5; done" + @printf " Credentials:\n" + @printf " ${RED}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${BLUE}%s${RESET}\n" "Username" "admin" + @printf " ${RED}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${BLUE}%s${RESET}\n" "Password" "password" + @printf "\n Services Available:\n" + @for link in \ + "Drupal|https://islandora.dev" \ + "IDE|https://ide.islandora.dev" \ + "ActiveMQ|https://activemq.islandora.dev" \ + "Blazegraph|https://blazegraph.islandora.dev/bigdata/" \ + "Fedora|https://fcrepo.islandora.dev/fcrepo/rest/" \ + "Matomo|https://islandora.dev/matomo/index.php" \ + "Cantaloupe|https://islandora.dev/cantaloupe" \ + "Solr|https://solr.islandora.dev" \ + "Traefik|https://traefik.islandora.dev" \ + ; \ + do \ + echo $$link | tr -s '|' '\000' | xargs -0 -n2 printf " ${RED}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${BLUE}%s${RESET}"; \ + done + +.PHONY: stop +## Stops the local development environment. +stop: | docker-compose + docker compose stop + +.PHONY: down +## Stops the local development environment and destroys volumes. +down: | docker-compose + docker compose down -v + +.PHONY: clean +## Destroys local environment and cleans up any uncommitted files. +clean: down | git + git clean -xfd . + +.PHONY: setup +## Checks that all required tools are installed (Installs pre-commit). +setup: .git/hooks/pre-commit | git docker-compose docker-buildx jq awk $(MKCERT) + +.PHONY: help +.SILENT: help +## Displays this help message. +help: | awk + @echo '' + @echo 'Usage:' + @echo ' ${RED}make${RESET} ${BLUE}${RESET}' + @echo '' + @echo 'BuildKit:' + @awk '/^[a-zA-Z\-_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = $$1; sub(/:$$/, "", helpCommand); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + if (helpCommand == "bake" || helpCommand == "push" || helpCommand == "manifest") { \ + printf " ${RED}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${BLUE}%s${RESET}\n", helpCommand, helpMessage; \ + } \ + } \ + } \ + {lastLine = $$0}' $(MAKEFILE_LIST) + @echo '' + @echo 'Compose:' + @awk '/^[a-zA-Z\-_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = $$1; sub(/:$$/, "", helpCommand); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + if (helpCommand == "certs" || helpCommand == "up" || helpCommand == "stop" || helpCommand == "down") { \ + printf " ${RED}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${BLUE}%s${RESET}\n", helpCommand, helpMessage; \ + } \ + } \ + } \ + {lastLine = $$0}' $(MAKEFILE_LIST) + @echo '' + @echo 'General:' + @awk '/^[a-zA-Z\-_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = $$1; sub(/:$$/, "", helpCommand); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + if (helpCommand == "setup" || helpCommand == "clean" || helpCommand == "help" || helpCommand == "test") { \ + printf " ${RED}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${BLUE}%s${RESET}\n", helpCommand, helpMessage; \ + } \ + } \ + } \ + {lastLine = $$0}' $(MAKEFILE_LIST) + @echo '' diff --git a/README.md b/README.md index 7a5ac114..0d9e0f4d 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,148 @@ # ISLE: Docker Prototype [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE) -![CI](https://github.com/Islandora-Devops/isle-buildkit/workflows/CI/badge.svg?branch=main) +[![Build and Push Docker Images](https://github.com/Islandora-Devops/isle-buildkit/actions/workflows/push.yml/badge.svg)](https://github.com/Islandora-Devops/isle-buildkit/actions/workflows/push.yml) - [Introduction](#introduction) - [Requirements](#requirements) + - [Windows](#windows) +- [Tooling](#tooling) + - [Make](#make) + - [Gradle](#gradle) + - [Github Actions](#github-actions) - [Building](#building) - [Build All Images](#build-all-images) - - [Building without Buildkit](#building-without-buildkit) - [Build Specific Image](#build-specific-image) - - [Building Continuously](#building-continuously) +- [Testing](#testing) + - [Test Specific Image](#test-specific-image) - [Running](#running) + - [IDE](#ide) + - [PHPStorm](#phpstorm) - [Docker Images](#docker-images) + - [Updating Dependencies](#updating-dependencies) + - [Updating Composer](#updating-composer) + - [Updating Configuration](#updating-configuration) - [Design Considerations](#design-considerations) - [Confd](#confd) - [S6 Overlay](#s6-overlay) - [Image Hierarchy](#image-hierarchy) - [Folder Layout](#folder-layout) - [Build System](#build-system) + - [Multi-arch builds](#multi-arch-builds) + - [Caching](#caching) - [Design Constraints](#design-constraints) - [Issues / FAQ](#issues--faq) ## Introduction This repository provides a number of docker images which can be used to build an -Islandora 8 site. +Islandora site. On commit, these images are automatically pushed to +[Docker Hub] via Github Actions. Which are consumed by [isle-dc] and +[isle-site-template]. They can also be used by other Docker orchestration tools +such as Swarm / Kubernetes. Reach out on the community slack for other example +installations. + +It is **not** meant as a starting point for new users or those unfamiliar with +Docker, or basic server administration. + +If you are looking to use islandora please read the [official documentation] and +use either [isle-dc] or the [isle-site-template] to deploy via [Docker] or the +[islandora-playbook] to deploy via [Ansible]. ## Requirements -To build the Docker images using the provided Gradle build scripts with [BuildKit] requires: +To build the Docker images using the provided Gradle build scripts requires: -- [Docker 18.09+](https://docs.docker.com/get-docker/) -- [OpenJDK or Oracle JDK 8+](https://www.java.com/en/download/) +- [Docker 20.10+](https://docs.docker.com/get-docker/) +- [GNU Make 4.3+](https://www.gnu.org/software/make/) +- [jq 1.6+](https://stedolan.github.io/jq/) +- [mkcert 1.4+](https://github.com/FiloSottile/mkcert) +- [OpenJDK or Oracle JDK 11+](https://www.java.com/en/download/) +- [pre-commit 2.19+](https://pre-commit.com/) -That being said the images themselves are compatible of running with older -versions of Docker. +> N.B You can use older versions of Docker to run the images, just not build +> them. -## Building +> N.B If you use Firefox you will also have to install `nss` to use `mkcert` see +> the [docs](https://github.com/FiloSottile/mkcert#installation). + +> N.B The version of `make` that comes with OSX is to old, please update +> using `brew` etc. + +To verify you have all the requirements run the following command. + +```bash +make setup +``` + +If it is unsuccessful you should see the following message: + +```bash +Could not find executable: XXXX +Consult the README.md for how to install requirements. +``` + +### Windows + +Since this repository relies on `make` you must use WSL2 to invoke it, and all +dependencies should be installed inside of the WSL2 context. With the exeception +of `mkcert` which must be installed in the host Windows context, as it needs to +modify the Windows trust store so that the browsers will support the generated +certificates. + +> N.B Firefox is not a supported browser on Windows for this project, you must +> use Edge or Chrome. + +## Tooling + +There are a number of tools you can use to [build](#building) and +[test](#testing) the images produced by this repository. In general there are +tools like `docker buildx` and `docker compose` that can be invoked directly or +you can the wrapper tools like [make](#make), [gradle](#gradle). Using the +wrapper tools has some advantages and is generally recommended, but it is +occasionally good to revert to the tools they wrap around if you need to debug +an issue with the building or testing. + +### Make + +[Building](#building) and [running](#running) relies on Make. You can see the +tasks available by invoking Make with no arguments. Make is really only +supported in Linux/OSX, or if you are using Windows you can use +[Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/install) + +```bash +make +``` + +Which yields: -The build scripts rely on Gradle and should function equally well across -platforms. The only difference being the script you call to interact with gradle -(the following assumes you are executing from the **root directory** of the -project): +```bash +Usage: + make + +BuildKit: + bake Builds and loads the target(s) into the local docker context. + push Builds and pushes the target(s) into remote repository. + manifest Creates manifest for multi-arch images. + +Compose: + up Starts up the local development environment. + down Stops the local development environment. + +General: + test Run all tests + clean Destroys local environment and cleans up any uncommitted files. + purge Destroys all data. + help Displays this help message. +``` + +### Gradle + +[Testing](#testing) and [generating security reports](#grype) as well as +[DockerHub maintenance](#dockerhub) rely on Gradle and should function equally +well across platforms. The only difference being the script you call to interact +with gradle (the following assumes you are executing from the **root directory** +of the project): **Linux or OSX:** @@ -75,222 +176,549 @@ Tasks runnable from root project ------------------------------------------------------------ ... - -Islandora tasks ---------------- -abuild:build - Creates Docker image. -activemq:build - Creates Docker image. -alpaca:build - Creates Docker image. -base:build - Creates Docker image. +Isle DockerHub tasks +-------------------- +deleteEligibleDockerHubTags - Delete eligible tags from DockerHub 'islandora/cache' Repository. +getDockerHubTagsEligibleForDeletion - Gets the tags eligible for removal from DockerHub 'islandora/cache' Repository. +getDockerHubToken - Gets the login token required for interacting with DockerHub Rest API. +getProtectedDockerHubTags - Gets the tags which should not be removed by DockerHub cleanup inactive tags task. + +Isle Reports tasks +------------------ +grype - Process the software bill of material with Grype +pullGrype - Pull anchore/grype docker image +pullSyft - Pull anchore/syft docker image +syft - Generate a software bill of material with Syft +updateGrypeDB - Update the Grype Database + +Isle Tests tasks +---------------- +cleanUpAfter - Clean up resources after running test +cleanUpBefore - Clean up resources before running test (if interrupted externally, etc) +setUp - Prepare to run test +test - Perform test ... ``` In Gradle each Project maps onto a folder in the file system path where it is -delimited by ``:`` instead of ``/`` (Unix) or ``\`` (Windows). +delimited by `:` instead of `/` (Unix) or `\` (Windows). -The root project ``:`` can be omitted. +The root project `:` can be omitted. -So if you want to run a particular task ``taskname`` that resided in the project -folder ``project/subproject`` you would specify it like so: +So if you want to run a particular task `taskname` that resided in the project +folder `project/subproject` you would specify it like so: ```bash ./gradlew :project:subproject:taskname ``` -To get more verbose output from Gradle use the ``--info`` argument like so: +To get more verbose output from Gradle use the `--info` argument like so: ```bash ./gradlew :PROJECT:TASK --info ``` -To build all the docker images you can use the following command: +### Github Actions + +This repository makes use of [Github Actions] to perform a number of tasks. + +| Workflow | Description | +| :----------------------------------------------------------------------- | :--------------------------------------------------------------------- | +| [cleanup.yml](.github/workflows/cleanup.yml) | Deletes old tags in DockerHub once a week. | +| [dockerhub-description.yml](.github/workflows/dockerhub-description.yml) | Updates DockerHub Description of images to match README.md files. | +| [push.yml](.github/workflows/push.yml) | Builds and Tests images and generates a security vulnerability report. | + +## Building + +This repository makes use of [buildx] which is a wrapper around [buildkit] to +build all the images. This can be invoked directly like so: + +```bash +docker buildx bake +``` + +By default if no `` is specified it will build all the images in this +repository. + +Alternatively you can use `make` to invoke `bake`, it is advantageous as it will +pass in additional properties that should allow you to make use of the remote +cache. + +```bash +make bake +``` + +If you want to build cross platform issues, please use the [isle-builder] +repository for setting up a builder. ### Build All Images The following will build all the images in the correct order. ```bash -./gradlew build +make bake ``` -### Building without Buildkit - -If you are having trouble building, consider building without BuildKit as it's -supported by older versions of Docker. +By default this will produce images like `islandora/base:local` you can change +the repository and tag by specifying them as arguments, like so: ```bash -./gradlew build -PuseBuildKit=false +make bake REPOSITORY=foo TAGS=bar ``` +This would produce images like `foo/base:bar`. + ### Build Specific Image To build a specific image and it's dependencies, for example -``islandora/tomcat``, you can use the following: +`islandora/tomcat`, you can use the following: ```bash -./gradlew tomcat:build +make bake TARGET=tomcat ``` -### Building Continuously +If you do not want to build all it's dependent images you can set the context +using existing images like so: -It is often helpful to build continuously where-in any change you make to any of -the Dockerfiles or other project files, will automatically trigger the building -of that image and any downstream dependencies. To do this add the -``--continuous`` flag like so: +```bash +make bake TARGET=nginx CONTEXTS="docker-image://islandora/base:1.0.10" +``` + +> N.B. Github actions do this to prevent rebuilding dependant images. + +## Testing + +There are a number of automated tests that are included in this repository which +can be found in the `tests` folders of each docker image project. + +To run these tests use the following command: ```bash -./gradlew build --continuous +./gradlew test ``` -When this is combined with the use of ``watchtower`` and -``restart: unless-stopped`` in a ``docker-compose.yml`` file. Images will be -redeployed with the latest changes while you develop automatically. +> N.B. Running all tests concurrently can saturate Docker's default number of +> bridge networks. Please see the [Issues/FAQ](#issues--faq) for how to remedy +> this. + +### Test Specific Image + +Alternatively you can test a single image like so: + +```bash +./gradlew tomcat:test +``` ## Running -There is no method for running the containers in `isle-buildkit`, instead please -refer to . +While `isle-buildkit` does provide a test environment, it is not meant for +development on Islandora or as production environment. It is meant for testing +for breaking changes to the images provided by this repository. Instead please +refer to [isle-dc], or the [isle-site-template], for how to build your own +Islandora site. + +To manually test changes in a functioning environment you can use the provided +`docker-compose.yml` file. + +Though you must **first** generate certificates for use by `traefik`. + +```bash +make certs +``` + +> N.B. This will prompt you for a password as generating a root Certificate +> requires administrative privileges. + +You can interact with the `docker compose` directly instead of using +`make`. + +```bash +docker compose up -d +``` + +Although you can interact with `docker compose` directly, it is recommend you +use `make` as this will ensure you have build all the images and generated the +required certificates needed, etc: + +```bash +make up +``` + +This will bring up the environment based on [islandora-starter-site]. When +completed a message will print like so: + +``` +Waiting for installation... + + Credentials: + Username admin + Password password + + Services Available: + Drupal https://islandora.dev + IDE https://ide.islandora.dev + ActiveMQ https://activemq.islandora.dev + Blazegraph https://blazegraph.islandora.dev/bigdata/ + Fedora https://fcrepo.islandora.dev/fcrepo/rest/ + Matomo https://islandora.dev/matomo/index.php + Solr https://solr.islandora.dev + Traefik https://traefik.islandora.dev +``` + +To **stop** the containers use the following command: + +```bash +make stop +``` + +To **destroy** this environment use the following command: + +```bash +make down +``` + +The two commands can be used at once to ensure you are starting from a clean +environment: + +```bash +make down up +``` + +### IDE + +An `IDE` is provided at which includes: + +- Intellisense & Code Completion +- Build tasks for performing lints & other common actions (accessible via `CTRL-B` or `CMD-B`) +- Integrated Debugger (`XDebug`) +- `PHPCS` / `PHPCBF` +- etc... + +To enable `XDebug` when using `drush` via the built-in terminal enter the +following command before invoking `drush`: + +```bash +export XDEBUG_SESSION=1 +``` + +For web requests, you must also send an `XDEBUG_SESSION` cookie with your +request, this can be toggled on and off via a browser plugin such as the +following. + +- [Chrome](https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc?hl=en) +- [Firefox](https://addons.mozilla.org/en-GB/firefox/addon/xdebug-helper-for-firefox/) + + +### PHPStorm + +PHPStorm and alternative IDE's which allow for remote development via SSH are +also supported. + +Add the following to your `~/.ssh/config` file: + +```txt +Host islandora.dev + ForwardAgent yes + PasswordAuthentication yes + Port 2222 + PreferredAuthentications password + PubkeyAuthentication no + StrictHostKeyChecking no + User nginx + UserKnownHostsFile /dev/null +``` + +You should now be able to ssh like so (assuming you've already brought the +docker compose environment up): + +```bash +ssh islandora.dev +``` + +You can then connect via the PHP remote development feature. + +![PHPStorm](./docs/assets/phpstorm.gif) + +> N.B. PHPStorm remote is not supported form Arm architectures so the above will +> not work on M1 macbooks and later. + ## Docker Images The following docker images are provided: -- [abuild](./abuild/README.md) -- [activemq](./activemq/README.md) -- [alpaca](./alpaca/README.md) -- [base](./base/README.md) -- [blazegraph](./blazegraph/README.md) -- [build](./build/README.md) -- [cantaloupe](./cantaloupe/README.md) -- [crayfish](./crayfish/README.md) -- [crayfits](./crayfits/README.md) -- [drupal](./drupal/README.md) -- [fcrepo](./fcrepo/README.md) -- [fits](./fits/README.md) -- [gemini](./gemini/README.md) -- [homarus](./homarus/README.md) -- [houdini](./houdini/README.md) -- [hypercube](./hypercube/README.md) -- [imagemagick](./imagemagick/README.md) -- [java](./java/README.md) -- [karaf](./karaf/README.md) -- [mariadb](./mariadb/README.md) -- [matomo](./matomo/README.md) -- [milliner](./milliner/README.md) -- [nginx](./nginx/README.md) -- [recast](./recast/README.md) -- [demo](./demo/README.md) -- [solr](./solr/README.md) -- [tomcat](./tomcat/README.md) +- [activemq] +- [alpaca] +- [base] +- [blazegraph] +- [cantaloupe] +- [crayfish] +- [crayfits] +- [drupal] +- [fcrepo6] +- [fits] +- [handle] +- [homarus] +- [houdini] +- [hypercube] +- [java] +- [mariadb] +- [matomo] +- [milliner] +- [nginx] +- [postgresql] +- [ripgrep] +- [solr] +- [test] +- [tomcat] Many are intermediate images used to build other images in the list, for example -[java](./java/README.md). Please see the README of each image to find out what -settings, and ports, are exposed and what functionality it provides. +[java](./java/README.md). Please see the `README.md` of each image to find out +what settings, and ports, are exposed and what functionality it provides, as +well as how to update it to the latest releases. + +Additionally this repository consumes [imagemagick] & [leptonica] images +produced by a separate repositories. Since it is a standalone image that rarely +changes and takes a while to build, due to building it under emulation. + +### Updating Dependencies + +To update the dependencies of a image follow this general pattern, for example [alpaca]. + +Update the following `ARG` values in + +```dockerfile +ARG ALPACA_VERSION="x.x.x" +ARG ALPACA_FILE_SHA256="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +``` + +You'll have to download the new version you wish to update to, you can construct +the url from the the following `ARG` values in the [Dockerfile](./alpaca/Dockerfile), +to generate the `sha256` value to put in the above `ARG`. + +```dockerfile +ARG ALPACA_VERSION="x.x.x" +ARG ALPACA_FILE="islandora-alpaca-app-${ALPACA_VERSION}-all.jar" +ARG ALPACA_URL="https://repo1.maven.org/maven2/ca/islandora/alpaca/islandora-alpaca-app/${ALPACA_VERSION}/${ALPACA_FILE}" +``` + +For example for the version `x.x.x`: + +```bash +ALPACA_VERSION="x.x.x" +ALPACA_FILE="islandora-alpaca-app-${ALPACA_VERSION}-all.jar" +ALPACA_URL="https://repo1.maven.org/maven2/ca/islandora/alpaca/islandora-alpaca-app/${ALPACA_VERSION}/${ALPACA_FILE}" +wget "${ALPACA_URL}" &>/dev/null +shasum -a 256 ${ALPACA_FILE} +``` + +> N.B. Please read the release notes the new version and account for any changes +> to configuration that are required, as well as test locally. + +#### Updating Composer + +A number of images like [crayfish] provide a `composer.lock` file to pin them to +particular dependencies. + +When updating the dependencies be sure to search for `composer.lock` in the +`rootfs` folder of the image and update them as well. + +This can be done by running the image after +[updating dependencies](#updating-dependencies), to get the latest code, and +running composer update. For example [crayfish]: + +```bash +# Update ARGS as done in previous section +# ... +# Build image +make bake TARGET=crayfish +for lock in $(find crayfish -name "composer.lock"); \ +do \ + docker run --rm -ti -v "$(pwd)/${lock}:${lock#crayfish/rootfs*}" -w $(dirname "${lock#crayfish/rootfs*}") --entrypoint composer islandora/crayfish:local update; \ +done +``` + +### Updating Configuration + +In particular review the files in +[rootfs/etc/confd](./alpaca/rootfs/etc/confd/), as configuration is likely to +change between releases. + ## Design Considerations All of the images build by this project are derived from the -[Alpine Docker Image](https://hub.docker.com/_/alpine) which is a Linux -distribution built around ``musl`` ``libc`` and ``BusyBox``. The image is only 5 -MB in size and has access to a package repository. It has been chosen for its -small size, and ease of generating custom packages (as is done in the -[imagemagick](./imagemagick/README.md) image). +[Alpine Docker Image] which is a Linux distribution built around [musl libc] and +[BusyBox]. -The [base](./base/README.md) image includes two tools essential to the -functioning of all the images. +> N.B. While [musl libc] is of general higher quality vs. [glibc], it is less +> commonly used and many libraries have come to depend on the undefined behavior +> of [glibc] so in some of our images we patch in [glibc] to ensure their +> correct function. -- [Confd](https://github.com/kelseyhightower/confd) - Configuration Management -- [S6 Overlay](https://github.com/just-containers/s6-overlay) - Process Manager - / Initialization system. +The image is only `5MB` in size and has access to a package repository. It has +been chosen for its small size, and ease of generating custom packages (as is +done in the [imagemagick] & [leptonica] images). + +The [base] image includes two tools essential to the functioning of all the +images. + +- [Confd]: Configuration Management +- [S6 Overlay]: Process Manager / Initialization system ### Confd -``confd`` is used for all Configuration Management, it is how images are +`confd` is used for all Configuration Management, it is how images are customized on startup and during runtime. For each Docker image there will be a -folder ``rootfs/etc/confd`` that has the following layout: +folder `rootfs/etc/confd` that has the following layout: ```bash ./rootfs/etc/confd ├── conf.d │ └── file.ext.toml -├── confd.toml └── templates └── file.ext.tmpl ``` -``confd.toml`` Is the configuration of ``confd`` and will typically limit the -namespace from which ``confd`` will read key values. For example in ``activemq``: +The `file.ext.toml` and `file.ext.tmpl` work as a pair. The `toml` file +defines where the template will be render to and who owns it. The `tmpl` file +being the template in question. Ideally these files should match the same name +of the file they are generating minus the `toml` or `tmpl` suffix. This is +to make their discovery easier. + +Additionally in the `base` image there is `confd.toml` which sets defaults +such a the `log-level`: ```toml backend = "env" confdir = "/etc/confd" -log-level = "debug" +log-level = "error" interval = 600 noop = false -prefix = "/activemq" ``` -The prefix is set to ``/activemq`` which means only keys / value pairs under -this prefix can be used by templates. We restrict images by prefix to force them -to define their own settings, reducing dependencies between images, and to allow -for greater customization. For example you could have Gemini use PostgreSQL as a -backend and Drupal using MariaDB since they do not share the same Database -configuration. +`confd` is also the source of all truth when it comes to configuration. We +have established a order of precedence in which environment variables at runtime +are defined. + +1. Confd backend (highest) +2. Secrets kept in `/run/secrets` (Except when using `Kubernetes`) +3. Environment variables passed into the container +4. Environment variables defined in Dockerfile(s) +5. Environment variables defined in the `/etc/defaults` directory (lowest only used for multiline variables, such as JWT) -The ``file.ext.toml`` and ``file.ext.tmpl`` work as a pair where the ``toml`` -file defines where the template will be render to and who owns it, and the -``tmpl`` file being the template in question. Ideally these files should match -the same name of the file they are generating minus the ``toml`` or ``tmpl`` -suffix. This is to make the discovery of them easier. +If not defined in the highest level the next level applies and so forth down the +list. + +> N.B. `/etc/defaults` and the environment variables declared in the +> Dockerfile(s) used to create the image are **required** to define all +> environment variables used by scripts and `confd` templates. If not +> specified in either of those locations the environment variables will not be +> available even if its defined at a **higher** level i.e. `confd`. + +The logic which enforces these rules is performed in +[container-environment.sh](base/rootfs/etc/s6-overlay/scripts/container-environment.sh) + +> N.B Some containers derive environment variables dynamically from other +> environment variables. In these cases they are expected to provided an +> additional `oneshot` services that must be executed before the `confd-oneshot` +> so that the variables are defined before `confd` is used to render +> templates. + +By either using the command `with-contenv` or starting a script with +`#!/command/with-contenv bash` the environment defined will follow the order +of precedence above. Additionally Within `confd` templates it is **required** +to use `getenv` function for fetching data, as the *final* value is written to +the container environment. ### S6 Overlay -From this tool we only really take advantage of two features: +[S6 Overlay] is the process supervisor we use in all the containers. It ensures +initialization happens in the correct order and services start in the correct +order (e.g. `fpm-php` starts prior to `nginx`, etc). -- Initialization scripts (*found in ``rootfs/etc/cont-init.d``*) -- Service scripts (*found in ``rootfs/etc/services.d``*) +There are two types of services: -Initialization scripts are run when the container is started and they execute in -alphabetical order. So to control the execution order they are prefix with -numbers. +- `oneshot` Services: Short lived services, used to prepare the container prior to running services +- `longrun` Services: Long lived services like Nginx -One initialization script ``01-confd-render-templates.sh`` is shared by all the -images. It does a first past render of the ``confd`` templates so subsequent -scripts can run. The rest of the scripts do the minimal steps required to get -the container into a ready state before the Service scripts start. +Both types of services can have dependencies on one another, which indicates the +order in which they are executed. `oneshot` services are run to **completion** +before their dependent services are executed. `longrun` services are meant to +run indefinitely, if for some reason one fails the container will stop and exit +with the code of the failed service (provided a `finish` script is provided). -The services scripts have the following structure: +The `longrun` services have the following structure: ```bash -./rootfs/etc/services.d +./rootfs/etc/s6-overlay/s6-rc.d └── SERVICE_NAME + ├── dependencies.d + │ └── base ├── finish - └── run + ├── run + └── type ``` -The ``run`` script is responsible for starting the service in the -**foreground**. The ``finish`` script can perform any cleanup necessary before +The `run` script is responsible for starting the service in the +**foreground**. The `finish` script can perform any cleanup necessary before stopping the service, but in general it is used to kill the container, like so: ```bash -s6-svscanctl -t /var/run/s6/services +/run/s6/basedir/bin/halt ``` -There are only a few Service scripts: +To declare dependencies between services, just add an empty file with the +services name in it's `dependencies.d` folder. + +For scripts we want to run at startup run we must register them. This can be +done by placing an empty file named for the service in +`./rootfs/etc/s6-overlay/s6-rc.d/user/contents.d`. + +There are only a few `longrun` services: - activemq -- confd +- confd (optional, not enabled by default) - fpm -- karaf - mysqld - nginx - solr - tomcat +- etc -Of these only ``confd`` is running in every container, it periodically listens -for changes in either ``etcd`` or the ``environment variables`` and will -re-render the templates upon any change. +Of these only `confd` can be configured to run in every container, it +periodically listens for changes in it's configured backend (e.g. `etcd` or +`environment variables`) and will re-render the templates upon any change. See +it's [README.md](./base/README.md), for more information. + +`oneshot` services are pretty much the same, except they use they `up` and +`down` instead of `run` and `finish`. + +Additionally `up` is an [execline] script and does not support `bash`. So we +typically just call out to a `bash` script instead, which by convention can be +found in `./rootfs/etc/s6-overlay/scripts`. + +One `oneshot` service is of particular interest to **all** the containers. The +`ready` service, which does not do anything in and of itself. It is meant as a +placeholder that other services can rely on to ensure that typical actions have +been performed, such as the configuration of environment variables, the +rendering of templates and so on. + +> N.B. **All** `longrun` services should have a dependency on the `ready` +> service. + +If you need to wait until a service to be ready for use, use the following +command: + +```bash +# Wait for PHP-FPM to report it has started. +s6-svwait -U /run/service/fpm +``` + +> N.B. This requires the service to make use of +> [notification-fd](https://skarnet.org/software/s6/notifywhenup.html), which at +> the time of writing is only implemented for `nginx` and `php-fpm` ### Image Hierarchy @@ -298,98 +726,132 @@ In order to save space and reduce the amount of duplication across images, they are arranged in a hierarchy, that roughly follows below: ```bash -├── abuild -│ └── imagemagick └── base ├── java │ ├── activemq - │ ├── karaf - │ │ └── alpaca + │ ├── alpaca │ ├── solr │ └── tomcat │ ├── blazegraph │ ├── cantaloupe - │ ├── fcrepo + │ ├── fcrepo6 │ └── fits ├── mariadb + ├── postgresql └── nginx ├── crayfish - │ ├── gemini │ ├── homarus - │ ├── houdini (consumes "imagemagick" as well during its build stage) - │ ├── hypercube + │ ├── houdini (consumes [imagemagick] as well during its build stage) + │ ├── hypercube (consumes [leptonica] as well during its build stage) │ ├── milliner - │ └── recast + │ └── riprap ├── crayfits ├── drupal - │ └── demo + │ └── test └── matomo ``` -[abuild](./abuild/README.md) and [imagemagick](./imagemagick/README.md) stand -outside of the hierarchy as they are use only to build packages that are -consumed by other images during their build stage. +[imagemagick] & [leptonica] stand outside of the hierarchy as they are use only +to build packages that are consumed by other images during their build stage. ### Folder Layout To make reasoning about what files go where each image follows the same filesystem layout for copying files into the image. -A folder called ``rootfs`` maps directly onto the linux filesystem of the final -image. So for example ``rootfs/etc/islandora/configs`` will be -``/etc/islandora/configs`` in the generated image. +A folder called `rootfs` maps directly onto the linux filesystem of the final +image. So for example `rootfs/etc/islandora/configs` will be +`/etc/islandora/configs` in the generated image. ### Build System -Gradle is used as the build system, it is setup such that it will automatically -detect which folders should be considered -[projects](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html) and -what dependencies exist between them. The only caveat is -that the projects cannot be nested, though that use case does not really apply. +Since [bake] is used to build all the images, you must add new images to +[docker-bake.hcl](./docker-bake.hcl). -The dependencies are resolved by parsing the Dockerfile and looking for ``FROM`` -statements to determine which images are required to build it. +Be sure to update `IMAGES` and `DEPENDENCIES` variables for any new images +added, along with all the required targets for your new `IMAGE-NAME`: -This means to add a new Docker image to the project you do not need to modify -the build scripts, simply add a new folder and place your Dockerfile inside of -it and it will be discovered built in the correct order relative to the other -images. +- `IMAGE-NAME-common`: Properties shared by all the following targets. +- `IMAGE-NAME`: Targets the host platform. +- `IMAGE-NAME-amd64`: Targets amd64, regardless of host platform. +- `IMAGE-NAME-arm64`: Targets arm64, regardless of host platform. +- `IMAGE-NAME-ci`: Used to update the remote cache and build both `PLATFORM-ci` images. +- `IMAGE-NAME-amd64-ci`: Targets amd64, regardless of host platform updates remote cache. +- `IMAGE-NAME-arm64-ci`: Targets arm64, regardless of host platform updates remote cache. -## Design Constraints +### Multi-arch builds -To be able to support a wide variety of backends for ``confd``, as well as -orchestration tools, all calls to ``getv`` **must provide a default**. With the -exception of keys that do not get used unless defined like -``DRUPAL_SITE_{SITE}_NAME``. This means the whatever backend for configuration, -wether it be ``etcd``, ``consul``, or ``environment variables``, containers can -successfully start without any other container present. +For a number of the following reasons we've split the builds to build a single +image per architecture at a time rather than concurrently building multi-arch +images with `buildkit` even though that is a supported feature. -This does not completely remove dependencies between containers, for example, -when the [demo](../docker/demo/README.md) starts it requires a running -[fcrepo](../docker/fcrepo/README.md) to be able to ingest nodes created by -``islandora_default`` features. In these cases an initialization script can -block until another container is available or a timeout has been reached. For -example: +- Some Docker repositories such as GitLab's and Amazons do not handle OCI + multi-arch images well, and it's good to be able to fall back onto a + architecture specific image. +- The `buildkit` caching system is bugging when dealing with concurrent builds + of multi-arch systems. It is better to split the caches by architecture to + ensure cache stability. +- Being able to refer to an image by it's architecture directly is useful when + testing for cross platform bugs. + +That being said we still produce the OCI manifests for multi-arch images. For +local development this is not a requirement but the +[Github Actions](#github-actions) will do this when building. ```bash -local fcrepo_host="{{ getv "/fcrepo/host" "fcrepo.isle-dc.localhost" }}" -local fcrepo_port="{{ getv "/fcrepo/host" "80" }}" -local fcrepo_url= +make manifest TARGET=tomcat +``` -# Indexing fails if port 80 is given explicitly. -if [[ "${fcrepo_port}" == "80" ]]; then - fcrepo_url="http://${fcrepo_host}/fcrepo/rest/" -else - fcrepo_url="http://${fcrepo_host}:${fcrepo_port}/fcrepo/rest/" -fi +So for example on any newish Docker the following command. -#... +```bash +docker run --rm -ti --entrypoint uname islandora/base:latest -a +``` + +Will pull the appropriate image for the host platform without the user +explicitly specifying which of the images to e.g. + +```bash +docker run --rm -ti --entrypoint uname islandora/base:latest-amd64 -a +``` + +Where the above command will explicitly pull the `amd64` image regardless of the +hosts architecture. + +> N.B. By default local builds will not build multi-arch images, they will only +> build the platform supported by the host. The above really only is used by the +> Github Actions build jobs. + +### Caching + +The caching provided by `buildkit` is somewhat finicky and hard to control. +We've opted to use [registry-cache] by default. No other forms of caching are +supported. + +Additionally things like the `s3` is too slow to be practical, and `gha` (Github +Actions cache) is not large enough to support all the images we build. + +## Design Constraints + +To be able to support a wide variety of backends for `confd`, as well as +orchestration tools, all calls **must use** `getenv` for the default value. With +the exception of keys that do not get used unless defined like +`DRUPAL_SITE_{SITE}_NAME`. This means the whatever backend for configuration, +wether it be `etcd`, `consul`, or `environment variables`, containers can +successfully start without any other container present. Additionally it ensure +that the order of precedence for configuration settings. + +This does not completely remove dependencies between containers, for example, +when the [fcrepo6] starts it requires a running database like [mariadb] to be +able to start. In these cases an `oneshot` service can block until another +container is available or a timeout has been reached. For example: -# Need access to Solr before we can actually import the right config. -if timeout 300 wait-for-open-port.sh "${fcrepo_host}" "${fcrepo_port}" ; then - echo "Fcrepo Found" +```bash +# Need access to database to start wait up to 5 minutes (i.e 300 seconds). +if timeout 300 wait-for-open-port.sh "${DB_HOST}" "${DB_PORT}" ; then + echo "Database Found" else - echo "Could not connect to Fcrepo" + echo "Could not connect to Database" exit 1 fi ``` @@ -401,11 +863,86 @@ This allows container to start up in any order, and to be orchestrated by any to **Question:** I'm getting the following error when building: ```bash -failed to solve with frontend dockerfile.v0: failed to solve with frontend gateway.v0: runc did not terminate successfully: context canceled +failed to solve with frontend dockerfile.v0: failed to solve with frontend +gateway.v0: runc did not terminate successfully: context canceled ``` -**Answer:** If possible upgrade Docker to the latest version, and switch to using the -[Overlay2](https://docs.docker.com/storage/storagedriver/overlayfs-driver/#configure-docker-with-the-overlay-or-overlay2-storage-driver) -filesystem with Docker. If that doesn't work trying building [without BuildKit](#building-without-buildkit). +**Answer:** If possible upgrade Docker to the latest version, and switch to +using the [Overlay2] filesystem with Docker. + + +**Question:** I'm getting the following error when running many tests at once: + +```bash +ERROR: could not find an available, non-overlapping IPv4 address pool among the +defaults to assign to the network +``` +**Answer:** By default Docker only allows **31** concurrent bridge networks to +be created, but you can change this in your `/etc/docker/daemon.json` file by +adding the following, and restarting `Docker`: + +```json +{ + "default-address-pools" : [ + { + "base" : "172.17.0.0/12", + "size" : 20 + }, + { + "base" : "192.168.0.0/16", + "size" : 24 + } + ] +} +``` -[Buildkit]: https://github.com/moby/buildkit/blob/main/frontend/dockerfile/docs/experimental.md +[abuild]: ./abuild/README.md +[activemq]: ./activemq/README.md +[alpaca]: ./alpaca/README.md +[base]: ./base/README.md +[blazegraph]: ./blazegraph/README.md +[cantaloupe]: ./cantaloupe/README.md +[crayfish]: ./crayfish/README.md +[crayfits]: ./crayfits/README.md +[drupal]: ./drupal/README.md +[fcrepo6]: ./fcrepo6/README.md +[fits]: ./fits/README.md +[handle]: ./handle/README.md +[homarus]: ./homarus/README.md +[houdini]: ./houdini/README.md +[hypercube]: ./hypercube/README.md +[java]: ./java/README.md +[mariadb]: ./mariadb/README.md +[matomo]: ./matomo/README.md +[milliner]: ./milliner/README.md +[nginx]: ./nginx/README.md +[postgresql]: ./postgresql/README.md +[ripgrep]: ./ripgrep/README.md +[solr]: ./solr/README.md +[test]: ./test/README.md +[tomcat]: ./tomcat/README.md + +[Alpine Docker Image]: https://hub.docker.com/_/alpine +[Ansible]: https://docs.ansible.com/ansible/latest/user_guide/index.html#getting-started +[bake]: https://docs.docker.com/engine/reference/commandline/buildx_bake/ +[buildkit]: https://docs.docker.com/build/buildkit/ +[buildx]: https://docs.docker.com/engine/reference/commandline/buildx/ +[BusyBox]: https://busybox.net/ +[Confd]: https://github.com/kelseyhightower/confd +[Docker Hub]: https://hub.docker.com/u/islandora +[Docker]: https://docs.docker.com/get-started/ +[execline]: https://skarnet.org/software/execline/index.html +[Github Actions]: https://github.com/features/actions +[glibc]: https://www.gnu.org/software/libc/ +[imagemagick]: https://github.com/Islandora-Devops/isle-imagemagick +[islandora-playbook]: https://github.com/Islandora-Devops/islandora-playbook +[islandora-starter-site]: https://github.com/Islandora/islandora-starter-site +[isle-dc]: https://github.com/Islandora-Devops/isle-dc +[isle-site-template]: https://github.com/Islandora-Devops/isle-site-template +[leptonica]: https://github.com/Islandora-Devops/isle-leptonica +[musl libc]: https://musl.libc.org/ +[official documentation]: https://islandora.github.io/documentation/ +[Overlay2]: https://docs.docker.com/storage/storagedriver/overlayfs-driver#configure-docker-with-the-overlay-or-overlay2-storage-driver +[registry-cache]: https://docs.docker.com/build/cache/backends/registry/ +[S6 Overlay]: https://github.com/just-containers/s6-overlay +[isle-builder]: https://github.com/Islandora-Devops/isle-dc diff --git a/abuild/Dockerfile b/abuild/Dockerfile deleted file mode 100644 index bbe26470..00000000 --- a/abuild/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM alpine:3.11.6 - -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - ln -s /var/cache/apk /etc/apk/cache && \ - apk add --update \ - alpine-sdk \ - coreutils \ - && \ - adduser -G abuild -g "Alpine Package Builder" -s /bin/ash -D builder && \ - echo "builder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers diff --git a/abuild/README.md b/abuild/README.md deleted file mode 100644 index 357c4dc0..00000000 --- a/abuild/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# ABuild - -Docker image for `abuild` which is a tool used for create `apk` package for -consumption by other docker containers. - -It is not meant to be deployed as a service, but rather as base for when -creating packages as is done in `islandora/imagemagick`. - -Consumers are expected to follow this pattern: - -Create a folder `/build` in the project directory where the `APKBUILD` file -resides (which describes how to compile and build the package). - -Define a docker file that: - -1. Installs the packages required for building (but not necessarily running) the - package. -2. Run `abuild-keygen` to generate a private/public key pair for signing the - package. -3. Run `abuild` to build the package using `APKBUILD`. - -```dockerfile -# syntax=docker/dockerfile:experimental -FROM islandora/abuild:latest - -# Include packages required for building the package (not necessarily the ones require for running). -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk --update add \ - package-require-for-building-1 \ - package-require-for-building-2 \ - -COPY /build /build - -WORKDIR /build - -RUN chown -R builder /build - -ARG PACKAGER="Packer Name " - -USER builder - -RUN export PACKAGER="${PACKAGER}" && \ - abuild-keygen -ain && \ - abuild-apk update && \ - abuild -``` - -Subsequent images which consume the package can then bring it in via a -combination of multi-stage build, and Buildkit bind mounts like so: - -```dockerfile -FROM islandora/package_image:latest as PACKAGE_IMAGE - -FROM islandora/crayfish:latest - -RUN --mount=type=bind,from=PACKAGE_IMAGE,source=/home/builder/packages/x86_64,target=/packages \ - --mount=type=bind,from=PACKAGE_IMAGE,source=/etc/apk/keys,target=/etc/apk/keys \ - --mount=type=cache,target=/root/.composer/cache \ - apk add /packages/PACKAGE_NAME-*.apk && \ - ... other build steps ...&& \ - cleanup.sh -``` - -Where the image is brought in as `PACKAGE_IMAGE` and the directory where the -generated `.pkg` resides as well as the location of `apk` key files are mounted -into the destination image. - -## Dependencies - -Requires `alpine:3.11.6` docker image to build. - -## Reference - -- -- diff --git a/activemq/.dockerignore b/activemq/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/activemq/.dockerignore +++ b/activemq/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/activemq/Dockerfile b/activemq/Dockerfile index ac432157..e727d750 100644 --- a/activemq/Dockerfile +++ b/activemq/Dockerfile @@ -1,23 +1,37 @@ -# syntax=docker/dockerfile:experimental -FROM local/java:latest +# syntax=docker/dockerfile:1.5.1 +FROM java -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - ACTIVEMQ_VERSION="5.14.5" && \ - ACTIVEMQ_FILE="apache-activemq-${ACTIVEMQ_VERSION}-bin.tar.gz" && \ - ACTIVEMQ_URL="https://archive.apache.org/dist/activemq/${ACTIVEMQ_VERSION}/${ACTIVEMQ_FILE}" && \ - ACTIVEMQ_FILE_SHA256="a4bc310ccb3fb439d0ba159e43f0e08e8073caf050c95e5e07c1a6d5f3f9a86e" && \ - ACTIVEMQ_SIG_SHA256="3bab7224602e7b2c3b660352a2e329b0ac18359aa265163438e573ff32e06c1d" && \ - download.sh --url "${ACTIVEMQ_URL}" --sha256 "${ACTIVEMQ_FILE_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - download.sh --url "${ACTIVEMQ_URL}.asc" --sha256 "${ACTIVEMQ_SIG_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-apache-service.sh \ - --name activemq \ - --key "62ED4DF0BACB8793" \ - --file "${DOWNLOAD_CACHE_DIRECTORY}/${ACTIVEMQ_FILE}" \ - examples webapps-demo docs +ARG TARGETARCH +ARG ACTIVEMQ_VERSION="5.17.3" +ARG ACTIVEMQ_FILE="apache-activemq-${ACTIVEMQ_VERSION}-bin.tar.gz" +ARG ACTIVEMQ_URL="https://archive.apache.org/dist/activemq/${ACTIVEMQ_VERSION}/${ACTIVEMQ_FILE}" +ARG ACTIVEMQ_FILE_SHA256="a4cc4c3a2f136707c2c696f3bb3ee2a86dbeff1b9eb5e237b14edc0c5e5a328f" + +EXPOSE 61616 5672 61613 1883 61614 8161 WORKDIR /opt/activemq -EXPOSE 61616 5672 61613 1883 61614 8161 +RUN --mount=type=cache,id=activemq-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${ACTIVEMQ_URL}" \ + --sha256 "${ACTIVEMQ_FILE_SHA256}" \ + --dest /opt/activemq \ + --strip \ + examples webapps-demo docs \ + && \ + cleanup.sh + +# Defaults environment variables to be overloaded. +ENV \ + ACTIVEMQ_AUDIT_LOG_LEVEL=INFO \ + ACTIVEMQ_LOG_LEVEL=INFO \ + ACTIVEMQ_PASSWORD=password \ + ACTIVEMQ_USER=admin \ + ACTIVEMQ_WEB_ADMIN_NAME=admin \ + ACTIVEMQ_WEB_ADMIN_PASSWORD=password \ + ACTIVEMQ_WEB_ADMIN_ROLES=admin + +COPY --link rootfs / -COPY rootfs / +RUN create-service-user.sh --name activemq && \ + cleanup.sh diff --git a/activemq/README.md b/activemq/README.md index b7621ed0..6e5e121d 100644 --- a/activemq/README.md +++ b/activemq/README.md @@ -1,6 +1,6 @@ # ActiveMQ -Docker image for [ActiveMQ] version 5.14.5. +Docker image for [ActiveMQ] version 5.17.3. Please refer to the [ActiveMQ Documentation] for more in-depth information. @@ -40,45 +40,44 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :-------------------------- | :--------------------------- | :------- | :--------------------------------------- | -| ACTIVEMQ_USER | /activemq/user | admin | See [Security]: credentials.properties | -| ACTIVEMQ_PASSWORD | /activemq/password | password | See [Security]: credentials.properties | -| ACTIVEMQ_WEB_ADMIN_NAME | /activemq/web/admin/name | admin | See [WebConsole]: jetty-realm.properties | -| ACTIVEMQ_WEB_ADMIN_PASSWORD | /activemq/web/admin/password | password | See [WebConsole]: jetty-realm.properties | -| ACTIVEMQ_WEB_ADMIN_ROLES | /activemq/web/admin/roles | admin | See [WebConsole]: jetty-realm.properties | +| Environment Variable | Default | Description | +| :-------------------------- | :------- | :----------------------------------------------------------------------------- | +| ACTIVEMQ_AUDIT_LOG_LEVEL | INFO | Log level. Possible Values: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE or ALL | +| ACTIVEMQ_LOG_LEVEL | INFO | Log level. Possible Values: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE or ALL | +| ACTIVEMQ_PASSWORD | password | See [Security]: credentials.properties | +| ACTIVEMQ_USER | admin | See [Security]: credentials.properties | +| ACTIVEMQ_WEB_ADMIN_NAME | admin | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_ADMIN_PASSWORD | password | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_ADMIN_ROLES | admin | See [WebConsole]: jetty-realm.properties | Additional users/groups/etc can be defined by adding more environment variables, following the above conventions: -| Environment Variable | Etcd Key | Description | -| :-------------------------------- | :--------------------------------- | :--------------------------------------- | -| ACTIVEMQ_USER_{USER}_NAME | /activemq/user/{USER}/name | See [Security]: users.properties | -| ACTIVEMQ_USER_{USER}_PASSWORD | /activemq/user/{USER}/password | See [Security]: users.properties | -| ACTIVEMQ_GROUP_{GROUP}_NAME | /activemq/group/{GROUP}/name | See [Security]: groups.properties | -| ACTIVEMQ_GROUP_{GROUP}_MEMBERS | /activemq/group/{GROUP}/members | See [Security]: groups.properties | -| ACTIVEMQ_WEB_USER_{USER}_NAME | /activemq/web/user/{USER}/name | See [WebConsole]: jetty-realm.properties | -| ACTIVEMQ_WEB_USER_{USER}_PASSWORD | /activemq/web/user/{USER}/password | See [WebConsole]: jetty-realm.properties | -| ACTIVEMQ_WEB_USER_{USER}_ROLES | /activemq/web/user/{USER}/roles | See [WebConsole]: jetty-realm.properties | +| Environment Variable | Description | +| :-------------------------------- | :--------------------------------------- | +| ACTIVEMQ_USER_{USER}_NAME | See [Security]: users.properties | +| ACTIVEMQ_USER_{USER}_PASSWORD | See [Security]: users.properties | +| ACTIVEMQ_GROUP_{GROUP}_NAME | See [Security]: groups.properties | +| ACTIVEMQ_GROUP_{GROUP}_MEMBERS | See [Security]: groups.properties | +| ACTIVEMQ_WEB_USER_{USER}_NAME | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_USER_{USER}_PASSWORD | See [WebConsole]: jetty-realm.properties | +| ACTIVEMQ_WEB_USER_{USER}_ROLES | See [WebConsole]: jetty-realm.properties | > N.B. These do not have defaults. For example to add a new user `someone` to the [WebConsole] you would need to define the following: -| Environment Variable | Etcd Key | Value | -| :--------------------------------- | :---------------------------------- | :------- | -| ACTIVEMQ_WEB_USER_SOMEONE_NAME | /activemq/web/user/someone/name | someone | -| ACTIVEMQ_WEB_USER_SOMEONE_PASSWORD | /activemq/web/user/someone/password | password | -| ACTIVEMQ_WEB_USER_SOMEONE_ROLES | /activemq/web/user/someone/roles | admin | +| Environment Variable | Value | +| :--------------------------------- | :------- | +| ACTIVEMQ_WEB_USER_SOMEONE_NAME | someone | +| ACTIVEMQ_WEB_USER_SOMEONE_PASSWORD | password | +| ACTIVEMQ_WEB_USER_SOMEONE_ROLES | admin | ## Logs -| Path | Description | -| :------------------------------ | :------------- | -| STDOUT | [ActiveMQ Log] | -| /opt/activemq/data/activemq.log | [ActiveMQ Log] | -| /opt/activemq/data/audit.log | [Audit Log] | +- [ActiveMQ Log] +- [Audit Log] [ActiveMQ Documentation]: https://activemq.apache.org/components/classic/documentation [ActiveMQ Log]: https://activemq.apache.org/how-do-i-change-the-logging diff --git a/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml b/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml index 8db2948b..43eb0fb9 100644 --- a/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml +++ b/activemq/rootfs/etc/confd/conf.d/credentials.properties.toml @@ -4,4 +4,4 @@ dest = "/opt/activemq/conf/credentials.properties" uid = 100 gid = 1000 mode = "0640" -keys = [ "/user", "/password" ] +keys = [ "/" ] diff --git a/activemq/rootfs/etc/confd/conf.d/groups.properties.toml b/activemq/rootfs/etc/confd/conf.d/groups.properties.toml index beb212b3..37245e3d 100644 --- a/activemq/rootfs/etc/confd/conf.d/groups.properties.toml +++ b/activemq/rootfs/etc/confd/conf.d/groups.properties.toml @@ -4,4 +4,4 @@ dest = "/opt/activemq/conf/groups.properties" uid = 100 gid = 1000 mode = "0640" -keys = [ "/group" ] +keys = [ "/" ] diff --git a/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml b/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml index 027de561..9a1f44b5 100644 --- a/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml +++ b/activemq/rootfs/etc/confd/conf.d/jetty-realm.properties.toml @@ -4,4 +4,4 @@ dest = "/opt/activemq/conf/jetty-realm.properties" uid = 100 gid = 1000 mode = "0640" -keys = [ "/web/admin", "/web/user" ] +keys = [ "/" ] diff --git a/activemq/rootfs/etc/confd/conf.d/log4j.properties.toml b/activemq/rootfs/etc/confd/conf.d/log4j.properties.toml new file mode 100644 index 00000000..3627ddeb --- /dev/null +++ b/activemq/rootfs/etc/confd/conf.d/log4j.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "log4j.properties.tmpl" +dest = "/opt/activemq/conf/log4j.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/activemq/rootfs/etc/confd/conf.d/users.properties.toml b/activemq/rootfs/etc/confd/conf.d/users.properties.toml index 6adc80b9..cffb8aeb 100644 --- a/activemq/rootfs/etc/confd/conf.d/users.properties.toml +++ b/activemq/rootfs/etc/confd/conf.d/users.properties.toml @@ -4,4 +4,4 @@ dest = "/opt/activemq/conf/users.properties" uid = 100 gid = 1000 mode = "0640" -keys = [ "/user" ] +keys = [ "/" ] diff --git a/activemq/rootfs/etc/confd/confd.toml b/activemq/rootfs/etc/confd/confd.toml deleted file mode 100644 index bbfe3bbc..00000000 --- a/activemq/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/activemq" diff --git a/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl b/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl index fdc94116..4952c702 100644 --- a/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl +++ b/activemq/rootfs/etc/confd/templates/credentials.properties.tmpl @@ -1,3 +1,3 @@ # Defines credentials that will be used by components (like web console) to access the broker -activemq.username={{ getv "/user" "admin" }} -activemq.password={{ getv "/password" "password" }} +activemq.username={{ getenv "ACTIVEMQ_USER" }} +activemq.password={{ getenv "ACTIVEMQ_PASSWORD" }} diff --git a/activemq/rootfs/etc/confd/templates/groups.properties.tmpl b/activemq/rootfs/etc/confd/templates/groups.properties.tmpl index ef272b95..8e26887d 100644 --- a/activemq/rootfs/etc/confd/templates/groups.properties.tmpl +++ b/activemq/rootfs/etc/confd/templates/groups.properties.tmpl @@ -1,4 +1,4 @@ # Defines groups and the users that belong to them. # group=user[,user ...] -{{ range $dir := lsdir "/group" }}{{ getv (printf "/group/%s/name" $dir) }}={{ getv (printf "/group/%s/members" $dir) }} +{{ range $dir := lsdir "/activemq/group" }}{{ getv (printf "/activemq/group/%s/name" $dir) }}={{ getv (printf "/activemq/group/%s/members" $dir) }} {{ end }} diff --git a/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl b/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl index f1c6291a..31a932a4 100644 --- a/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl +++ b/activemq/rootfs/etc/confd/templates/jetty-realm.properties.tmpl @@ -1,5 +1,5 @@ # Defines users that can access the web (console, demo, etc.) # username: password [,rolename ...] -{{ getv "/web/admin/name" "admin" }}: {{ getv "/web/admin/password" "password" }}, {{ getv "/web/admin/roles" "admin" }} -{{ range $dir := lsdir "/web/user" }}{{ getv (printf "/web/user/%s/name" $dir) }}: {{ getv (printf "/web/user/%s/password" $dir) }}, {{ getv (printf "/web/user/%s/roles" $dir) }} +{{ getenv "ACTIVEMQ_WEB_ADMIN_NAME" }}: {{ getenv "ACTIVEMQ_WEB_ADMIN_PASSWORD" }}, {{ getenv "ACTIVEMQ_WEB_ADMIN_ROLES" }} +{{ range $dir := lsdir "/activemq/web/user" }}{{ getv (printf "/activemq/web/user/%s/name" $dir) }}: {{ getv (printf "/activemq/web/user/%s/password" $dir) }}, {{ getv (printf "/activemq/web/user/%s/roles" $dir) }} {{ end }} diff --git a/activemq/rootfs/etc/confd/templates/log4j.properties.tmpl b/activemq/rootfs/etc/confd/templates/log4j.properties.tmpl new file mode 100644 index 00000000..78d7da80 --- /dev/null +++ b/activemq/rootfs/etc/confd/templates/log4j.properties.tmpl @@ -0,0 +1,67 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You 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 file controls most of the logging in ActiveMQ which is mainly based around +# the commons logging API. +# +log4j.rootLogger={{ getenv "ACTIVEMQ_LOG_LEVEL" }}, console +log4j.logger.org.apache.activemq.spring=WARN +log4j.logger.org.apache.activemq.web.handler=WARN +log4j.logger.org.springframework=WARN +log4j.logger.org.apache.xbean=WARN +log4j.logger.org.apache.camel=INFO +log4j.logger.org.eclipse.jetty=WARN + +# When debugging or reporting problems to the ActiveMQ team, +# comment out the above lines and uncomment the next. + +#log4j.rootLogger=DEBUG, logfile, console + +# Or for more fine grained debug logging uncomment one of these +#log4j.logger.org.apache.activemq=DEBUG +#log4j.logger.org.apache.camel=DEBUG + +# Console appender +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n +log4j.appender.console.threshold={{ getenv "ACTIVEMQ_LOG_LEVEL" }} + +# use some of the following patterns to see MDC logging data +# +# %X{activemq.broker} +# %X{activemq.connector} +# %X{activemq.destination} +# +# e.g. +# +# log4j.appender.logfile.layout.ConversionPattern=%d | %-20.20X{activemq.connector} | %-5p | %m | %c | %t%n + +log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer + +########### +# Audit log +########### + +log4j.additivity.org.apache.activemq.audit=false +log4j.logger.org.apache.activemq.audit={{ getenv "ACTIVEMQ_AUDIT_LOG_LEVEL" }}, audit + +log4j.appender.audit=org.apache.log4j.ConsoleAppender +log4j.appender.audit.layout=org.apache.log4j.PatternLayout +log4j.appender.audit.layout.ConversionPattern=%d | %-5p | %m | %t%n +log4j.appender.audit.threshold={{ getenv "ACTIVEMQ_AUDIT_LOG_LEVEL" }} diff --git a/activemq/rootfs/etc/confd/templates/users.properties.tmpl b/activemq/rootfs/etc/confd/templates/users.properties.tmpl index b44780bf..669a832d 100644 --- a/activemq/rootfs/etc/confd/templates/users.properties.tmpl +++ b/activemq/rootfs/etc/confd/templates/users.properties.tmpl @@ -1,2 +1,2 @@ -{{ range $dir := lsdir "/user" }}{{ getv (printf "/user/%s/name" $dir) }}={{ getv (printf "/user/%s/password" $dir) }} +{{ range $dir := lsdir "/activemq/user" }}{{ getv (printf "/activemq/user/%s/name" $dir) }}={{ getv (printf "/activemq/user/%s/password" $dir) }} {{ end }} diff --git a/activemq/rootfs/etc/cont-init.d/02-activemq-setup.sh b/activemq/rootfs/etc/cont-init.d/02-activemq-setup.sh deleted file mode 100755 index b34d4b51..00000000 --- a/activemq/rootfs/etc/cont-init.d/02-activemq-setup.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /opt/activemq/data/activemq.log -chown activemq:activemq /opt/activemq/data/activemq.log - -ln -sf /dev/stdout /opt/activemq/data/audit.log -chown activemq:activemq /opt/activemq/data/audit.log - -# When bind mounting we need to ensure that we -# actually can write to the folder. -chown activemq:activemq /opt/activemq/data diff --git a/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/dependencies.d/ready b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/finish b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/run b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/run new file mode 100755 index 00000000..9ea0dc80 --- /dev/null +++ b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/run @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -e + +# When bind mounting we need to ensure that we +# actually can write to the folder. +chown activemq:activemq /opt/activemq/data +exec s6-setuidgid activemq /opt/activemq/bin/activemq console diff --git a/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/type b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/activemq/rootfs/etc/s6-overlay/s6-rc.d/activemq/type @@ -0,0 +1 @@ +longrun diff --git a/activemq/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/activemq b/activemq/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/activemq new file mode 100644 index 00000000..e69de29b diff --git a/activemq/rootfs/etc/services.d/activemq/finish b/activemq/rootfs/etc/services.d/activemq/finish deleted file mode 100644 index f8984dd3..00000000 --- a/activemq/rootfs/etc/services.d/activemq/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh : -s6-svscanctl -t /var/run/s6/services diff --git a/activemq/rootfs/etc/services.d/activemq/run b/activemq/rootfs/etc/services.d/activemq/run deleted file mode 100644 index 1c175abc..00000000 --- a/activemq/rootfs/etc/services.d/activemq/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh : -with-contenv -s6-setuidgid activemq -/opt/activemq/bin/activemq console diff --git a/activemq/rootfs/opt/activemq/conf/jetty.xml b/activemq/rootfs/opt/activemq/conf/jetty.xml new file mode 100644 index 00000000..743bbb69 --- /dev/null +++ b/activemq/rootfs/opt/activemq/conf/jetty.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + index.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/activemq/rootfs/opt/activemq/conf/jolokia-access.xml b/activemq/rootfs/opt/activemq/conf/jolokia-access.xml new file mode 100644 index 00000000..79fef24d --- /dev/null +++ b/activemq/rootfs/opt/activemq/conf/jolokia-access.xml @@ -0,0 +1,34 @@ + + + + + + + + com.sun.management:type=DiagnosticCommand + * + * + + + com.sun.management:type=HotSpotDiagnostic + * + * + + + + diff --git a/activemq/tests/ServiceStartsWithDefaults/build.gradle.kts b/activemq/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..5e9c0b56 --- /dev/null +++ b/activemq/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("activemq", 0, 143) +} diff --git a/activemq/tests/ServiceStartsWithDefaults/docker-compose.yml b/activemq/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..288b92f4 --- /dev/null +++ b/activemq/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,18 @@ +# file: docker-compose.yml +# +# Tests that the service starts successfully (timeout otherwise). +# +version: "3.8" + +x-common: &common + restart: "no" + +name: activemq-servicestartswithdefaults +services: + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/activemq/tests/ServiceStartsWithDefaults/test.sh b/activemq/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..2d6ac0e0 --- /dev/null +++ b/activemq/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,14 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +until /opt/activemq/bin/activemq status +do + echo "Waiting for ActiveMQ to successfully start" + sleep 1 +done + +# All tests were successful +exit 0 diff --git a/alpaca/.dockerignore b/alpaca/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/alpaca/.dockerignore +++ b/alpaca/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/alpaca/Dockerfile b/alpaca/Dockerfile index ab4655cd..26002f97 100644 --- a/alpaca/Dockerfile +++ b/alpaca/Dockerfile @@ -1,41 +1,80 @@ -# syntax=docker/dockerfile:experimental -FROM local/karaf:latest +# syntax=docker/dockerfile:1.5.1 +FROM java -# Install common features and repos -RUN bin/start && \ - ALPACA_VERSION=1.0.3 && \ - ACTIVEMQ_VERSION=5.15.0 && \ - CAMEL_VERSION=2.20.4 && \ - bin/client -r 10 -d 5 "feature:repo-add mvn:ca.islandora.alpaca/islandora-karaf/${ALPACA_VERSION}/xml/features" && \ - bin/client -r 10 -d 5 "feature:repo-add mvn:org.apache.activemq/activemq-karaf/${ACTIVEMQ_VERSION}/xml/features" && \ - bin/client -r 10 -d 5 "feature:repo-add mvn:org.apache.camel.karaf/apache-camel/${CAMEL_VERSION}/xml/features" && \ - bin/client -r 10 -d 5 "feature:install fcrepo-service-activemq" && \ - bin/client -r 10 -d 5 "feature:install fcrepo-service-camel" && \ - bin/client -r 10 -d 5 "feature:install islandora-http-client" && \ - bin/stop && \ - rm -rf instances/* +ARG TARGETARCH +ARG ALPACA_VERSION="2.2.0" +ARG ALPACA_FILE="islandora-alpaca-app-${ALPACA_VERSION}-all.jar" +ARG ALPACA_URL="https://repo1.maven.org/maven2/ca/islandora/alpaca/islandora-alpaca-app/${ALPACA_VERSION}/${ALPACA_FILE}" +ARG ALPACA_FILE_SHA256="5722306dd78f9fdc3d7a4248a527c439143a3472e5b2d4ea10601b0038b43923" -# Derivative connector -RUN bin/start && \ - bin/client -r 10 -d 5 "feature:install islandora-connector-derivative" && \ - bin/stop && \ - rm -rf instances/* +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=alpaca-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${ALPACA_URL}" \ + --sha256 "${ALPACA_FILE_SHA256}" \ + && \ + mkdir -p /opt/alpaca && \ + cp "${DOWNLOAD_CACHE_DIRECTORY}/${ALPACA_FILE}" "/opt/alpaca/alpaca.jar" && \ + cleanup.sh -# Fcrepo indexing -RUN bin/start && \ - bin/client -r 10 -d 5 "feature:install islandora-indexing-fcrepo" && \ - bin/stop && \ - rm -rf instances/* +RUN create-service-user.sh --name alpaca && \ + cleanup.sh -# Triple indexing -RUN bin/start && \ - bin/client -r 10 -d 5 "feature:install fcrepo-indexing-triplestore" && \ - bin/client -r 10 -d 5 "feature:install islandora-indexing-triplestore" && \ - bin/stop && \ - rm -rf instances/* +ENV \ + ALPACA_CLIENT_ADDITIONAL_OPTIONS= \ + ALPACA_CLIENT_CONFIGURER=true \ + ALPACA_CLIENT_CONNECTION_TIMEOUT=-1 \ + ALPACA_CLIENT_REQUEST_TIMEOUT=-1 \ + ALPACA_CLIENT_SOCKET_TIMEOUT=-1 \ + ALPACA_DERIVATIVE_FITS_ASYNC_CONSUMER=true \ + ALPACA_DERIVATIVE_FITS_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_FITS_ENABLED=true \ + ALPACA_DERIVATIVE_FITS_MAX_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_FITS_QUEUE=queue:islandora-connector-fits \ + ALPACA_DERIVATIVE_FITS_URL=http://crayfits:8000/ \ + ALPACA_DERIVATIVE_HOMARUS_ASYNC_CONSUMER=true \ + ALPACA_DERIVATIVE_HOMARUS_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_HOMARUS_ENABLED=true \ + ALPACA_DERIVATIVE_HOMARUS_MAX_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_HOMARUS_QUEUE=queue:islandora-connector-homarus \ + ALPACA_DERIVATIVE_HOMARUS_URL=http://homarus:8000/convert \ + ALPACA_DERIVATIVE_HOUDINI_ASYNC_CONSUMER=true \ + ALPACA_DERIVATIVE_HOUDINI_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_HOUDINI_ENABLED=true \ + ALPACA_DERIVATIVE_HOUDINI_MAX_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_HOUDINI_QUEUE=queue:islandora-connector-houdini \ + ALPACA_DERIVATIVE_HOUDINI_URL=http://houdini:8000/convert \ + ALPACA_DERIVATIVE_OCR_ASYNC_CONSUMER=true \ + ALPACA_DERIVATIVE_OCR_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_OCR_ENABLED=true \ + ALPACA_DERIVATIVE_OCR_MAX_CONSUMERS=-1 \ + ALPACA_DERIVATIVE_OCR_QUEUE=queue:islandora-connector-ocr \ + ALPACA_DERIVATIVE_OCR_URL=http://hypercube:8000/ \ + ALPACA_DERIVATIVE_SYSTEMS=fits,homarus,houdini,ocr \ + ALPACA_FCREPO_INDEXER_ASYNC_CONSUMER=true \ + ALPACA_FCREPO_INDEXER_CONSUMERS=-1 \ + ALPACA_FCREPO_INDEXER_ENABLED=true \ + ALPACA_FCREPO_INDEXER_MAX_CONSUMERS=-1 \ + ALPACA_FCREPO_INDEXER_MILLINER_URL=http://milliner:8000/ \ + ALPACA_FCREPO_INDEXER_QUEUE_DELETE=queue:islandora-indexing-fcrepo-delete \ + ALPACA_FCREPO_INDEXER_QUEUE_EXTERNAL=queue:islandora-indexing-fcrepo-file-external \ + ALPACA_FCREPO_INDEXER_QUEUE_MEDIA=queue:islandora-indexing-fcrepo-media \ + ALPACA_FCREPO_INDEXER_QUEUE_NODE=queue:islandora-indexing-fcrepo-content \ + ALPACA_JAVA_OPTS= \ + ALPACA_JMS_CONNECTIONS=10 \ + ALPACA_JMS_CONSUMERS=1 \ + ALPACA_JMS_PASSWORD=password \ + ALPACA_JMS_URL=tcp://activemq:61616 \ + ALPACA_JMS_USER=admin \ + ALPACA_MAX_REDELIVERIES=5 \ + ALPACA_TRIPLESTORE_INDEXER_ASYNC_CONSUMER=true \ + ALPACA_TRIPLESTORE_INDEXER_CONSUMERS=-1 \ + ALPACA_TRIPLESTORE_INDEXER_ENABLED=true \ + ALPACA_TRIPLESTORE_INDEXER_MAX_CONSUMERS=-1 \ + ALPACA_TRIPLESTORE_INDEXER_QUEUE_DELETE=queue:islandora-indexing-triplestore-delete \ + ALPACA_TRIPLESTORE_INDEXER_QUEUE_INDEX=queue:islandora-indexing-triplestore-index \ + ALPACA_TRIPLESTORE_INDEXER_URL=http://blazegraph:8080/bigdata/namespace/islandora/sparql -RUN chown -R karaf:karaf /opt/karaf +COPY --link rootfs / -COPY rootfs / - -ENV JAVA_OPTS="-Dfile.encoding=UTF-8 -Dnet.sf.ehcache.skipUpdateCheck=true -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+UseParNewGC -XX:MaxPermSize=128m -Xms512m -Xmx8g" +WORKDIR /opt/alpaca diff --git a/alpaca/README.md b/alpaca/README.md index bbe3964b..d5b369b6 100644 --- a/alpaca/README.md +++ b/alpaca/README.md @@ -1,79 +1,72 @@ # Alpaca -Docker image for [Alpaca] version 1.0.3. +Docker image for [Alpaca] version 2.2.0. Please refer to the [Alpaca Documentation] for more in-depth information. -As a quick example this will bring up an instance of Alpaca, and allow you to -log view the [WebConsole] on as the user `admin` with -the password `password`. - -```bash -docker run --rm -ti -p 8181:8181 \ - -e "KARAF_ADMIN_NAME=admin" \ - -e "KARAF_ADMIN_PASSWORD=password" \ - islandora/alpaca -``` - ## Dependencies -Requires `islandora/karaf` docker image to build. Please refer to the -[Karaf Image README](../karaf/README.md) for additional information including +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](../java/README.md) for additional information including additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :----------------------------------------- | :----------------------------------------- | :--------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ALPACA_ACTIVEMQ_PASSWORD | /alpaca/activemq/password | password | Password to authenticate with | -| ALPACA_ACTIVEMQ_URL | /alpaca/activemq/url | tcp://broker:61616 | The url for connecting to the ActiveMQ broker, shared by all components | -| ALPACA_ACTIVEMQ_USER | /alpaca/activemq/user | admin | User to authenticate as | -| ALPACA_FCREPO_AUTH_HOST | /alpaca/fcrepo/auth/host | | User to authenticate as | -| ALPACA_FCREPO_AUTH_PASSWORD | /alpaca/fcrepo/auth/password | | Password to authenticate with | -| ALPACA_FCREPO_AUTH_USER | /alpaca/fcrepo/auth/user | | URL to authenticate against | -| ALPACA_FCREPO_URL | /alpaca/fcrepo/url | http://fcrepo/fcrepo/rest | The url of fcrepo rest API | -| ALPACA_FITS_QUEUE | /alpaca/fits/queue | broker:queue:islandora-connector-fits | ActiveMQ Queue to consume from | -| ALPACA_FITS_REDELIVERIES | /alpaca/fits/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | -| ALPACA_FITS_SERVICE | /alpaca/fits/service | http://crayfits:8000 | Url of micro-service | -| ALPACA_HOMARUS_QUEUE | /alpaca/homarus/queue | broker:queue:islandora-connector-homarus | ActiveMQ Queue to consume from | -| ALPACA_HOMARUS_REDELIVERIES | /alpaca/homarus/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | -| ALPACA_HOMARUS_SERVICE | /alpaca/homarus/service | http://homarus:8000/convert | Url of micro-service | -| ALPACA_HOUDINI_QUEUE | /alpaca/houdini/queue | broker:queue:islandora-connector-houdini | ActiveMQ Queue to consume from | -| ALPACA_HOUDINI_REDELIVERIES | /alpaca/houdini/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | -| ALPACA_HOUDINI_SERVICE | /alpaca/houdini/service | http://houdini:8000/convert | Url of micro-service | -| ALPACA_HTTP_TOKEN | /alpaca/http/token | islandora | The static token value to be used for authentication by the HttpClient available as an OSGi service for other services to use against the Fedora repository | -| ALPACA_INDEXING_GEMINI_URL | /alpaca/indexing/gemini/url | http://gemini:8000 | Url of micro-service | -| ALPACA_INDEXING_MILLINER_URL | /alpaca/indexing/milliner/url | http://milliner:8000 | Url of micro-service | -| ALPACA_INDEXING_REDELIVERIES | /alpaca/indexing/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | -| ALPACA_INDEXING_STREAM_FILE_DELETE | /alpaca/indexing/stream/file/delete | broker:queue:islandora-indexing-fcrepo-file-delete | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_FILE_INDEX | /alpaca/indexing/stream/file/index | broker:queue:islandora-indexing-fcrepo-file | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_INPUT | /alpaca/indexing/stream/input | broker:topic:fedora | ActiveMQ Topic to consume | -| ALPACA_INDEXING_STREAM_MEDIA_INDEX | /alpaca/indexing/stream/media/index | broker:queue:islandora-indexing-fcrepo-media | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_NODE_DELETE | /alpaca/indexing/stream/node/delete | broker:queue:islandora-indexing-fcrepo-delete | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_NODE_INDEX | /alpaca/indexing/stream/node/index | broker:queue:islandora-indexing-fcrepo-content | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_TRIPLESTORE_DELETE | /alpaca/indexing/stream/triplestore/delete | broker:queue:islandora-indexing-triplestore-delete | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_TRIPLESTORE_INDEX | /alpaca/indexing/stream/triplestore/index | broker:queue:islandora-indexing-triplestore-index | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_STREAM_TRIPLESTORE_REINDEX | /alpaca/indexing/stream/reindex | broker:queue:triplestore.reindex | ActiveMQ Queue to consume from | -| ALPACA_INDEXING_URL | /alpaca/indexing/url | http://blazegraph/bigdata/namespace/islandora/sparql | Url to triple store indexer | -| ALPACA_LOGGER_CAMEL_LEVEL | /alpaca/logger/camel/level | WARN | Camel [Log Level] | -| ALPACA_LOGGER_ISLANDORA_LEVEL | /alpaca/logger/islandora/level | WARN | Islandora [Log Level] | -| ALPACA_LOGGER_ROOT_LEVEL | /alpaca/logger/root/level | WARN | Root [Log Level] | -| ALPACA_OCR_QUEUE | /alpaca/ocr/queue | broker:queue:islandora-connector-ocr | ActiveMQ Queue to consume from | -| ALPACA_OCR_REDELIVERIES | /alpaca/ocr/redeliveries | 10 | Number of attempts to redeliver if an exception occurs | -| ALPACA_OCR_SERVICE | /alpaca/ocr/service | http://hypercube:8000 | Url of micro-service | - -## Logs - -| Path | Description | -| :-------------------------------- | :------------ | -| /opt/karaf/data/log/camel.log | Camel Log | -| /opt/karaf/data/log/islandora.log | Islandora Log | +| Environment Variable | Default | Description | +| :---------------------------------------- | :-------------------------------------------------------- | :---------------------------------------------------------------------- | +| ALPACA_CLIENT_ADDITIONAL_OPTIONS | | | +| ALPACA_CLIENT_CONFIGURER | true | | +| ALPACA_CLIENT_CONNECTION_TIMEOUT | -1 | | +| ALPACA_CLIENT_REQUEST_TIMEOUT | -1 | | +| ALPACA_CLIENT_SOCKET_TIMEOUT | -1 | | +| ALPACA_DERIVATIVE_FITS_ASYNC_CONSUMER | true | | +| ALPACA_DERIVATIVE_FITS_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_FITS_ENABLED | true | | +| ALPACA_DERIVATIVE_FITS_MAX_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_FITS_QUEUE | queue:islandora-connector-fits | ActiveMQ Queue to consume from | +| ALPACA_DERIVATIVE_FITS_URL | http://crayfits:8000 | Url of micro-service | +| ALPACA_DERIVATIVE_HOMARUS_ASYNC_CONSUMER | true | | +| ALPACA_DERIVATIVE_HOMARUS_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_HOMARUS_ENABLED | true | | +| ALPACA_DERIVATIVE_HOMARUS_MAX_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_HOMARUS_QUEUE | queue:islandora-connector-homarus | ActiveMQ Queue to consume from | +| ALPACA_DERIVATIVE_HOMARUS_URL | http://homarus:8000/convert | Url of micro-service | +| ALPACA_DERIVATIVE_HOUDINI_ASYNC_CONSUMER | true | | +| ALPACA_DERIVATIVE_HOUDINI_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_HOUDINI_ENABLED | true | | +| ALPACA_DERIVATIVE_HOUDINI_MAX_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_HOUDINI_QUEUE | queue:islandora-connector-houdini | ActiveMQ Queue to consume from | +| ALPACA_DERIVATIVE_HOUDINI_URL | http://houdini:8000/convert | Url of micro-service | +| ALPACA_DERIVATIVE_OCR_ASYNC_CONSUMER | true | | +| ALPACA_DERIVATIVE_OCR_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_OCR_ENABLED | true | | +| ALPACA_DERIVATIVE_OCR_MAX_CONSUMERS | -1 | | +| ALPACA_DERIVATIVE_OCR_QUEUE | queue:islandora-connector-ocr | ActiveMQ Queue to consume from | +| ALPACA_DERIVATIVE_OCR_URL | http://hypercube:8000 | Url of micro-service | +| ALPACA_DERIVATIVE_SYSTEMS | fits,homarus,houdini,ocr | | +| ALPACA_FCREPO_INDEXER_ASYNC_CONSUMER | true | | +| ALPACA_FCREPO_INDEXER_CONSUMERS | -1 | | +| ALPACA_FCREPO_INDEXER_ENABLED | true | | +| ALPACA_FCREPO_INDEXER_MAX_CONSUMERS | -1 | | +| ALPACA_FCREPO_INDEXER_MILLINER_URL | http://milliner:8000 | Url of micro-service | +| ALPACA_FCREPO_INDEXER_QUEUE_DELETE | queue:islandora-indexing-fcrepo-delete | ActiveMQ Queue to consume from | +| ALPACA_FCREPO_INDEXER_QUEUE_EXTERNAL | queue:islandora-indexing-fcrepo-file-external | ActiveMQ Queue to consume from | +| ALPACA_FCREPO_INDEXER_QUEUE_MEDIA | queue:islandora-indexing-fcrepo-media | ActiveMQ Queue to consume from | +| ALPACA_FCREPO_INDEXER_QUEUE_NODE | queue:islandora-indexing-fcrepo-content | ActiveMQ Queue to consume from | +| ALPACA_JAVA_OPTS | | | +| ALPACA_JMS_CONNECTIONS | 10 | | +| ALPACA_JMS_CONSUMERS | 1 | | +| ALPACA_JMS_PASSWORD | password | Password to authenticate with | +| ALPACA_JMS_URL | tcp://activemq:61616 | The url for connecting to the ActiveMQ broker, shared by all components | +| ALPACA_JMS_USER | admin | User to authenticate as | +| ALPACA_MAX_REDELIVERIES | 5 | Number of attempts to redeliver if an exception occurs | +| ALPACA_TRIPLESTORE_INDEXER_ASYNC_CONSUMER | true | | +| ALPACA_TRIPLESTORE_INDEXER_CONSUMERS | -1 | | +| ALPACA_TRIPLESTORE_INDEXER_ENABLED | true | | +| ALPACA_TRIPLESTORE_INDEXER_MAX_CONSUMERS | -1 | | +| ALPACA_TRIPLESTORE_INDEXER_QUEUE_DELETE | queue:islandora-indexing-triplestore-delete | ActiveMQ Queue to consume from | +| ALPACA_TRIPLESTORE_INDEXER_QUEUE_INDEX | queue:islandora-indexing-triplestore-index | ActiveMQ Queue to consume from | +| ALPACA_TRIPLESTORE_INDEXER_URL | http://blazegraph:8080/bigdata/namespace/islandora/sparql | Url of micro-service | [Alpaca Documentation]: https://islandora.github.io/documentation/ [Alpaca]: https://github.com/Islandora/Alpaca -[JMX]: https://karaf.apache.org/manual/latest/#_monitoring_and_management_using_jmx -[Karaf Directory Structure]: https://karaf.apache.org/manual/latest/#_directory_structure -[Log Level]: https://logging.apache.org/log4j/2.x/manual/customloglevels.html -[RMI]: https://karaf.apache.org/manual/latest/monitoring -[SSH]: https://karaf.apache.org/manual/latest/remote -[WebConsole]: https://karaf.apache.org/manual/latest/webconsole diff --git a/alpaca/rootfs/etc/confd/conf.d/alpaca.properties.toml b/alpaca/rootfs/etc/confd/conf.d/alpaca.properties.toml new file mode 100644 index 00000000..3958ca18 --- /dev/null +++ b/alpaca/rootfs/etc/confd/conf.d/alpaca.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "alpaca.properties.tmpl" +dest = "/opt/alpaca/alpaca.properties" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.fits.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.fits.blueprint.xml.toml deleted file mode 100644 index 3e24c34e..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.fits.blueprint.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl" -dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.fits.blueprint.xml" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/fits" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.homarus.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.homarus.blueprint.xml.toml deleted file mode 100644 index 708413b4..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.homarus.blueprint.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl" -dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.homarus.blueprint.xml" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/homarus" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.houdini.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.houdini.blueprint.xml.toml deleted file mode 100644 index 2dcba334..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.houdini.blueprint.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl" -dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.houdini.blueprint.xml" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/houdini" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.ocr.blueprint.xml.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.ocr.blueprint.xml.toml deleted file mode 100644 index e75d086e..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.connector.ocr.blueprint.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl" -dest = "/opt/karaf/deploy/ca.islandora.alpaca.connector.ocr.blueprint.xml" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/ocr" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.http.client.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.http.client.cfg.toml deleted file mode 100644 index 24b552e6..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.http.client.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.http.client.cfg.tmpl" -dest = "/opt/karaf/etc/ca.islandora.alpaca.http.client.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/http" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.fcrepo.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.fcrepo.cfg.toml deleted file mode 100644 index 43f1825b..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.fcrepo.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl" -dest = "/opt/karaf/etc/ca.islandora.alpaca.indexing.fcrepo.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/indexing" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.triplestore.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.triplestore.cfg.toml deleted file mode 100644 index 6cdc21e5..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/ca.islandora.alpaca.indexing.triplestore.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "ca.islandora.alpaca.indexing.triplestore.cfg.tmpl" -dest = "/opt/karaf/etc/ca.islandora.alpaca.indexing.triplestore.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/indexing" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.indexing.triplestore.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.indexing.triplestore.cfg.toml deleted file mode 100644 index 92385107..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.indexing.triplestore.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "org.fcrepo.camel.indexing.triplestore.cfg.tmpl" -dest = "/opt/karaf/etc/org.fcrepo.camel.indexing.triplestore.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/indexing" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.activemq.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.activemq.cfg.toml deleted file mode 100644 index 393f8cc1..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.activemq.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "org.fcrepo.camel.service.activemq.cfg.tmpl" -dest = "/opt/karaf/etc/org.fcrepo.camel.service.activemq.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/activemq" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.cfg.toml deleted file mode 100644 index 35c2a5e5..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/org.fcrepo.camel.service.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "org.fcrepo.camel.service.cfg.tmpl" -dest = "/opt/karaf/etc/org.fcrepo.camel.service.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/fcrepo" ] diff --git a/alpaca/rootfs/etc/confd/conf.d/org.ops4j.pax.logging.cfg.toml b/alpaca/rootfs/etc/confd/conf.d/org.ops4j.pax.logging.cfg.toml deleted file mode 100644 index c6fa6d91..00000000 --- a/alpaca/rootfs/etc/confd/conf.d/org.ops4j.pax.logging.cfg.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "org.ops4j.pax.logging.cfg.tmpl" -dest = "/opt/karaf/etc/org.ops4j.pax.logging.cfg" -uid = 100 -gid = 1000 -mode = "0644" -keys = [ "/log" ] diff --git a/alpaca/rootfs/etc/confd/confd.toml b/alpaca/rootfs/etc/confd/confd.toml deleted file mode 100644 index 0415e04e..00000000 --- a/alpaca/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/alpaca" diff --git a/alpaca/rootfs/etc/confd/templates/alpaca.properties.tmpl b/alpaca/rootfs/etc/confd/templates/alpaca.properties.tmpl new file mode 100644 index 00000000..ef04619d --- /dev/null +++ b/alpaca/rootfs/etc/confd/templates/alpaca.properties.tmpl @@ -0,0 +1,77 @@ +# Common options +error.maxRedeliveries={{ getenv "ALPACA_MAX_REDELIVERIES" }} + +# The JMS connection URI, used for connecting to a local or remote ActiveMQ broker +jms.brokerUrl={{ getenv "ALPACA_JMS_URL" }} + +# If authentication is enabled on the activemq broker, add appropriate values here +jms.username={{ getenv "ALPACA_JMS_USER" }} +jms.password={{ getenv "ALPACA_JMS_PASSWORD" }} + +# Set the number of conncurrent consumers and the max number of connections. +# Overrides: +# https://github.com/fcrepo-exts/fcrepo-camel-toolbox/blob/2080280e2454aabd4fb6bdf1f1cdf67017b1d3dc/fcrepo-service-activemq/src/main/resources/OSGI-INF/blueprint/blueprint.xml#L20-L21 +jms.concurrent-consumers={{ getenv "ALPACA_JMS_CONSUMERS" }} +jms.connections={{ getenv "ALPACA_JMS_CONNECTIONS" }} +jms.max-concurrent-consumers={{ getenv "ALPACA_JMS_MAX_CONSUMERS" }} + +# Custom Http client options +# All timeouts in milliseconds +request.configurer.enabled={{ getenv "ALPACA_CLIENT_CONFIGURER" }} +request.timeout={{ getenv "ALPACA_CLIENT_REQUEST_TIMEOUT" }} +connection.timeout={{ getenv "ALPACA_CLIENT_CONNECTION_TIMEOUT" }} +socket.timeout={{ getenv "ALPACA_CLIENT_SOCKET_TIMEOUT" }} + +# Additional HTTP endpoint options, these can be for Camel or to be sent to the baseUrl or service.url +http.additional_options={{ getenv "ALPACA_CLIENT_ADDITIONAL_OPTIONS" }} + +# Fedora indexer options +fcrepo.indexer.enabled={{ getenv "ALPACA_FCREPO_INDEXER_ENABLED" }} +fcrepo.indexer.node={{ getenv "ALPACA_FCREPO_INDEXER_QUEUE_NODE" }} +fcrepo.indexer.delete={{ getenv "ALPACA_FCREPO_INDEXER_QUEUE_DELETE" }} +fcrepo.indexer.media={{ getenv "ALPACA_FCREPO_INDEXER_QUEUE_MEDIA" }} +fcrepo.indexer.external={{ getenv "ALPACA_FCREPO_INDEXER_QUEUE_EXTERNAL" }} +fcrepo.indexer.milliner.baseUrl={{ getenv "ALPACA_FCREPO_INDEXER_MILLINER_URL" }} +fcrepo.indexer.concurrent-consumers={{ getenv "ALPACA_FCREPO_INDEXER_CONSUMERS" }} +fcrepo.indexer.max-concurrent-consumers={{ getenv "ALPACA_FCREPO_INDEXER_MAX_CONSUMERS" }} +fcrepo.indexer.async-consumer={{ getenv "ALPACA_FCREPO_INDEXER_ASYNC_CONSUMER" }} + +# Triplestore indexer options +triplestore.indexer.enabled={{ getenv "ALPACA_TRIPLESTORE_INDEXER_ENABLED" }} +triplestore.baseUrl={{ getenv "ALPACA_TRIPLESTORE_INDEXER_URL" }} +triplestore.index.stream={{ getenv "ALPACA_TRIPLESTORE_INDEXER_QUEUE_INDEX" }} +triplestore.delete.stream={{ getenv "ALPACA_TRIPLESTORE_INDEXER_QUEUE_DELETE" }} +triplestore.indexer.concurrent-consumers={{ getenv "ALPACA_TRIPLESTORE_INDEXER_CONSUMERS" }} +triplestore.indexer.max-concurrent-consumers={{ getenv "ALPACA_TRIPLESTORE_INDEXER_MAX_CONSUMERS" }} +triplestore.indexer.async-consumer={{ getenv "ALPACA_TRIPLESTORE_INDEXER_ASYNC_CONSUMER" }} + +# Derivative services +derivative.systems.installed={{ getenv "ALPACA_DERIVATIVE_SYSTEMS" }} fits,homarus,houdini,ocr + +derivative.fits.enabled={{ getenv "ALPACA_DERIVATIVE_FITS_ENABLED" }} +derivative.fits.in.stream={{ getenv "ALPACA_DERIVATIVE_FITS_QUEUE" }} +derivative.fits.service.url={{ getenv "ALPACA_DERIVATIVE_FITS_URL" }} +derivative.fits.concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_FITS_CONSUMERS" }} +derivative.fits.max-concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_FITS_MAX_CONSUMERS" }} +derivative.fits.async-consumer={{ getenv "ALPACA_DERIVATIVE_FITS_ASYNC_CONSUMER" }} + +derivative.homarus.enabled={{ getenv "ALPACA_DERIVATIVE_HOMARUS_ENABLED" }} +derivative.homarus.in.stream={{ getenv "ALPACA_DERIVATIVE_HOMARUS_QUEUE" }} +derivative.homarus.service.url={{ getenv "ALPACA_DERIVATIVE_HOMARUS_URL" }} +derivative.homarus.concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_HOMARUS_CONSUMERS" }} +derivative.homarus.max-concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_HOMARUS_MAX_CONSUMERS" }} +derivative.homarus.async-consumer={{ getenv "ALPACA_DERIVATIVE_HOMARUS_ASYNC_CONSUMER" }} + +derivative.houdini.enabled={{ getenv "ALPACA_DERIVATIVE_HOUDINI_ENABLED" }} +derivative.houdini.in.stream={{ getenv "ALPACA_DERIVATIVE_HOUDINI_QUEUE" }} +derivative.houdini.service.url={{ getenv "ALPACA_DERIVATIVE_HOUDINI_URL" }} +derivative.houdini.concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_HOUDINI_CONSUMERS" }} +derivative.houdini.max-concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_HOUDINI_MAX_CONSUMERS" }} +derivative.houdini.async-consumer={{ getenv "ALPACA_DERIVATIVE_HOUDINI_ASYNC_CONSUMER" }} + +derivative.ocr.enabled={{ getenv "ALPACA_DERIVATIVE_OCR_ENABLED" }} +derivative.ocr.in.stream={{ getenv "ALPACA_DERIVATIVE_OCR_QUEUE" }} +derivative.ocr.service.url={{ getenv "ALPACA_DERIVATIVE_OCR_URL" }} +derivative.ocr.concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_OCR_CONSUMERS" }} +derivative.ocr.max-concurrent-consumers={{ getenv "ALPACA_DERIVATIVE_OCR_MAX_CONSUMERS" }} +derivative.ocr.async-consumer={{ getenv "ALPACA_DERIVATIVE_OCR_ASYNC_CONSUMER" }} diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl deleted file mode 100644 index 0cd13abf..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.fits.blueprint.xml.tmpl +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - ca.islandora.alpaca.connector.derivative - - - diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl deleted file mode 100644 index e2bbc7e8..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.homarus.blueprint.xml.tmpl +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - ca.islandora.alpaca.connector.derivative - - - diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl deleted file mode 100644 index 3c919de9..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.houdini.blueprint.xml.tmpl +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - ca.islandora.alpaca.connector.derivative - - - diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl deleted file mode 100644 index 19e67394..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.connector.ocr.blueprint.xml.tmpl +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - ca.islandora.alpaca.connector.derivative - - - diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.http.client.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.http.client.cfg.tmpl deleted file mode 100644 index c1a25f04..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.http.client.cfg.tmpl +++ /dev/null @@ -1 +0,0 @@ -token.value={{ getv "/http/token" "islandora" }} diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl deleted file mode 100644 index 49a7e682..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.fcrepo.cfg.tmpl +++ /dev/null @@ -1,8 +0,0 @@ -error.maxRedeliveries={{ getv "/indexing/redeliveries" "10" }} -file.delete.stream={{ getv "/indexing/stream/file/delete" "broker:queue:islandora-indexing-fcrepo-file-delete" }} -file.stream={{ getv "/indexing/stream/file/index" "broker:queue:islandora-indexing-fcrepo-file" }} -gemini.baseUrl={{ getv "/indexing/gemini/url" "http://gemini:8000" }} -media.stream={{ getv "/indexing/stream/media/index" "broker:queue:islandora-indexing-fcrepo-media" }} -milliner.baseUrl={{ getv "/indexing/milliner/url" "http://milliner:8000" }} -node.delete.stream={{ getv "/indexing/stream/node/delete" "broker:queue:islandora-indexing-fcrepo-delete" }} -node.stream={{ getv "/indexing/stream/node/index" "broker:queue:islandora-indexing-fcrepo-content" }} diff --git a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.triplestore.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.triplestore.cfg.tmpl deleted file mode 100644 index aa09e7a2..00000000 --- a/alpaca/rootfs/etc/confd/templates/ca.islandora.alpaca.indexing.triplestore.cfg.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -index.stream={{ getv "/indexing/stream/triplestore/index" "broker:queue:islandora-indexing-triplestore-index" }} -delete.stream={{ getv "/indexing/stream/triplestore/delete" "broker:queue:islandora-indexing-triplestore-delete" }} -triplestore.baseUrl={{ getv "/indexing/url" "http://blazegraph/bigdata/namespace/islandora/sparql" }} -error.maxRedeliveries={{ getv "/indexing/redeliveries" "10" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.indexing.triplestore.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.indexing.triplestore.cfg.tmpl deleted file mode 100644 index 5d6003cc..00000000 --- a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.indexing.triplestore.cfg.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -input.stream={{ getv "/indexing/stream/input" "broker:topic:fedora"}} -triplestore.baseUrl={{ getv "/indexing/url" "http://blazegraph/bigdata/namespace/islandora/sparql" }} -triplestore.reindex.stream={{ getv "/indexing/stream/triplestore/reindex" "broker:queue:triplestore.reindex" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.activemq.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.activemq.cfg.tmpl deleted file mode 100644 index c2e28736..00000000 --- a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.activemq.cfg.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -# The JMS connection URI, used for connecting to a local or remote ActiveMQ broker -jms.brokerUrl={{ getv "/activemq/url" "tcp://activemq:61616" }} - -# If authentication is enabled on the activemq broker, add appropriate values here -jms.username={{ getv "/activemq/user" "" }} -jms.password={{ getv "/activemq/password" "" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.cfg.tmpl deleted file mode 100644 index 15bdffba..00000000 --- a/alpaca/rootfs/etc/confd/templates/org.fcrepo.camel.service.cfg.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -# The baseUrl for the fedora repository. -fcrepo.baseUrl={{ getv "/fcrepo/url" "http://fcrepo/fcrepo/rest" }} - -# If authentication is enabled on the Fedora repository, add appropriate values here -fcrepo.authUsername={{ getv "/fcrepo/auth/user" "" }} -fcrepo.authPassword={{ getv "/fcrepo/auth/password" "" }} -fcrepo.authHost={{ getv "/fcrepo/auth/host" "" }} diff --git a/alpaca/rootfs/etc/confd/templates/org.ops4j.pax.logging.cfg.tmpl b/alpaca/rootfs/etc/confd/templates/org.ops4j.pax.logging.cfg.tmpl deleted file mode 100644 index 31c51588..00000000 --- a/alpaca/rootfs/etc/confd/templates/org.ops4j.pax.logging.cfg.tmpl +++ /dev/null @@ -1,34 +0,0 @@ -# Root logger -log4j.rootLogger={{ getv "/logger/root/level" "WARN" }}, out, osgi:* -log4j.throwableRenderer=org.apache.log4j.OsgiThrowableRenderer - -# File appender -log4j.appender.out=org.apache.log4j.RollingFileAppender -log4j.appender.out.layout=org.apache.log4j.PatternLayout -log4j.appender.out.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n -log4j.appender.out.file=${karaf.data}/log/karaf.log -log4j.appender.out.append=true -log4j.appender.out.maxFileSize=1MB -log4j.appender.out.maxBackupIndex=10 - -# Camel Logger -log4j.appender.camel=org.apache.log4j.RollingFileAppender -log4j.appender.camel.layout=org.apache.log4j.PatternLayout -log4j.appender.camel.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n -log4j.appender.camel.file=${karaf.data}/log/camel.log -log4j.appender.camel.append=false -log4j.appender.camel.maxFileSize=1MB -log4j.appender.camel.maxBackupIndex=10 - -log4j.logger.org.apache.camel={{ getv "/logger/camel/level" "WARN" }}, camel - -# Islandora Logger -log4j.appender.islandora=org.apache.log4j.RollingFileAppender -log4j.appender.islandora.layout=org.apache.log4j.PatternLayout -log4j.appender.islandora.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n -log4j.appender.islandora.file=${karaf.data}/log/islandora.log -log4j.appender.islandora.append=false -log4j.appender.islandora.maxFileSize=1MB -log4j.appender.islandora.maxBackupIndex=10 - -log4j.logger.ca.islandora.camel={{ getv "/logger/islandora/level" "WARN" }}, islandora diff --git a/alpaca/rootfs/etc/cont-init.d/04-alpaca-setup.sh b/alpaca/rootfs/etc/cont-init.d/04-alpaca-setup.sh deleted file mode 100755 index 305dcb64..00000000 --- a/alpaca/rootfs/etc/cont-init.d/04-alpaca-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /opt/karaf/data/log/camel.log -chown karaf:karaf /opt/karaf/data/log/camel.log - -ln -sf /dev/stdout /opt/karaf/data/log/islandora.log -chown karaf:karaf /opt/karaf/data/log/islandora.log diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/dependencies.d/ready b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/type b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/up b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/up new file mode 100755 index 00000000..566bc8b0 --- /dev/null +++ b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca-setup/up @@ -0,0 +1,2 @@ +# Some directories must exist prior to rendering templates. +/etc/s6-overlay/scripts/alpaca-setup.sh diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/dependencies.d/alpaca-setup b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/dependencies.d/alpaca-setup new file mode 100644 index 00000000..e69de29b diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/finish b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/run b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/run new file mode 100755 index 00000000..50006071 --- /dev/null +++ b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/run @@ -0,0 +1,4 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e +exec s6-setuidgid alpaca java "${ALPACA_JAVA_OPTS[@]}" -jar /opt/alpaca/alpaca.jar -c /opt/alpaca/alpaca.properties diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/type b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/alpaca/type @@ -0,0 +1 @@ +longrun diff --git a/alpaca/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/alpaca b/alpaca/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/alpaca new file mode 100644 index 00000000..e69de29b diff --git a/alpaca/rootfs/etc/s6-overlay/scripts/alpaca-setup.sh b/alpaca/rootfs/etc/s6-overlay/scripts/alpaca-setup.sh new file mode 100755 index 00000000..9820b643 --- /dev/null +++ b/alpaca/rootfs/etc/s6-overlay/scripts/alpaca-setup.sh @@ -0,0 +1,18 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +function main { + local tcp="${ALPACA_JMS_URL%:*}" + local host="${tcp##*/}" + local port="${ALPACA_JMS_URL##*:}" + + if timeout 300 wait-for-open-port.sh "${host}" "${port}"; then + echo "Broker found at ${host}:${port}" + return 0 + else + echo "Could not connect to broker at ${host}:${port}" + exit 1 + fi +} +main diff --git a/alpaca/tests/ServiceStartsWithDefaults/build.gradle.kts b/alpaca/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..a88765f4 --- /dev/null +++ b/alpaca/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,7 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("alpaca", 0, 143) + expectOutput("alpaca", "[main] (AlpacaDriver) Alpaca started") +} diff --git a/alpaca/tests/ServiceStartsWithDefaults/docker-compose.yml b/alpaca/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..00c480f2 --- /dev/null +++ b/alpaca/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,17 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: alpaca-servicestartswithdefaults +services: + alpaca: + <<: *common + image: ${ALPACA:-islandora/alpaca:local} + depends_on: + - activemq + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} diff --git a/base/.dockerignore b/base/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/base/.dockerignore +++ b/base/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/base/Dockerfile b/base/Dockerfile index 6e9ced40..150d7c64 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -1,52 +1,130 @@ -# syntax=docker/dockerfile:experimental -FROM alpine:3.11.6 +# syntax=docker/dockerfile:1.5.1 +FROM alpine -COPY build/download.sh /usr/local/bin +ARG TARGETARCH +ARG S6_VERSION="3.1.2.1" +ARG S6_BASE_URL="https://github.com/just-containers/s6-overlay/releases/download/v${S6_VERSION}" +ARG S6_OVERLAY_NOARCH=s6-overlay-noarch.tar.xz +ARG S6_OVERLAY_NOARCH_SHA256="cee89d3eeabdfe15239b2c5c3581d9352d2197d4fd23bba3f1e64bf916ccf496" +ARG S6_OVERLAY_SYMLINKS_ARCH=s6-overlay-symlinks-arch.tar.xz +ARG S6_OVERLAY_SYMLINKS_ARCH_SHA256="1b75ac96ddc953f6b7b10be4f579c3e4f6cdf85270116a539930e03e74066f2f" +ARG S6_OVERLAY_SYMLINKS_NOARCH=s6-overlay-symlinks-noarch.tar.xz +ARG S6_OVERLAY_SYMLINKS_NOARCH_SHA256="1e36efb936084fddffe6c55dae8f478e7b2d70f77db2caaceb78c7425b9a7956" +ARG S6_OVERLAY_AMD64=s6-overlay-x86_64.tar.xz +ARG S6_OVERLAY_AMD64_SHA256="6019b6b06cfdbb1d1cd572d46b9b158a4904fd19ca59d374de4ddaaa6a3727d5" +ARG S6_OVERLAY_ARM64=s6-overlay-aarch64.tar.xz +ARG S6_OVERLAY_ARM64_SHA256="e73f9a021b64f88278830742149c14ef8a52331102881ba025bf32a66a0e7c78" + +LABEL License="MIT License" + +# Start s6 +ENTRYPOINT [ "/init" ] # Install packages and tools required by all downstream images. -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=base-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ ln -s /var/cache/apk /etc/apk/cache && \ - apk add --update \ + apk add \ bash \ curl \ git \ gnupg \ + jq \ mariadb-client \ mysql-client \ netcat-openbsd \ openssl \ + patch \ postgresql-client \ + procps \ + shadow \ + util-linux \ wget \ + yq \ && \ - S6_VERSION="1.22.1.0" && \ - S6_FILE="s6-overlay-amd64.tar.gz" && \ - S6_URL="https://github.com/just-containers/s6-overlay/releases/download/v${S6_VERSION}/${S6_FILE}" && \ - S6_SHA256="73f9779203310ddf9c5132546a1978e1a2b05990263b92ed2c34c1e258e2df6c" && \ - S6_SIG_SHA256="7e9c33f45bca1f89b3a1702175a4109e99c911e47ae9de62fbec013406db2b01" && \ - download.sh --url "${S6_URL}" --sha256 "${S6_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - download.sh --url "${S6_URL}.sig" --sha256 "${S6_SIG_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - gpg --keyserver hkp://pool.sks-keyservers.net --recv-key 2536CA16DF4FCDA2 && \ - gpg "${DOWNLOAD_CACHE_DIRECTORY}/${S6_FILE}.sig" && \ - tar -xzf "${DOWNLOAD_CACHE_DIRECTORY}/${S6_FILE}" -C / && \ - CONFD_VERSION="0.15.0" && \ - CONFD_URL="https://github.com/kelseyhightower/confd/releases/download/v${CONFD_VERSION}/confd-${CONFD_VERSION}-linux-amd64" && \ - CONFD_SHA256="7f3aba1d803543dd1df3944d014f055112cf8dadf0a583c76dd5f46578ebe3c2" && \ - download.sh --url "${CONFD_URL}" --sha256 "${CONFD_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - cp "${DOWNLOAD_CACHE_DIRECTORY}/confd-${CONFD_VERSION}-linux-amd64" /usr/local/bin/confd && \ - chmod a+x /usr/local/bin/confd && \ + addgroup -g 2000 jwt && \ echo '' > /root/.ash_history -# Start s6 -ENTRYPOINT [ "/init" ] +ENV DOWNLOAD_CACHE_DIRECTORY=/opt/downloads -LABEL License="MIT License" +# Install s6. +RUN --mount=type=bind,source=rootfs/usr/local/bin/download.sh,target=/usr/local/bin/download.sh \ + --mount=type=cache,id=base-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${S6_BASE_URL}/${S6_OVERLAY_NOARCH}" \ + --sha256 "${S6_OVERLAY_NOARCH_SHA256}" \ + --dest / \ + && \ + download.sh \ + --url "${S6_BASE_URL}/${S6_OVERLAY_SYMLINKS_ARCH}" \ + --sha256 "${S6_OVERLAY_SYMLINKS_ARCH_SHA256}" \ + --dest / \ + && \ + download.sh \ + --url "${S6_BASE_URL}/${S6_OVERLAY_SYMLINKS_NOARCH}" \ + --sha256 "${S6_OVERLAY_SYMLINKS_NOARCH_SHA256}" \ + --dest / \ + && \ + echo '' > /root/.ash_history + +RUN --mount=type=bind,source=rootfs/usr/local/bin/download.sh,target=/usr/local/bin/download.sh \ + --mount=type=cache,id=base-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + if [ "${TARGETARCH}" = "amd64" ]; \ + then \ + download.sh \ + --url "${S6_BASE_URL}/${S6_OVERLAY_AMD64}" \ + --sha256 "${S6_OVERLAY_AMD64_SHA256}" \ + --dest / ; \ + else \ + download.sh \ + --url "${S6_BASE_URL}/${S6_OVERLAY_ARM64}" \ + --sha256 "${S6_OVERLAY_ARM64_SHA256}" \ + --dest / ; \ + fi && \ + echo '' > /root/.ash_history + +SHELL ["/bin/bash", "-euo", "pipefail", "-c"] -# https://github.com/just-containers/s6-overlay#customizing-s6-behaviour -ENV S6_LOGGING=0 \ +ENV \ + CERTIFICATE_AUTHORITY=/usr/local/share/ca-certificates/rootCA.pem \ + CERTIFICATE=/usr/local/share/ca-certificates/cert.pem \ + CONFD_BACKEND=env \ + CONFD_ENABLE_SERVICE=false \ + CONFD_LOG_LEVEL=error \ + CONFD_POLLING_INTERVAL=30 \ + ETCD_CONNECTION_TIMEOUT=10 \ + ETCD_HOST=etcd \ + ETCD_PORT=2379 \ S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \ + S6_CMD_WAIT_FOR_SERVICE=1 \ + S6_CMD_WAIT_FOR_SERVICES_MAXTIME=30000 \ + S6_LOGGING=0 \ + S6_SERVICES_GRACETIME=30000 \ TERM=xterm -COPY rootfs / +# CERT_AUTHORITY and CERT_PUBLIC as well as JWT_PUBLIC_KEY and JWT_PRIVATE_KEY +# are defined in /etc/defaults. As Docker does not support setting multiline +# environment variables via ENV. The 'DB' environment variables can be +# overridden by prefixing it with the image name i.e. `FCREPO_DB_NAME` would +# override the value for `DB_NAME`. +ENV \ + DB_DRIVER=mysql \ + DB_HOST= \ + DB_MYSQL_HOST=mariadb \ + DB_MYSQL_PORT=3306 \ + DB_NAME=default \ + DB_PASSWORD=password \ + DB_PORT= \ + DB_POSTGRESQL_HOST=postgresql \ + DB_POSTGRESQL_PORT=5432 \ + DB_ROOT_PASSWORD=password \ + DB_ROOT_USER=root \ + DB_USER=default \ + DEVELOPMENT_ENVIRONMENT=false \ + JWT_ADMIN_TOKEN=islandora \ + UID= + +COPY --link rootfs / + +# Install confd +COPY --link confd/confd-0.15.0-linux-${TARGETARCH} /usr/local/bin/confd diff --git a/base/README.md b/base/README.md index 374af3b4..a2ce2040 100644 --- a/base/README.md +++ b/base/README.md @@ -7,25 +7,135 @@ It's based off off [Alpine Linux], and includes [s6 overlay] and [confd]. ## Dependencies -Requires `alpine:3.11.6` +Requires `alpine` version is set in [docker-bake.hcl](../docker-bake.hcl). ## Settings -| Environment Variable | Default | Description | -| :---------------------- | :------ | :--------------------------------------- | -| ETCD_HOST | etcd | The host where etcd, can be found | -| ETCD_HOST_PORT | 2379 | The port where etcd can be accessed | -| ETCD_CONNECTION_TIMEOUT | 0 | Timeout to wait for a connection to etcd | +### Confd Settings -If [etcd] cannot be reached the container will use environment variables as a -[backend] for [confd]. The timeout is set to `0` by default to ensure containers -start quickly in a development environment where etcd is not running. +The following environment variables cannot be provided by [confd] as they drive +it's configuration, they must be set on each container as environment variables. + +| Environment Variable | Default | Description | +| :---------------------- | :------ | :-------------------------------------------------------------------------------- | +| CONFD_BACKEND | env | The backend to use for `confd` only `env`, and `etcd` are supported at the moment | +| CONFD_ENABLE_SERVICE | false | If `true` confd will run continuously rather than just on startup. | +| CONFD_LOG_LEVEL | error | The log level to use when executing `confd` | +| CONFD_POLLING_INTERVAL | 30 | Time in seconds between runs of `confd` when enabled as a service | +| ETCD_CONNECTION_TIMEOUT | 0 | Timeout to wait for a connection to etcd | +| ETCD_HOST | etcd | The host where etcd, can be found | +| ETCD_PORT | 2379 | The port where etcd can be accessed | Users do not require [etcd] to run the containers, environment variables can be used instead for simplicity. +### Certificate Settings + +If using development certificates for local development, they can be made +available within the containers using the following environment variables. + +| Environment Variable | Default | Description | +| :------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| CERT_PUBLIC_KEY | | Primarily used for development. If provided the certificate will be registered inside of the container such that curl, etc accepts the certificate as valid. | +| CERT_AUTHORITY | | Primarily used for development. If provided the authority is registered with the java, so that requests originating from Java accept the public certificate. | + +For example if generating certificates locally with [mkcert] for local +development, and using `islandora.dev` as the primary domain. + +> N.B `islandora.dev` just redirects back to `127.0.0.1`. + +```bash +mkcert -install +mkcert \ + -cert-file cert.pem \ + -key-file privkey.pem \ + "*.islandora.dev" \ + "islandora.dev" \ + "localhost" \ + "127.0.0.1" \ + "::1" +``` + +This will generate `cert.pem` which can be use as `CERT_PUBLIC_KEY` and +`rootCA.pem` can be used for `CERT_AUTHORITY`. `rootCA.pem` can be found at the +path printed by using the command `mkcert -CAROOT`. + +Now requests originating within the container will accept the development +certificate as genuine. + +> N.B. This is not required for production sites or certificates that are +> publically available. + +### JWT Settings + +Many services that connect to Drupal / Fedora authenticate via JWT. Please see +the Islandora documentation for [JWT Authentication], and the [Syn] project for +more details. The base image includes these environment variables to reduce +duplication. + +| Environment Variable | Default | Description | +| :------------------- | :-------------------------------------------- | :----------------------------------------------------------------------------------------------------------- | +| JWT_ADMIN_TOKEN | islandora | Used for [bearer authentication] (Only use with HTTPS or over private networks) | +| JWT_PRIVATE_KEY | @see base/rootfs/etc/defaults/JWT_PRIVATE_KEY | Private key for JWT authentication, RSA PEM Format is expected (should only be used in the Drupal container) | +| JWT_PUBLIC_KEY | @see base/rootfs/etc/defaults/JWT_PUBLIC_KEY | Public key for JWT authentication | + +To generate a private public / private key pair use the following. + +```bash +ssh-keygen -q -t rsa -m pem -f /tmp/JWT -N "" +``` + +This produces two files `/tmp/JWT` and `/tmp/JWT.pub`. Which can be used for +`JWT_PRIVATE_KEY` and `JWT_PUBLIC_KEY` respectively. The format is RSA PEM, +*without a password*. **Do not share these files** keep their contents hidden. + +The public/private key pair and [Syn] configuration are placed in `/opt/keys` +and are only readable by the `jwt` group, if your service needs to read these files +add `jwt` as a secondary group to your service user. + +### Database Settings + +Many services can work with multiple backends, to this end the `DB_DRIVER` +setting is used to determine which of the backend specific environment variables +to use. For example if `DB_DRIVER` is equal to `mysql` then the `DB_MYSQL_HOST` +and `DB_MYSQL_PORT` variables will be used when connecting to the backend. + +| Environment Variable | Default | Description | +| :------------------- | :--------- | :---------------------------------------------------------------------------------------------- | +| DB_DRIVER | mysql | The database driver to use by default, only `mysql` and `postgresql` are supported at this time | +| DB_HOST | | The database host to use. The default value is derived from `DB_DRIVER` if not specified | +| DB_MYSQL_HOST | mariadb | The default database host if `DB_DRIVER` is `mysql` | +| DB_MYSQL_PORT | 3306 | The default database port if `DB_DRIVER` is `mysql` | +| DB_NAME | default | The name of the default database if no other is specified | +| DB_PASSWORD | password | The password of the user used by the service (e.g. Drupal) to connect to the database | +| DB_PORT | | The database port to use. The default value is derived from `DB_DRIVER` if not specified | +| DB_POSTGRESQL_HOST | postgresql | The default database host if `DB_DRIVER` is `postgresql` | +| DB_POSTGRESQL_PORT | 5432 | The default database port if `DB_DRIVER` is `postgresql` | +| DB_ROOT_PASSWORD | password | The root user password | +| DB_ROOT_USER | root | The root user, which is used only on startup to create database / user in the chosen backend | +| DB_USER | default | The user used by the service (e.g. Drupal) to connect to the database | + +> N.B. For all of the settings above, images that descend from this image can +> apply a prefix to every setting. So for example `DB_NAME` would become +> `FCREPO_DB_NAME`. This is to allow for different settings on a per-service +> basis when sharing the same confd backend. + +### Development Settings + +When doing development with the containers it is sometimes useful to remap the +`uid` of users in the container to match that of the host user to prevent +permission denied errors when bind mounting files. + +| Environment Variable | Default | Description | +| :---------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------- | +| DEVELOPMENT_ENVIRONMENT | false | Set to `true` if using the containers for development, runs start up scripts to remap `uid` of users inside of the container etc. | +| UID | | The `uid` of the host user | + [Alpine Linux]: https://alpinelinux.org -[backend]: https://github.com/kelseyhightower/confd/blob/34a6ce8897ab3bde10f49c30c815fe496d592860/docs/configuration-guide.md +[bearer authentication]: https://tools.ietf.org/html/rfc6750 [confd]: https://github.com/kelseyhightower/confd [etcd]: https://github.com/etcd-io/etcd +[JWT Authentication]: https://islandora.github.io/documentation/technical-documentation/jwt/ +[mkcert]: https://github.com/FiloSottile/mkcert [s6 overlay]: https://github.com/just-containers/s6-overlay +[Syn]: https://github.com/Islandora/Syn diff --git a/base/build/download.sh b/base/build/download.sh deleted file mode 100755 index 80bc71a5..00000000 --- a/base/build/download.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash -set -e - -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" - -function usage { - cat <<- EOF - usage: $PROGNAME DEST - - Downloads the file at the given url checking it against the given sha256. - If checksum matches return 0 otherwise delete the downloaded file and return non-zero. - - Download is placed in the directory DEST. - - OPTIONS: - -u --url The url of the file to download. - -c --sha256 The sha256 checksum to use to validate the download. - -h --help Show this help. - -x --debug Debug this script. - - Examples: - $PROGNAME https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz 7f3aba1d803543dd1df3944d014f055112cf8dadf0a583c76dd5f46578ebe3c2 /opt/downloads -EOF -} - -function cmdline { - local arg= - for arg - do - local delim="" - case "$arg" in - # Translate --gnu-long-options to -g (short options) - --url) args="${args}-u ";; - --sha256) args="${args}-c ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; - esac - done - - # Reset the positional parameters to the short options - eval set -- $args - - while getopts "u:c:hx" OPTION - do - case $OPTION in - u) - readonly URL=${OPTARG} - ;; - c) - readonly CHECKSUM=${OPTARG} - ;; - h) - usage - exit 0 - ;; - x) - readonly DEBUG='-x' - set -x - ;; - esac - done - - if [[ -z $URL || -z $CHECKSUM ]]; then - echo "Missing one or more required options: --url --sha256" - exit 1 - fi - - # The only parameters is the destination directory. - shift $((OPTIND-1)) - - if [ "$#" -ne 1 ]; then - echo "Illegal number of parameters" - usage - return 1 - fi - - readonly DEST="${1}" - - return 0 -} - - -function validate { - local file=${1} - sha256sum "${file}" | cut -f1 -d' ' | xargs test "${CHECKSUM}" == -} - -function main { - cmdline ${ARGS} - local file="${DEST}/$(basename ${URL})" - # Remove the downloaded file if it exist and does not match the checksum so that it can be downloaded again. - if [ -f "${file}" ] && ! validate "${file}"; then - rm "${file}" - fi - wget -N -P "${DEST}" "${URL}" - # Return non-zero if the checksum doesn't match the downloaded file. - validate "${file}" -} -main diff --git a/base/confd/confd-0.15.0-linux-amd64 b/base/confd/confd-0.15.0-linux-amd64 new file mode 100755 index 00000000..dd6bc73b Binary files /dev/null and b/base/confd/confd-0.15.0-linux-amd64 differ diff --git a/base/confd/confd-0.15.0-linux-arm64 b/base/confd/confd-0.15.0-linux-arm64 new file mode 100755 index 00000000..ea5acf10 Binary files /dev/null and b/base/confd/confd-0.15.0-linux-arm64 differ diff --git a/base/rootfs/etc/cleanup.d/empty-ash-history.sh b/base/rootfs/etc/cleanup.d/empty-ash-history.sh index 5da7ff59..b99823bb 100755 --- a/base/rootfs/etc/cleanup.d/empty-ash-history.sh +++ b/base/rootfs/etc/cleanup.d/empty-ash-history.sh @@ -1,2 +1,2 @@ #!/bin/sh -echo '' > /root/.ash_history +echo '' >/root/.ash_history diff --git a/base/rootfs/etc/cleanup.d/empty-bash-history.sh b/base/rootfs/etc/cleanup.d/empty-bash-history.sh index 290e95f7..e4d38e0d 100755 --- a/base/rootfs/etc/cleanup.d/empty-bash-history.sh +++ b/base/rootfs/etc/cleanup.d/empty-bash-history.sh @@ -1,2 +1,2 @@ #!/bin/sh -echo '' > /root/.bash_history +echo '' >/root/.bash_history diff --git a/base/rootfs/etc/confd/conf.d/cert.pem.toml b/base/rootfs/etc/confd/conf.d/cert.pem.toml new file mode 100644 index 00000000..2f01facc --- /dev/null +++ b/base/rootfs/etc/confd/conf.d/cert.pem.toml @@ -0,0 +1,7 @@ +[template] +src = "cert.pem.tmpl" +dest = "/usr/local/share/ca-certificates/cert.pem" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/" ] diff --git a/drupal/rootfs/etc/confd/conf.d/private.key.toml b/base/rootfs/etc/confd/conf.d/private.key.toml similarity index 57% rename from drupal/rootfs/etc/confd/conf.d/private.key.toml rename to base/rootfs/etc/confd/conf.d/private.key.toml index 89c0e021..d8db7ccc 100644 --- a/drupal/rootfs/etc/confd/conf.d/private.key.toml +++ b/base/rootfs/etc/confd/conf.d/private.key.toml @@ -1,7 +1,7 @@ [template] src = "private.key.tmpl" dest = "/opt/keys/jwt/private.key" -uid = 100 -gid = 101 -mode = "0600" -keys = [ "/jwt" ] +uid = 0 +gid = 2000 +mode = "0640" +keys = [ "/" ] diff --git a/drupal/rootfs/etc/confd/conf.d/public.key.toml b/base/rootfs/etc/confd/conf.d/public.key.toml similarity index 57% rename from drupal/rootfs/etc/confd/conf.d/public.key.toml rename to base/rootfs/etc/confd/conf.d/public.key.toml index e7765b34..1aa017f2 100644 --- a/drupal/rootfs/etc/confd/conf.d/public.key.toml +++ b/base/rootfs/etc/confd/conf.d/public.key.toml @@ -1,7 +1,7 @@ [template] src = "public.key.tmpl" dest = "/opt/keys/jwt/public.key" -uid = 100 -gid = 101 -mode = "0600" -keys = [ "/jwt" ] +uid = 0 +gid = 2000 +mode = "0640" +keys = [ "/" ] diff --git a/base/rootfs/etc/confd/conf.d/rootCA.pem.toml b/base/rootfs/etc/confd/conf.d/rootCA.pem.toml new file mode 100644 index 00000000..9c8907a0 --- /dev/null +++ b/base/rootfs/etc/confd/conf.d/rootCA.pem.toml @@ -0,0 +1,7 @@ +[template] +src = "rootCA.pem.tmpl" +dest = "/usr/local/share/ca-certificates/rootCA.pem" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/" ] diff --git a/base/rootfs/etc/confd/conf.d/setup-environment.sh.toml b/base/rootfs/etc/confd/conf.d/setup-environment.sh.toml deleted file mode 100644 index d7fc515b..00000000 --- a/base/rootfs/etc/confd/conf.d/setup-environment.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setup-environment.sh.tmpl" -dest = "/var/run/islandora/setup-environment.sh" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/" ] diff --git a/base/rootfs/etc/confd/conf.d/syn-settings.xml.toml b/base/rootfs/etc/confd/conf.d/syn-settings.xml.toml new file mode 100644 index 00000000..5f5be6d3 --- /dev/null +++ b/base/rootfs/etc/confd/conf.d/syn-settings.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "syn-settings.xml.tmpl" +dest = "/opt/keys/jwt/syn-settings.xml" +uid = 0 +gid = 2000 +mode = "0640" +keys = [ "/" ] diff --git a/base/rootfs/etc/confd/confd.toml b/base/rootfs/etc/confd/confd.toml index c1565b39..117e451e 100644 --- a/base/rootfs/etc/confd/confd.toml +++ b/base/rootfs/etc/confd/confd.toml @@ -1,5 +1,5 @@ backend = "env" confdir = "/etc/confd" -log-level = "debug" +log-level = "error" interval = 600 noop = false diff --git a/base/rootfs/etc/confd/templates/cert.pem.tmpl b/base/rootfs/etc/confd/templates/cert.pem.tmpl new file mode 100644 index 00000000..d859abc0 --- /dev/null +++ b/base/rootfs/etc/confd/templates/cert.pem.tmpl @@ -0,0 +1 @@ +{{ getenv "CERT_PUBLIC_KEY" }} \ No newline at end of file diff --git a/base/rootfs/etc/confd/templates/private.key.tmpl b/base/rootfs/etc/confd/templates/private.key.tmpl new file mode 100644 index 00000000..aa04cb62 --- /dev/null +++ b/base/rootfs/etc/confd/templates/private.key.tmpl @@ -0,0 +1 @@ +{{ getenv "JWT_PRIVATE_KEY" }} \ No newline at end of file diff --git a/base/rootfs/etc/confd/templates/public.key.tmpl b/base/rootfs/etc/confd/templates/public.key.tmpl new file mode 100644 index 00000000..d944e88d --- /dev/null +++ b/base/rootfs/etc/confd/templates/public.key.tmpl @@ -0,0 +1 @@ +{{ getenv "JWT_PUBLIC_KEY" }} \ No newline at end of file diff --git a/base/rootfs/etc/confd/templates/rootCA.pem.tmpl b/base/rootfs/etc/confd/templates/rootCA.pem.tmpl new file mode 100644 index 00000000..edbc5cdf --- /dev/null +++ b/base/rootfs/etc/confd/templates/rootCA.pem.tmpl @@ -0,0 +1 @@ +{{ getenv "CERT_AUTHORITY" }} \ No newline at end of file diff --git a/base/rootfs/etc/confd/templates/setup-environment.sh.tmpl b/base/rootfs/etc/confd/templates/setup-environment.sh.tmpl deleted file mode 100644 index 337982aa..00000000 --- a/base/rootfs/etc/confd/templates/setup-environment.sh.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/with-contenv bash - -set -e - -# Child images are expected to replace this file to provide setting as environment variables. diff --git a/fcrepo/rootfs/etc/confd/templates/syn-settings.xml.tmpl b/base/rootfs/etc/confd/templates/syn-settings.xml.tmpl similarity index 82% rename from fcrepo/rootfs/etc/confd/templates/syn-settings.xml.tmpl rename to base/rootfs/etc/confd/templates/syn-settings.xml.tmpl index e9c912f1..f32109af 100644 --- a/fcrepo/rootfs/etc/confd/templates/syn-settings.xml.tmpl +++ b/base/rootfs/etc/confd/templates/syn-settings.xml.tmpl @@ -1,6 +1,6 @@ - {{ getv "/jwt/admin/token" "islandora" }} + {{ getenv "JWT_ADMIN_TOKEN" }} diff --git a/base/rootfs/etc/cont-init.d/01-confd-render-templates.sh b/base/rootfs/etc/cont-init.d/01-confd-render-templates.sh deleted file mode 100755 index 4e83e9bc..00000000 --- a/base/rootfs/etc/cont-init.d/01-confd-render-templates.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Renders confd templates once. -confd-render-templates.sh diff --git a/base/rootfs/etc/cont-init.d/02-setup-environment.sh b/base/rootfs/etc/cont-init.d/02-setup-environment.sh deleted file mode 100755 index 07e58311..00000000 --- a/base/rootfs/etc/cont-init.d/02-setup-environment.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Defines environment variables for use in other init scripts. -# It is generated by the 01-confd-render-templates.sh and its contents are -# expected to be overridden in child images. -/var/run/islandora/setup-environment.sh diff --git a/base/rootfs/etc/defaults/CERT_AUTHORITY b/base/rootfs/etc/defaults/CERT_AUTHORITY new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/defaults/CERT_PUBLIC_KEY b/base/rootfs/etc/defaults/CERT_PUBLIC_KEY new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/confd/templates/private.key.tmpl b/base/rootfs/etc/defaults/JWT_PRIVATE_KEY similarity index 94% rename from drupal/rootfs/etc/confd/templates/private.key.tmpl rename to base/rootfs/etc/defaults/JWT_PRIVATE_KEY index 04252c1b..37d25c7a 100644 --- a/drupal/rootfs/etc/confd/templates/private.key.tmpl +++ b/base/rootfs/etc/defaults/JWT_PRIVATE_KEY @@ -1,4 +1,4 @@ -{{ getv "/jwt/private/key" `-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA6uK3nozywVaRCAB3FHdRZNHunSZvN/c31QimZAqQMGxj7JrG h1LF8JRX+XAQ+CJcPD9r6xXjKSS1Gqa2Os2wARr/9abIwG5QeNsrJ8GMt3Z/WICn NeaFAkUVviwKWcA61iFJWvTDAuI0hCaxArRKsk0BfFSMh+4u3JAdD9tUxUx6AAUX @@ -24,4 +24,4 @@ ktSAXw96Jjr8TbygPVNIUYhvBEPMOnjsJlfTkiB0thToFvpChF+nR37kfbPKCv5h Epc8nwKBgQCdKyLi54Fm24nqEuZYbAxxGI9TVT7wJjoKGn64JWrXtX7xRltmJC3t nLwNCojcbyG4kVB+Myzr2OEtFkO45j83GjrZ4O+jCuSj+AmCxEcc7xNA9cgu9usG sQXdGmIIB0Cbk54OyHNdsZgZCXi9GTRF9uvYZKL9qktS+UZMJ1Xz/g== ------END RSA PRIVATE KEY-----` }} +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/drupal/rootfs/etc/confd/templates/public.key.tmpl b/base/rootfs/etc/defaults/JWT_PUBLIC_KEY similarity index 82% rename from drupal/rootfs/etc/confd/templates/public.key.tmpl rename to base/rootfs/etc/defaults/JWT_PUBLIC_KEY index e0e8e191..fcf18204 100644 --- a/drupal/rootfs/etc/confd/templates/public.key.tmpl +++ b/base/rootfs/etc/defaults/JWT_PUBLIC_KEY @@ -1,4 +1,4 @@ -{{ getv "/jwt/public/key" `-----BEGIN PUBLIC KEY----- +-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6uK3nozywVaRCAB3FHdR ZNHunSZvN/c31QimZAqQMGxj7JrGh1LF8JRX+XAQ+CJcPD9r6xXjKSS1Gqa2Os2w ARr/9abIwG5QeNsrJ8GMt3Z/WICnNeaFAkUVviwKWcA61iFJWvTDAuI0hCaxArRK @@ -6,4 +6,4 @@ sk0BfFSMh+4u3JAdD9tUxUx6AAUXUCdtPyluaBd53wuB0r9xRlPnDw6I9QHfKK80 Xrrsu1PYATgrsy69stzCln3KlO5Oxc6O8OjMdjC2D2c3HmsO4CKPvvaVuaow/a9P a3SNje4UXN+/1xUfQskxafP8CKVSr8xxtwzSureiskb5/98moAiutpUtp15yyAm0 rwIDAQAB ------END PUBLIC KEY-----` }} +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/dependencies.d/confd-oneshot b/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/dependencies.d/confd-oneshot new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/type b/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/type @@ -0,0 +1 @@ +oneshot diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/up b/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/up new file mode 100755 index 00000000..9059712b --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/cacert-import/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/cacert-import.sh diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/container-environment b/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/database-defaults b/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/database-defaults new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/type b/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/type @@ -0,0 +1 @@ +oneshot diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/up b/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/up new file mode 100755 index 00000000..a2550ae9 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/confd-oneshot.sh diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd/dependencies.d/ready b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd/finish b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/finish new file mode 100755 index 00000000..8e56dbdf --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/finish @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Only run the service if explicitly told to do so. +if [[ "${CONFD_ENABLE_SERVICE}" == "true" ]]; then + # shellcheck disable=SC1091 + source /usr/local/share/s6/finish "${1}" "${2}" +fi diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd/run b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/run new file mode 100755 index 00000000..7c942dd3 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/run @@ -0,0 +1,10 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Only run the service if explicitly told to do so. +if [[ "${CONFD_ENABLE_SERVICE}" == "true" ]]; then + exec confd-render-templates.sh -- -interval "${CONFD_POLLING_INTERVAL}" +else + exec s6-svc -Od . +fi diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/confd/type b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/confd/type @@ -0,0 +1 @@ +longrun diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/dependencies.d/base b/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/dependencies.d/base new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/type b/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/type @@ -0,0 +1 @@ +oneshot diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/up b/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/up new file mode 100755 index 00000000..6ad8148e --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/container-environment/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/container-environment.sh diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/container-environment b/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/type b/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/type @@ -0,0 +1 @@ +oneshot diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/up b/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/up new file mode 100755 index 00000000..aa4636bd --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/database-defaults.sh diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/cacert-import b/base/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/cacert-import new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/confd-oneshot b/base/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/confd-oneshot new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/tty b/base/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/tty new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/ready/type b/base/rootfs/etc/s6-overlay/s6-rc.d/ready/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/ready/type @@ -0,0 +1 @@ +oneshot diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/ready/up b/base/rootfs/etc/s6-overlay/s6-rc.d/ready/up new file mode 100755 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/tty/dependencies.d/base b/base/rootfs/etc/s6-overlay/s6-rc.d/tty/dependencies.d/base new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/tty/type b/base/rootfs/etc/s6-overlay/s6-rc.d/tty/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/tty/type @@ -0,0 +1 @@ +oneshot diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/tty/up b/base/rootfs/etc/s6-overlay/s6-rc.d/tty/up new file mode 100755 index 00000000..50f23ee2 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/s6-rc.d/tty/up @@ -0,0 +1,14 @@ +# If the container is started without allocating a tty, i.e. without `-t`. +# It can cause issues for non-root processes that want to write directly to +# standard out. +# +# If a tty is allocated /dev/stdout will indirectly point to it /dev/pts/0. +# This file allows members of the tty group to write to it. +# +# If no tty is allocated /dev/stdout will point to /proc/self/fd/1 which +# will be a pipe to the hosts users active terminal. This pipe is owned +# root with read/write access only permitted to the root user. +# +# To permit the containers to be started without `tty` we allow all users +# to read/write to the stdout,stderr,stdin pipes. +chmod o+rw /dev/stdin /dev/stdout /dev/stderr diff --git a/base/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/confd b/base/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/confd new file mode 100644 index 00000000..e69de29b diff --git a/base/rootfs/etc/s6-overlay/scripts/cacert-import.sh b/base/rootfs/etc/s6-overlay/scripts/cacert-import.sh new file mode 100755 index 00000000..424040a9 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/scripts/cacert-import.sh @@ -0,0 +1,23 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +set -e + +# Install the bind-mounted certificate if present. +if [[ -s "/usr/local/share/ca-certificates/cert.pem" ]]; then + update-ca-certificates +fi + +# Import into the java certificate store if java is installed. +# And the CA pem file exists. +if [[ -s "/usr/local/share/ca-certificates/rootCA.pem" ]]; then + if hash keytool &>/dev/null; then + keytool \ + -importcert \ + -noprompt \ + -cacerts \ + -storepass changeit \ + -file "/usr/local/share/ca-certificates/rootCA.pem" \ + -alias rootCA.pem + fi +fi diff --git a/base/rootfs/etc/s6-overlay/scripts/confd-oneshot.sh b/base/rootfs/etc/s6-overlay/scripts/confd-oneshot.sh new file mode 100755 index 00000000..2b28a387 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/scripts/confd-oneshot.sh @@ -0,0 +1,4 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e +confd-render-templates.sh -- -onetime -sync-only diff --git a/base/rootfs/etc/s6-overlay/scripts/container-environment.sh b/base/rootfs/etc/s6-overlay/scripts/container-environment.sh new file mode 100755 index 00000000..27caaa74 --- /dev/null +++ b/base/rootfs/etc/s6-overlay/scripts/container-environment.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -e + +# Sets container environment variables in order of precedence depending on the +# source: +# +# 1. Confd backend (highest) +# 2. Secrets kept in /run/secrets +# 3. Environment variables passed into the container +# 4. Environment variables defined in Dockerfile(s) +# 5. Environment variables defined in the /etc/defaults directory (lowest only used for multiline variables) +# +# If not defined in the highest level the next level applies and so forth down +# the list. /etc/defaults and the environment variables declared in the +# Dockerfile(s) used to create this image are expected to define all +# environment variables used by scripts and Confd templates. +# +# Confd templates are required to use `getenv` function for all default values. + +# Load the environment variables according to the expected precedence. +# Note `exec -c` is used to empty the existing environment. +# +# Write those to the container environment if not already present. The container +# environment has already been initialized by this point and contains levels 3 and +# 4 as mentioned in the top of this file. + +# Temporary conditional to prevent issues with Kubernetes as `s6-envdir` expects the +# folder to contain only files, Kubernetes mounts a folder in this location and works +# with secrets in a different way. At a later time we'll revisit our convention to +# hopefully support all that Kuberentes has to offer while not degrading the +# quality of Swarm or Docker Compose. At the moment Kubernetes users will need +# to inject the secrets as environment variables. Please see +# https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables +if [[ $(find /run/secrets -mindepth 1 -maxdepth 1 -type d | wc -l) -gt 0 ]]; then + /command/exec -c \ + s6-envdir -fn -- /etc/defaults \ + s6-envdir -fn -- /var/run/s6/container_environment \ + s6-dumpenv -- /var/run/s6/container_environment +else + /command/exec -c \ + s6-envdir -fn -- /etc/defaults \ + s6-envdir -fn -- /var/run/s6/container_environment \ + s6-envdir -fn -- /run/secrets \ + s6-dumpenv -- /var/run/s6/container_environment +fi + +# Confd backend variable needs to be normalized. +CONFD_BACKEND=$(&2 + exit 1 + ;; +esac + +# Use what has been provided by the user or default to the derived values. +cat <&2 + usage + exit 1 + ;; esac done @@ -56,7 +61,7 @@ function cmdline { } function main { - cmdline ${ARGS} + cmdline "${ARGS[@]}" for file in /etc/cleanup.d/*; do $file done diff --git a/base/rootfs/usr/local/bin/confd-import-environment.sh b/base/rootfs/usr/local/bin/confd-import-environment.sh new file mode 100755 index 00000000..7782a049 --- /dev/null +++ b/base/rootfs/usr/local/bin/confd-import-environment.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +set -e + +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME + +function usage() { + cat <<-EOF + usage: $PROGNAME + + Import environment variables from confd into the 'container environment', + i.e. accessible via with-contenv. + + Reads a confd template file from stdin. Renders the file and then imports it + into the container environment with s6-env and s6-dumpenv. + + The file passed via stdin should render to a set of key/values repesenting a + set of environment variables and their values. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Import the environment variable FOO_BAR from confd: + echo 'FOO_BAR="{{ getv "/foo/bar" }}"' | $PROGNAME +EOF +} + +function cmdline() { + local arg= + for arg; do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; + esac + done + + # Reset the positional parameters to the short options + eval set -- "${args}" + + while getopts "hx" OPTION; do + case $OPTION in + h) + usage + exit 0 + ;; + x) + set -x + ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; + esac + done + + return 0 +} + +function main { + local tmp_dir + cmdline "${ARGS[@]}" + + # Temporary directory to deposit generated confd configuration templates and + # output, etc. + tmp_dir="$(mktemp -d -t confd-XXXXXXXXXX)" + mkdir -p "${tmp_dir}/conf.d" "${tmp_dir}/templates" "${tmp_dir}/out" + + # Generate template script that will update the container environment with + # values provided by the confd backend. execline is used rather than bash + # to avoid issues with whitespace newlines and string interpolation. + echo 's6-env -i' >"${tmp_dir}/templates/import.sh.tmpl" + cat - >>"${tmp_dir}/templates/import.sh.tmpl" + echo 's6-dumpenv -- /var/run/s6/container_environment' >>"${tmp_dir}/templates/import.sh.tmpl" + + # Temporary confd template config. + cat <>"${tmp_dir}/conf.d/import.sh.toml" +[template] +src = "import.sh.tmpl" +dest = "${tmp_dir}/import.sh" +keys = ["/"] +EOF + + # Temporary confd config. + cat <"${tmp_dir}/confd.toml" +confdir = "${tmp_dir}" +noop = false +prefix = "/" +EOF + + # Generate script to import environment variables from confd. + with-contenv confd-render-templates.sh -- -onetime -sync-only -config-file "${tmp_dir}/confd.toml" + + # Import the variables from confd. + execlineb -P "${tmp_dir}/import.sh" + + # Remove temporary files. + rm -fr "${tmp_dir}" +} +main diff --git a/base/rootfs/usr/local/bin/confd-override-environment.sh b/base/rootfs/usr/local/bin/confd-override-environment.sh new file mode 100755 index 00000000..bf25b010 --- /dev/null +++ b/base/rootfs/usr/local/bin/confd-override-environment.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +set -e + +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME + +function usage() { + cat <<-EOF + usage: $PROGNAME + + With a given prefix find all environment variables that have that prefix + 'A', match that list against environment varaibles that use them as suffixes + 'B', and override the value of 'A' with 'B'. + + This allows values like FITS_TOMCAT_CATALINA_OPTS to replace + TOMCAT_CATALINA_OPTS. If no value is provided that overrides the original, + the original stays the same. + + OPTIONS: + -p --prefix Prefix to find the environment variables to override (Required). + -h --help Show this help. + -x --debug Debug this script. + + Examples: + $PROGNAME --prefix TOMCAT +EOF +} + +function cmdline() { + local arg= + for arg; do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --prefix) args="${args}-p " ;; + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; + esac + done + + # Reset the positional parameters to the short options + eval set -- "${args}" + + while getopts "p:hx" OPTION; do + case $OPTION in + p) + readonly PREFIX=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + set -x + ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; + esac + done + + if [[ -z $PREFIX ]]; then + echo "Missing one of required options: --prefix" >&2 + exit 1 + fi + + return 0 +} + +function main { + local environment_variables + cmdline "${ARGS[@]}" + + # Overwrite environment variables only if suitable canidate exists. + environment_variables=$(with-contenv env | grep -E "^${PREFIX}_" | cut -f1 -d=) + { + for environment_variable in ${environment_variables}; do + FILE=(/var/run/s6/container_environment/*_"${environment_variable}") + if [ -f "${FILE[0]}" ]; then + DEFAULT_VAR=$(basename "${FILE[0]}") + echo "${environment_variable}=\"{{ getenv \"${DEFAULT_VAR}\" }}\"" + fi + done + } | /usr/local/bin/confd-import-environment.sh +} +main diff --git a/base/rootfs/usr/local/bin/confd-render-templates.sh b/base/rootfs/usr/local/bin/confd-render-templates.sh index 4390b25d..9f67f56a 100755 --- a/base/rootfs/usr/local/bin/confd-render-templates.sh +++ b/base/rootfs/usr/local/bin/confd-render-templates.sh @@ -1,28 +1,28 @@ #!/usr/bin/env bash set -e -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" - -# Define defaults if no value environment variables are specified for the following. -readonly ETCD_HOST=${ETCD_HOST:-etcd} -readonly ETCD_PORT=${ETCD_PORT:-2379} -readonly ETCD_TIMEOUT=${ETCD_TIMEOUT:-0} -readonly CONFD_LOG_LEVEL=${CONFD_LOG_LEVEL:-error} -readonly CONFD_POLLING_INTERVAL=${CONFD_POLLING_INTERVAL:-30} +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME function usage { - cat <<- EOF + cat <<-EOF usage: $PROGNAME options - Renders the confd templates using the backend defined by CONFD_BACKEND if found falling back to environment variables otherwise. + Renders the confd templates according to specified environment variables: + + - CONFD_BACKEND + - CONFD_LOG_LEVEL + - ETCD_CONNECTION_TIMEOUT + - ETCD_HOST + - ETCD_PORT + - etc - By default this just renders once and exits, unless --continuous is specified. + Addional options are passed on to confd. Exits non-zero if not successful. OPTIONS: - --continuous Render the templates continously according to the environment variable ${CONFD_POLLING_INTERVAL}. -h --help Show this help. -x --debug Debug this script. @@ -34,91 +34,75 @@ EOF function cmdline { local arg= - for arg - do + for arg; do local delim="" case "$arg" in - # Translate --gnu-long-options to -g (short options) - --continuous) args="${args}-a ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; esac done # Reset the positional parameters to the short options - eval set -- $args + eval set -- "${args}" - while getopts "ahx" OPTION - do + while getopts "hx" OPTION; do case $OPTION in - a) - readonly CONTINUOUS=1 - ;; h) usage exit 0 ;; x) - readonly DEBUG='-x' set -x ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; esac done - return 0 -} + shift $((OPTIND - 1)) -function wait_for_connection { - local service="${1}"; shift - local host="${service}_HOST" - local port="${service}_PORT" - local duration="${service}_TIMEOUT" - echo "Waiting for up to ${!duration} seconds to connect to ${!host}:${!port}" - # Put in subshell to supress "Teminated" message that always gets printed. - # Its part of bashes job system and misleads those reading the log to thing - # there was an error at startup. - if $(timeout ${!duration} wait-for-open-port.sh ${!host} ${!port} &> /dev/null); then - return 0 + # Remaining options to be passed onto the client, preceeded by '--'. + if [ "$#" -gt 0 ]; then + readonly OPTIONS=("${@}") + shift $# else - return 1 - fi -} - -function render { - local backend="${1}"; shift - local onetime_args="-onetime -sync-only" - local continuous_args="-interval ${CONFD_POLLING_INTERVAL}" - local args= - - if [ -z ${CONTINUOUS} ]; then - args="${onetime_args}" - else - args="${continuous_args}" + readonly OPTIONS=() fi - echo "confd using '${backend}' backend..." - confd ${args} -log-level ${CONFD_LOG_LEVEL} -backend ${backend} + return 0 } function main { - cmdline ${ARGS} - local backend=env # Default to env if no other backend can be reached. - - case "${CONFD_BACKEND:-etcdv3}" in - etcd|etcdv3) - if wait_for_connection ETCD; then - backend=etcdv3 - fi - ;; - env) - backend=env - ;; - *) + local args + cmdline "${ARGS[@]}" + + args=("-log-level" "${CONFD_LOG_LEVEL}") + + # If using remote backend make sure it is accessible before continuing + wait-for-confd-backend.sh + + case "${CONFD_BACKEND}" in + etcd | etcdv3) + args+=("-backend" "etcdv3" "-node" "http://${ETCD_HOST}:${ETCD_PORT}") + ;; + env) + args+=("-backend" "env") + ;; + *) + # Unknown backend assume failure. + exit 1 + ;; esac - render ${backend} + exec confd "${args[@]}" "${OPTIONS[@]}" } main diff --git a/base/rootfs/usr/local/bin/create-database.sh b/base/rootfs/usr/local/bin/create-database.sh new file mode 100755 index 00000000..596b73b8 --- /dev/null +++ b/base/rootfs/usr/local/bin/create-database.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash +set -e + +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME + +function usage() { + cat <<-EOF + usage: $PROGNAME options FILE + + With no FILE, or when FILE is -, read standard input. + + Wrapper around execute-sql-file.sh that handles some of the oddities of + postgresql, etc. + + If any of the options are not provided they will be derived from their + respective 'DB' environment variables. + + Warning: by default DB_ROOT_USER/DB_ROOT_PASSWORD will be used if the + respective options are not specified. + + OPTIONS: + --driver The database driver. + --host The database host. + --port The database port. + --user The user to connect as. + --password The password to use for the user. + --database The database to create. + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Create a new database assuming DB_DRIVER is mysql: + echo 'CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci;' | $PROGNAME +EOF +} + +# Check if a fallback is required / missing. +function fallback { + local option=${1} + local name=${2} + local fallback=${3} + if [[ -z ${!name} ]]; then + if [[ -z ${!fallback} ]]; then + echo "Missing option ${option} and fallback environment variable ${fallback}" >&2 + exit 1 + else + return 0 + fi + fi + return 1 +} + +function cmdline { + local arg= + for arg; do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --driver) args="${args}-a " ;; + --host) args="${args}-b " ;; + --port) args="${args}-c " ;; + --user) args="${args}-d " ;; + --password) args="${args}-e " ;; + --database) args="${args}-f " ;; + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; + esac + done + + # Reset the positional parameters to the short options + eval set -- "${args}" + + while getopts "a:b:c:d:e:f:hx" OPTION; do + case $OPTION in + a) + readonly DRIVER=${OPTARG} + ;; + b) + readonly HOST=${OPTARG} + ;; + c) + readonly PORT=${OPTARG} + ;; + d) + readonly USER=${OPTARG} + ;; + e) + readonly PASSWORD=${OPTARG} + ;; + f) + readonly NAME=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + set -x + ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; + esac + done + + if fallback "--database" "NAME" "DB_NAME"; then + readonly NAME=${DB_NAME} + fi + + if fallback "--user" "USER" "DB_ROOT_USER"; then + readonly USER=${DB_ROOT_USER} + fi + + if fallback "--password" "PASSWORD" "DB_ROOT_PASSWORD"; then + readonly PASSWORD=${DB_ROOT_PASSWORD} + fi + + if fallback "--driver" "DRIVER" "DB_DRIVER"; then + readonly DRIVER=${DB_DRIVER} + fi + + if fallback "--host" "HOST" "DB_HOST"; then + readonly HOST=${DB_HOST} + fi + + if fallback "--port" "PORT" "DB_PORT"; then + readonly PORT=${DB_PORT} + fi + + shift $((OPTIND - 1)) + + # Allow either passing in a file/pipe or reading from stdin by specifiying "-" or + # ommiting completely. + if [[ -f "${1}" || -p "${1}" ]]; then + readonly FILE="${1}" + shift + elif [[ "${1}" == "-" ]]; then + readonly FILE=/dev/stdin + shift + else + readonly FILE=/dev/stdin + fi + + return 0 +} + +function execute_sql_file { + execute-sql-file.sh \ + --driver "${DRIVER}" \ + --host "${HOST}" \ + --port "${PORT}" \ + --user "${USER}" \ + --password "${PASSWORD}" \ + "${@}" +} + +function postgresql_database_exists { + execute_sql_file --database "${NAME}" <(echo 'select 1') +} + +function postgresql_create_database { + # Postgres does not support CREATE DATABASE IF NOT EXISTS so split our logic across multiple queries. + if ! postgresql_database_exists; then + execute_sql_file <(echo "CREATE DATABASE ${NAME}") + fi + execute_sql_file --database "${NAME}" "${FILE}" +} + +function mysql_create_database { + execute_sql_file "${FILE}" +} + +function main { + cmdline "${ARGS[@]}" + case "${DRIVER}" in + mysql) + mysql_create_database + ;; + postgresql) + postgresql_create_database + ;; + *) + echo "Only MySQL/PostgresSQL databases are supported for now." >&2 + exit 1 + ;; + esac +} +main diff --git a/base/rootfs/usr/local/bin/create-service-user.sh b/base/rootfs/usr/local/bin/create-service-user.sh new file mode 100755 index 00000000..e64303c7 --- /dev/null +++ b/base/rootfs/usr/local/bin/create-service-user.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -e + +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME + +function usage() { + cat <<-EOF + usage: $PROGNAME options [DIR]... + + Creates a user/group for the service and as well as a directory in /opt + ensuring that all files are owned by that user/group. + + Additional parameters are directories to be created, and owned by the new + user/group. + + OPTIONS: + -n --name The name of the user (used to create user/group and home directory). + -g --group The secondary group to add the user to (Optional). + -h --help Show this help. + -x --debug Debug this script. + + Examples: + Create user/group "activemq" and home folder /opt/activemq: + $PROGNAME --name "activemq" +EOF +} + +function cmdline() { + local arg= + for arg; do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --name) args="${args}-n " ;; + --group) args="${args}-g " ;; + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; + esac + done + + # Reset the positional parameters to the short options + eval set -- "${args}" + + while getopts "n:g:hx" OPTION; do + case $OPTION in + n) + readonly NAME=${OPTARG} + ;; + g) + readonly GROUP=${OPTARG} + ;; + h) + usage + exit 0 + ;; + x) + set -x + ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; + esac + done + + if [[ ! -v NAME ]]; then + echo "Missing one or more required options: --name" >&2 + exit 1 + fi + + # All remaning parameters are directories to be created. + shift $((OPTIND - 1)) + DIRECTORIES=("$@") + readonly DIRECTORIES + + return 0 +} + +function main { + local install_directory user group + cmdline "${ARGS[@]}" + + install_directory="/opt/${NAME}" + user="${NAME}" + group="${NAME}" + mkdir -p "${install_directory}" + addgroup "${group}" # Primary group is always the same as the name. + # Users that run services should permit login and should not require passwords. + adduser --system --disabled-password --no-create-home --ingroup "${group}" --shell /sbin/nologin --home "${install_directory}" "${user}" + # User also needs to be a member of tty to write directly to /dev/stdout, etc. + addgroup "${user}" tty + # Optional secondary group. + if [[ -v GROUP ]]; then + addgroup "${NAME}" "${GROUP}" + fi + if ((${#DIRECTORIES[@]})); then + mkdir -p "${DIRECTORIES[@]}" + fi + chown -R "${user}:${group}" "${install_directory}" "${DIRECTORIES[@]}" +} +main diff --git a/base/rootfs/usr/local/bin/download.sh b/base/rootfs/usr/local/bin/download.sh new file mode 100755 index 00000000..829c0a8c --- /dev/null +++ b/base/rootfs/usr/local/bin/download.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +set -euo pipefail + +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME + +function usage { + cat <<-EOF + usage: $PROGNAME options + + Downloads the file at the given url to the download cache folder. + + Does not re-download the file it already exists and matches the given checksum. + + Unpacks the file if the destination option is given. + + Download is placed in the directory ${DOWNLOAD_CACHE_DIRECTORY}. + + OPTIONS: + -u --url The url of the file to download. + -c --sha256 The sha256 checksum to use to validate the download. + -d --dest The location to unpack file into (optional). + -s --strip Exclude the root folder when unpacking (optional). + -h --help Show this help. + -x --debug Debug this script. + + Examples: + $PROGNAME \\ + --url https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz + --sha256 7f3aba1d803543dd1df3944d014f055112cf8dadf0a583c76dd5f46578ebe3c2 \\ + --dest /opt/s6-overlay +EOF +} + +function cmdline { + local arg= + local args= + for arg; do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --url) args="${args}-u " ;; + --sha256) args="${args}-c " ;; + --dest) args="${args}-d " ;; + --strip) args="${args}-s " ;; + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; + esac + done + + # Reset the positional parameters to the short options + eval set -- "${args}" + + while getopts "u:c:d:shx" OPTION; do + case $OPTION in + u) + readonly URL=${OPTARG} + ;; + c) + readonly CHECKSUM=${OPTARG} + ;; + d) + readonly DEST=${OPTARG} + ;; + s) + readonly STRIP=true + ;; + h) + usage + exit 0 + ;; + x) + set -x + ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; + esac + done + + if [[ -z $URL || -z $CHECKSUM ]]; then + echo "Missing one or more required options: --url --sha256" + exit 1 + fi + + # All remaning parameters are files to be removed from the installation. + shift $((OPTIND-1)) + readonly REMOVE=("$@") + + return 0 +} + +function validate { + local file=${1} + sha256sum "${file}" | cut -f1 -d' ' | xargs test "${CHECKSUM}" == +} + +function unpack { + local file="${1}" + local dest="${2}" + local args=() + mkdir -p "${dest}" + if [[ -v STRIP ]]; then + args+=("--strip-components" "1") + fi + case "${file}" in + *.tar.xz | *.txz) + tar -xf "${file}" -C "${dest}" "${args[@]}" + ;; + *.tar.gz | *.tgz) + tar -xzf "${file}" -C "${dest}" "${args[@]}" + ;; + *.zip | *.war) + if [[ -v STRIP ]]; then + mkdir -p /tmp/unpack + unzip "${file}" -d /tmp/unpack + mv "$(find /tmp/unpack/ -type d -mindepth 1 -maxdepth 1)"/* "${dest}" + rm -fr /tmp/unpack + else + unzip "${file}" -d "${dest}" + fi + ;; + *.jar) + cp "${file}" "${dest}" + ;; + *) + echo "Unable to unpack ${file} please update script to support additional formats." >&2 + exit 1 + ;; + esac + # Remove extraneous files. + for i in "${REMOVE[@]}"; do + rm -fr "${dest:?}/${i}" + done +} + +function main { + local file + cmdline "${ARGS[@]}" + + file="${DOWNLOAD_CACHE_DIRECTORY:?}/$(basename "${URL}")" + # Remove the downloaded file if it exist and does not match the checksum so that it can be downloaded again. + if [ -f "${file}" ] && ! validate "${file}"; then + rm "${file}" + fi + wget -N -P "${DOWNLOAD_CACHE_DIRECTORY}" "${URL}" + # Return non-zero if the checksum does not match the downloaded file. + validate "${file}" + if [[ -v DEST ]]; then + unpack "${file}" "${DEST}" + fi +} +main diff --git a/base/rootfs/usr/local/bin/execute-sql-file.sh b/base/rootfs/usr/local/bin/execute-sql-file.sh index 31e9ee21..3542e18d 100755 --- a/base/rootfs/usr/local/bin/execute-sql-file.sh +++ b/base/rootfs/usr/local/bin/execute-sql-file.sh @@ -1,15 +1,23 @@ #!/usr/bin/env bash set -e - -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME function usage { - cat <<- EOF + cat <<-EOF usage: $PROGNAME options FILE + With no FILE, or when FILE is -, read standard input. + Executes the given SQL file against the appropriate driver. + If any of the options are not provided they will be derived from their + respective 'DB' environment variables. + + Warning: by default DB_ROOT_USER/DB_ROOT_PASSWORD will be used if the + respective options are not specified. + OPTIONS: --driver The database driver. --host The database host. @@ -17,7 +25,6 @@ function usage { --user The user to connect as. --password The password to use for the user. --database The database to run the sql command against. (Optional) - -h --help Show this help. -x --debug Debug this script. @@ -32,85 +39,130 @@ function usage { EOF } +# Check if a fallback is required / missing. +function fallback { + local option=${1} + local name=${2} + local fallback=${3} + if [[ -z ${!name} ]]; then + if [[ -z ${!fallback} ]]; then + echo "Missing option ${option} and fallback environment variable ${fallback}" >&2 + exit 1 + else + return 0 + fi + fi + return 1 +} + function cmdline { local arg= - for arg - do + for arg; do local delim="" case "$arg" in - # Translate --gnu-long-options to -g (short options) - --driver) args="${args}-a ";; - --host) args="${args}-b ";; - --port) args="${args}-c ";; - --user) args="${args}-d ";; - --password) args="${args}-e ";; - --database) args="${args}-f ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; + # Translate --gnu-long-options to -g (short options) + --driver) args="${args}-a " ;; + --host) args="${args}-b " ;; + --port) args="${args}-c " ;; + --user) args="${args}-d " ;; + --password) args="${args}-e " ;; + --database) args="${args}-f " ;; + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; esac done # Reset the positional parameters to the short options - eval set -- $args + eval set -- "${args}" - while getopts "a:b:c:d:e:f:hx" OPTION - do + while getopts "a:b:c:d:e:f:hx" OPTION; do case $OPTION in a) - readonly DRIVER=${OPTARG} + DRIVER=${OPTARG} ;; b) - readonly HOST=${OPTARG} + HOST=${OPTARG} ;; c) - readonly PORT=${OPTARG} + PORT=${OPTARG} ;; d) - readonly USER=${OPTARG} + USER=${OPTARG} ;; e) - readonly PASSWORD=${OPTARG} + PASSWORD=${OPTARG} ;; f) - readonly DATABASE=${OPTARG} + DATABASE=${OPTARG} ;; h) usage exit 0 ;; x) - readonly DEBUG='-x' set -x ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; esac done - if [[ -z $DRIVER || -z $HOST || -z $PORT || -z $USER || -z $PASSWORD ]]; then - echo "Missing one of required options: --driver --host --port --user --password" >&2 - exit 1 + if fallback "--user" "USER" "DB_ROOT_USER"; then + USER=${DB_ROOT_USER} fi - shift $((OPTIND-1)) + if fallback "--password" "PASSWORD" "DB_ROOT_PASSWORD"; then + PASSWORD=${DB_ROOT_PASSWORD} + fi + + if fallback "--driver" "DRIVER" "DB_DRIVER"; then + DRIVER=${DB_DRIVER} + fi + + if fallback "--host" "HOST" "DB_HOST"; then + HOST=${DB_HOST} + fi - if [ "$#" -lt 1 ]; then - echo "Illegal number of parameters" >&2 - usage - return 1 + if fallback "--port" "PORT" "DB_PORT"; then + PORT=${DB_PORT} fi - readonly FILE="${1}"; shift + shift $((OPTIND - 1)) + + # Allow either passing in a file or reading from stdin by specifiying "-" or + # ommiting completely. + if [[ -f "${1}" || -p "${1}" ]]; then + FILE="${1}" + shift + elif [[ "${1}" == "-" ]]; then + FILE=/dev/stdin + shift + else + FILE=/dev/stdin + fi # Remaining options to be passed onto the client, preceeded by '--'. + if [[ "${1}" == "--" ]]; then + shift + fi + if [ "$#" -gt 0 ]; then - shift; - readonly OPTIONS=(${@}); shift $# + OPTIONS=("${@}") + shift $# else - readonly OPTIONS=() + OPTIONS=() fi + readonly DRIVER HOST PORT USER PASSWORD DATABASE FILE OPTIONS + return 0 } @@ -128,7 +180,7 @@ function wait_for_access { function mysql_execute_sql_file { local database_arg= - if [[ ! -z "${DATABASE}" ]]; then + if [[ -n "${DATABASE}" ]]; then database_arg="--database=${DATABASE}" fi @@ -140,13 +192,13 @@ function mysql_execute_sql_file { --protocol=tcp \ "${database_arg}" \ "${OPTIONS[@]}" \ - < "${FILE}" + <"${FILE}" } function postgresql_execute_sql_file { local database_arg="--dbname=postgres" - if [[ ! -z "${DATABASE}" ]]; then + if [[ -n "${DATABASE}" ]]; then database_arg="--dbname=${DATABASE}" fi @@ -162,20 +214,21 @@ function postgresql_execute_sql_file { function execute_sql_file { case "${DRIVER}" in - mysql|pdo_mysql) - mysql_execute_sql_file - ;; - pgsql|postgresql|pdo_pgsql) - postgresql_execute_sql_file - ;; - *) - echo "Only MySQL/PostgresSQL databases are supported for now." >&2 - exit 1 + mysql) + mysql_execute_sql_file + ;; + postgresql) + postgresql_execute_sql_file + ;; + *) + echo "Only MySQL/PostgresSQL databases are supported for now." >&2 + exit 1 + ;; esac } function main { - cmdline ${ARGS} + cmdline "${ARGS[@]}" wait_for_access execute_sql_file } diff --git a/base/rootfs/usr/local/bin/git-clone-cached.sh b/base/rootfs/usr/local/bin/git-clone-cached.sh deleted file mode 100755 index 840c35e9..00000000 --- a/base/rootfs/usr/local/bin/git-clone-cached.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env bash -set -e - -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" - -function usage { - cat <<- EOF - usage: $PROGNAME options [FILE]... - - Does a git clone utilizing the Buildkit caching mechanism. - - OPTIONS: - -u --url The URL of the repository to clone. - -d --cache-dir The directory to use as a cache. - -c --commit The commit hash or tag to checkout. - -w --worktree The directory to checkout the repository into. - -s --strip Remove the git repo as well as any files passed as parameters to save space. - -h --help Show this help. - -x --debug Debug this script. - - Examples: - Clone repository: - $PROGNAME \\ - --url https://github.com/Islandora-CLAW/Alpaca.git \\ - --cache-dir /opt/downloads \\ - --commit "${COMMIT}" \\ - --worktree /opt/alpaca -EOF -} - -function cmdline { - local arg= - for arg - do - local delim="" - case "$arg" in - # Translate --gnu-long-options to -g (short options) - --url) args="${args}-u ";; - --cache-dir) args="${args}-d ";; - --commit) args="${args}-c ";; - --worktree) args="${args}-w ";; - --strip) args="${args}-s ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; - esac - done - - # Reset the positional parameters to the short options - eval set -- $args - - while getopts "u:d:c:w:shx" OPTION - do - case $OPTION in - u) - readonly URL=${OPTARG} - ;; - d) - readonly CACHE_DIRECTORY=${OPTARG} - ;; - c) - readonly COMMIT=${OPTARG} - ;; - w) - readonly WORKTREE=${OPTARG} - ;; - h) - usage - exit 0 - ;; - x) - readonly DEBUG='-x' - set -x - ;; - esac - done - - if [[ -z $URL || -z $CACHE_DIRECTORY || -z $COMMIT || -z $WORKTREE ]]; then - echo "Missing one or more required options: --url --cache-dir --commit --worktree" - exit 1 - fi - - # All remaning parameters are files to be removed from the repo if --strip was specified. - shift $((OPTIND-1)) - readonly REMOVE=("$@") - - return 0 -} - -function main { - cmdline ${ARGS} - local repo=$(basename ${WORKTREE}) - git clone --mirror ${URL} ${CACHE_DIRECTORY}/${repo} || true - git clone ${CACHE_DIRECTORY}/${repo} ${WORKTREE} - git -C ${WORKTREE} fetch --all - git -C ${WORKTREE} reset --hard ${COMMIT} - if [[ -z $STRIP ]]; then - rm -fr ${WORKTREE}/.git - for i in "${REMOVE[@]}"; do - rm -fr "${WORKTREE}/${i}" - done - fi -} -main diff --git a/base/rootfs/usr/local/bin/wait-for-confd-backend.sh b/base/rootfs/usr/local/bin/wait-for-confd-backend.sh new file mode 100755 index 00000000..1fe40972 --- /dev/null +++ b/base/rootfs/usr/local/bin/wait-for-confd-backend.sh @@ -0,0 +1,105 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME + +function usage { + cat <<-EOF + usage: $PROGNAME + + Waits for confd backend specified by the CONFD_BACKEND environment variable + to become available or until a backend dependent timeout has been exceeded. + + Exits non-zero if not successful. + + OPTIONS: + -h --help Show this help. + -x --debug Debug this script. + + Examples: + $PROGNAME +EOF +} + +function cmdline { + local arg= + for arg; do + local delim="" + case "$arg" in + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; + esac + done + + # Reset the positional parameters to the short options + eval set -- "${args}" + + while getopts "ahx" OPTION; do + case $OPTION in + h) + usage + exit 0 + ;; + x) + set -x + ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; + esac + done + + return 0 +} + +function wait_for_connection { + local service host port duration + service="${1}" + shift + host="${service}_HOST" + port="${service}_PORT" + duration="${service}_CONNECTION_TIMEOUT" + echo "Waiting for up to ${!duration} seconds to connect to ${!host}:${!port}" >&2 + # Put in subshell to supress "Teminated" message that always gets printed. + # Its part of bashes job system and misleads those reading the log to thing + # there was an error at startup. + if timeout "${!duration}" wait-for-open-port.sh "${!host}" "${!port}" &>/dev/null; then + return 0 + else + return 1 + fi +} + +function main { + cmdline "${ARGS[@]}" + + case "${CONFD_BACKEND}" in + etcd | etcdv3) + if wait_for_connection ETCD; then + exit 0 + else + exit 1 + fi + ;; + env) + # No need to wait for environment variables. + exit 0 + ;; + *) + # Unknown backend assume failure. + exit 1 + ;; + esac +} +main diff --git a/base/rootfs/usr/local/bin/wait-for-database.sh b/base/rootfs/usr/local/bin/wait-for-database.sh index 3467f6f9..d6dde62d 100755 --- a/base/rootfs/usr/local/bin/wait-for-database.sh +++ b/base/rootfs/usr/local/bin/wait-for-database.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash set -e -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME function usage { - cat <<- EOF + cat <<-EOF usage: $PROGNAME options Waits for an connection to an database as the given user, or until the @@ -36,29 +37,29 @@ EOF function cmdline { local arg= - for arg - do + for arg; do local delim="" case "$arg" in - # Translate --gnu-long-options to -g (short options) - --driver) args="${args}-a ";; - --host) args="${args}-b ";; - --port) args="${args}-c ";; - --user) args="${args}-d ";; - --password) args="${args}-e ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; + # Translate --gnu-long-options to -g (short options) + --driver) args="${args}-a " ;; + --host) args="${args}-b " ;; + --port) args="${args}-c " ;; + --user) args="${args}-d " ;; + --password) args="${args}-e " ;; + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; esac done # Reset the positional parameters to the short options - eval set -- $args + eval set -- "${args}" - while getopts "a:b:c:d:e:hx" OPTION - do + while getopts "a:b:c:d:e:hx" OPTION; do case $OPTION in a) readonly DRIVER=${OPTARG} @@ -80,9 +81,13 @@ function cmdline { exit 0 ;; x) - readonly DEBUG='-x' set -x ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; esac done @@ -96,17 +101,17 @@ function cmdline { function wait_for_connection { local duration=${TIMEOUT:-300} - echo "Waiting for up to ${duration} seconds to connect to Database ${HOST}:${PORT}" - timeout ${duration} wait-for-open-port.sh ${HOST} ${PORT} + echo "Waiting for up to ${duration} seconds to connect to Database ${HOST}:${PORT}" >&2 + timeout "${duration}" wait-for-open-port.sh "${HOST}" "${PORT}" } function mysql_validate_credentials { mysqladmin \ -s \ - --user=${USER} \ - --password=${PASSWORD} \ - --host=${HOST} \ - --port=${PORT} \ + --user="${USER}" \ + --password="${PASSWORD}" \ + --host="${HOST}" \ + --port="${PORT}" \ --protocol=tcp \ ping } @@ -121,35 +126,36 @@ function postgresql_validate_credentials { } function validate_credentials { - echo "Validating Database credentials" + echo "Validating Database credentials" >&2 case "${DRIVER}" in - mysql|pdo_mysql) - mysql_validate_credentials - ;; - pgsql|postgresql|pdo_pgsql) - postgresql_validate_credentials - ;; - *) - echo "Only MySQL/PostgresSQL databases are supported for now." >&2 - exit 1 + mysql) + mysql_validate_credentials + ;; + postgresql) + postgresql_validate_credentials + ;; + *) + echo "Only MySQL/PostgresSQL databases are supported for now." >&2 + exit 1 + ;; esac } function main { - cmdline ${ARGS} + cmdline "${ARGS[@]}" if wait_for_connection; then - echo "Database found" + echo "Database found" >&2 else - echo "Timed out waiting for database connection" + echo "Timed out waiting for database connection" >&2 exit 1 fi if validate_credentials; then - echo "Credentials are valid" + echo "Credentials are valid" >&2 exit 0 else - echo "Credentials are invalid" + echo "Credentials are invalid" >&2 exit 1 fi } diff --git a/base/rootfs/usr/local/bin/wait-for-open-port.sh b/base/rootfs/usr/local/bin/wait-for-open-port.sh index d80c9e04..ee427c55 100755 --- a/base/rootfs/usr/local/bin/wait-for-open-port.sh +++ b/base/rootfs/usr/local/bin/wait-for-open-port.sh @@ -1,21 +1,22 @@ #!/usr/bin/env bash set -e -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" +ARGS=("$@") +PROGNAME=$(basename "$0") +readonly ARGS PROGNAME function usage { - cat <<- EOF + cat <<-EOF usage: $PROGNAME HOST PORT Waits for the given PORT to be open on HOST, re-checks every second. - + Use in conjunction with timeout. OPTIONS: -h --help Show this help. -x --debug Debug this script. - + Examples: Check if database is acccessible: timeout 10 $PROGNAME database 3306 @@ -24,56 +25,61 @@ EOF function cmdline { local arg= - for arg - do + for arg; do local delim="" case "$arg" in - # Translate --gnu-long-options to -g (short options) - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; + # Translate --gnu-long-options to -g (short options) + --help) args="${args}-h " ;; + --debug) args="${args}-x " ;; + # Pass through anything else + *) + [[ "${arg:0:1}" == "-" ]] || delim="\"" + args="${args}${delim}${arg}${delim} " + ;; esac done - + # Reset the positional parameters to the short options - eval set -- $args - - while getopts "hx" OPTION - do + eval set -- "${args}" + + while getopts "hx" OPTION; do case $OPTION in h) usage exit 0 ;; x) - readonly DEBUG='-x' set -x ;; + *) + echo "Invalid Option: $OPTION" >&2 + usage + exit 1 + ;; esac done - shift $((OPTIND-1)) - + shift $((OPTIND - 1)) + if [ "$#" -ne 2 ]; then - echo "Illegal number of parameters" - usage - return 1 + echo "Illegal number of parameters" >&2 + usage + return 1 fi - readonly HOST=${1}; shift + readonly HOST=${1} + shift readonly PORT=${1} return 0 } function main { - cmdline ${ARGS} - echo "Waiting for ${PORT} on ${HOST} to open." - while ! nc -z -w5 $HOST $PORT &> /dev/null; do - sleep 1 - done - exit 0; + cmdline "${ARGS[@]}" + echo "Waiting for ${PORT} on ${HOST} to open." >&2 + while ! nc -z -w5 "${HOST}" "${PORT}" &>/dev/null; do + sleep 1 + done + exit 0 } main diff --git a/base/rootfs/usr/local/share/isle/utilities.sh b/base/rootfs/usr/local/share/isle/utilities.sh new file mode 100755 index 00000000..cfcbf01e --- /dev/null +++ b/base/rootfs/usr/local/share/isle/utilities.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +# Shared functions that are broadly useful, adds call stacks on error to help +# with debugging along with convenience functions. + +set -E -T + +function error_handler { + local code num script + code=${1} + num=${BASH_LINENO[0]} + script=$(realpath "${BASH_SOURCE[1]}") + set +x + echo " " + echo "Error: '${code}' on line '${num}' in '${script}'" >&2 + echo "Trace:" + echo "------" + for i in $( # Do no include the error_handler. + seq 0 $(("${#BASH_LINENO[@]}" - 2)) + ); do + local j=$((i + 1)) # Offset to account for error_handler. + script=$(realpath "${BASH_SOURCE[$j]}") + num=${BASH_LINENO[$i]} + echo "# ${i} File: ${script}, Line: ${BASH_LINENO[$i]} Function: ${FUNCNAME[$j]:-}" >&2 + awk 'NR>L-4 && NR>>":""),$0 }' L=${num} "${script}" >&2 + echo "------" + done + exit "${code}" +} +trap 'error_handler ${?}' ERR + +function exit_handler { + local code=${1} + if [[ "${code}" == "0" ]]; then + echo "Exited Successfully" + else + echo "Failed with exit code: ${code}" + fi + exit "${code}" +} +trap 'exit_handler ${?}' EXIT + +# Wait for a 20x response at the given address. +function wait_20x { + local address=${1} + shift + echo "Waiting for reponse on $address" + while ! curl --fail -i -X GET "${address}" &>/dev/null; do + sleep 5 + done +} + +# Checks if the given variable value matches against the expected value. +function expect { + local var=${1} + shift + local value=${1} + shift + if [[ "${!var}" != "${value}" ]]; then + echo "Value for ${var} is '${!var}' expected '${value}'" + exit 1 + else + echo "Value for ${var} matches expected '${value}'" + fi +} diff --git a/base/rootfs/usr/local/share/s6/finish b/base/rootfs/usr/local/share/s6/finish new file mode 100755 index 00000000..b277f20f --- /dev/null +++ b/base/rootfs/usr/local/share/s6/finish @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -e + +SERVICE_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" &>/dev/null && pwd)" +SERVICE=$(basename "${SERVICE_DIR}") +readonly SERVICE SERVICE_DIR + +# Handles exit codes / signals to ensure the container exits with the expected +# value. Meant to be sourced in /etc/service.d/*/finish scripts. +# See https://skarnet.org/software/s6/s6-supervise.html + +# Process received a non-catchable signal (i.e. SIGINT). s6 sets the exit +# code to be equal to 256 and expects the user to inspect the signal value +# instead. +# It is possible for the service to recieve a signal directly and exit +# with a exit code that indicates it exited due to receiving a signal +# e.g. 128 + signal. + +echo "s6-rc: info: service ${SERVICE} finish: executing..." >&2 + +# The first argument will be the exit code of your service, or 256 if your +# service was killed by an uncaught signal +if test "${1}" -eq 256; then + # 128 + signal indicates that it was not handled by our service. + EXIT_CODE=$(s6-expr 128 + "${2}") + SIGNAL="${2}" + HANDLED=1 + echo "s6-rc: info: service ${SERVICE} failed to handle signal: ${SIGNAL}..." >&2 +elif test "${1}" -gt 128; then + # Was handled but application adds to 128 + signal to indicate a it recieved the signal. + EXIT_CODE="${1}" + SIGNAL=$(s6-expr "${1}" - 128) + HANDLED=0 + echo "s6-rc: info: service ${SERVICE} handled signal: ${SIGNAL}..." >&2 +else + EXIT_CODE="${1}" + echo "s6-rc: info: service ${SERVICE} did not recieve a signal..." >&2 +fi +readonly SIGNAL EXIT_CODE HANDLED + +# Report the exit code / signal and exit (only if a non-zero exit code has not already been reported). +if test "$(cat /run/s6-linux-init-container-results/exitcode)" -eq 0; then + if test -z "${SIGNAL}"; then + echo "${EXIT_CODE}" >/run/s6-linux-init-container-results/exitcode + echo "s6-rc: info: service ${SERVICE} exiting with exit code: ${EXIT_CODE}" >&2 + else + if test "${SIGNAL}" -eq 15 -a "${HANDLED}" -eq 0; then + # Process received a SIGTERM. Shutdown gracefully and do not set exit code. + echo "s6-rc: info: service ${SERVICE} received SIGTERM exiting gracefully" >&2 + else + echo "${EXIT_CODE}" >/run/s6-linux-init-container-results/exitcode + echo "s6-rc: info: service ${SERVICE} received signal: ${SIGNAL}, exiting with exit code: ${EXIT_CODE}" >&2 + fi + fi +fi + +# Regardless take down all other services. +s6-svc -Od . +/run/s6/basedir/bin/halt diff --git a/base/tests/EnvironmentOverrideDatabase/docker-compose.yml b/base/tests/EnvironmentOverrideDatabase/docker-compose.yml new file mode 100644 index 00000000..97782582 --- /dev/null +++ b/base/tests/EnvironmentOverrideDatabase/docker-compose.yml @@ -0,0 +1,28 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +name: base-environmentoverridedatabase +services: + base: + # Allow downstream container to override `DB` environment variables. + environment: + TEST_DB_DRIVER: "postgresql" + TEST_DB_MYSQL_HOST: "DB_MYSQL_HOST override" + TEST_DB_MYSQL_PORT: "DB_MYSQL_PORT override" + TEST_DB_NAME: "DB_NAME override" + TEST_DB_PASSWORD: "DB_PASSWORD override" + TEST_DB_POSTGRESQL_HOST: "DB_POSTGRESQL_HOST override" + TEST_DB_POSTGRESQL_PORT: "DB_POSTGRESQL_PORT override" + TEST_DB_ROOT_PASSWORD: "DB_ROOT_PASSWORD override" + TEST_DB_ROOT_USER: "DB_ROOT_USER override" + TEST_DB_USER: "DB_USER override" + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${BASE:-islandora/base:local} diff --git a/base/tests/EnvironmentOverrideDatabase/test.sh b/base/tests/EnvironmentOverrideDatabase/test.sh new file mode 100755 index 00000000..e6a6d744 --- /dev/null +++ b/base/tests/EnvironmentOverrideDatabase/test.sh @@ -0,0 +1,20 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Checks that all `DB` environment variables can be overriden. +expect "DB_DRIVER" "postgresql" +expect "DB_MYSQL_HOST" "DB_MYSQL_HOST override" +expect "DB_MYSQL_PORT" "DB_MYSQL_PORT override" +expect "DB_NAME" "DB_NAME override" +expect "DB_PASSWORD" "DB_PASSWORD override" +expect "DB_POSTGRESQL_HOST" "DB_POSTGRESQL_HOST override" +expect "DB_POSTGRESQL_PORT" "DB_POSTGRESQL_PORT override" +expect "DB_ROOT_PASSWORD" "DB_ROOT_PASSWORD override" +expect "DB_ROOT_USER" "DB_ROOT_USER override" +expect "DB_USER" "DB_USER override" + +# All tests were successful +exit 0 diff --git a/base/tests/EnvironmentPrecedence/build.gradle.kts b/base/tests/EnvironmentPrecedence/build.gradle.kts new file mode 100644 index 00000000..105c867b --- /dev/null +++ b/base/tests/EnvironmentPrecedence/build.gradle.kts @@ -0,0 +1,20 @@ +import plugins.TestsPlugin.DockerCompose +import tasks.DockerPull + +val pull by tasks.registering(DockerPull::class) { + image.set("gcr.io/etcd-development/etcd:v3.5.6") +} + +tasks.named("setUp") { + doLast { + project.exec { + commandLine = baseArguments + listOf("up", "-d", "etcd") + workingDir = project.projectDir + } + project.exec { + commandLine = baseArguments + listOf("exec", "-T", "etcd", "sh", "/populate-etcd.sh") + workingDir = project.projectDir + } + } + dependsOn(pull) +} diff --git a/base/tests/EnvironmentPrecedence/defaults/DB_NAME b/base/tests/EnvironmentPrecedence/defaults/DB_NAME new file mode 100644 index 00000000..349a0a98 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/defaults/DB_NAME @@ -0,0 +1 @@ +DB_NAME /etc/defaults value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/defaults/DB_PASSWORD b/base/tests/EnvironmentPrecedence/defaults/DB_PASSWORD new file mode 100644 index 00000000..bfc6d51f --- /dev/null +++ b/base/tests/EnvironmentPrecedence/defaults/DB_PASSWORD @@ -0,0 +1 @@ +DB_PASSWORD /etc/defaults value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/defaults/DB_USER b/base/tests/EnvironmentPrecedence/defaults/DB_USER new file mode 100644 index 00000000..3e83b412 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/defaults/DB_USER @@ -0,0 +1 @@ +DB_USER /etc/defaults value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/defaults/JWT_ADMIN_TOKEN b/base/tests/EnvironmentPrecedence/defaults/JWT_ADMIN_TOKEN new file mode 100644 index 00000000..50c19516 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/defaults/JWT_ADMIN_TOKEN @@ -0,0 +1 @@ +JWT_ADMIN_TOKEN /etc/defaults value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/docker-compose.yml b/base/tests/EnvironmentPrecedence/docker-compose.yml new file mode 100644 index 00000000..ded51b08 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/docker-compose.yml @@ -0,0 +1,53 @@ +# file: docker-compose.yml +# +# Used for testing environment precedence follows what is expected from: +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +secrets: + # Secrets are #2 on the precedence list. + DB_PASSWORD: + file: "./secrets/DB_PASSWORD" + JWT_ADMIN_TOKEN: + file: "./secrets/JWT_ADMIN_TOKEN" + JWT_PRIVATE_KEY: + file: "./secrets/JWT_PRIVATE_KEY" + +name: base-environmentprecedence +services: + # Single node cluster. + etcd: + image: gcr.io/etcd-development/etcd:v3.5.6 + environment: + ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379" + ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379" + ETCD_UNSUPPORTED_ARCH: arm64 + volumes: + - ./populate-etcd.sh:/populate-etcd.sh + # etcd will be the confd backend and as such is #1 on the precedence list. + command: > + etcd --data-dir=/data + base: + # Environment variables defined here are #3 on on the precedence list. + # Environment variables specified in the Dockerfile for are #4 on the + # precedence list. Followed by files in /etc/defaults in the image, + # which are #5 on the precedence list + environment: + CONFD_BACKEND: "etcd" + DB_NAME: "DB_NAME passed in value" # Should take precedence. + DB_PASSWORD: "DB_PASSWORD passed in value" # Should be overridden by the secret. + JWT_ADMIN_TOKEN: "JWT_ADMIN_TOKEN passed in value" # Should be overridden by the confd backend. + secrets: + - DB_PASSWORD # Should take precedence. + - JWT_ADMIN_TOKEN # Should be overridden by confd backend. + - JWT_PRIVATE_KEY # Used to test template generation, should take precedence over /etc/defaults. + volumes: + - ./test.sh:/test.sh # Test to run. + - ./defaults/DB_NAME:/etc/defaults/DB_NAME # Should be overridden by the passed in environment variable. + - ./defaults/DB_PASSWORD:/etc/defaults/DB_PASSWORD # Should be overridden by the secret. + - ./defaults/DB_USER:/etc/defaults/DB_USER # Should be overridden by environment variable defined in Dockerfile. + - ./defaults/JWT_ADMIN_TOKEN:/etc/defaults/JWT_ADMIN_TOKEN # Should be overridden by confd backend. + command: + - /test.sh # Run test and exit. + image: ${BASE:-islandora/base:local} diff --git a/base/tests/EnvironmentPrecedence/populate-etcd.sh b/base/tests/EnvironmentPrecedence/populate-etcd.sh new file mode 100755 index 00000000..c308e81a --- /dev/null +++ b/base/tests/EnvironmentPrecedence/populate-etcd.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# Wait for etcd to start +while true; do + if etcdctl endpoint status >/dev/null 2>&1; then + break + fi + sleep 1 +done + +etcdctl put /jwt/admin/token "JWT_ADMIN_TOKEN confd value" diff --git a/base/tests/EnvironmentPrecedence/secrets/DB_PASSWORD b/base/tests/EnvironmentPrecedence/secrets/DB_PASSWORD new file mode 100644 index 00000000..ab0bcb16 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/secrets/DB_PASSWORD @@ -0,0 +1 @@ +DB_PASSWORD secret value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/secrets/JWT_ADMIN_TOKEN b/base/tests/EnvironmentPrecedence/secrets/JWT_ADMIN_TOKEN new file mode 100644 index 00000000..48eaba09 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/secrets/JWT_ADMIN_TOKEN @@ -0,0 +1 @@ +JWT_ADMIN_TOKEN secret value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/secrets/JWT_PRIVATE_KEY b/base/tests/EnvironmentPrecedence/secrets/JWT_PRIVATE_KEY new file mode 100644 index 00000000..d394d070 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/secrets/JWT_PRIVATE_KEY @@ -0,0 +1 @@ +JWT_PRIVATE_KEY secret value \ No newline at end of file diff --git a/base/tests/EnvironmentPrecedence/test.sh b/base/tests/EnvironmentPrecedence/test.sh new file mode 100755 index 00000000..de9458c0 --- /dev/null +++ b/base/tests/EnvironmentPrecedence/test.sh @@ -0,0 +1,34 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Check environment variables match expectations otherwise exit non-zero. +# +# For each level we specify an a value for that level and all levels that are +# lower precedence than it. We then check to see that precedence holds as +# expected: +# +# 1. Confd backend (highest) +# 2. Secrets kept in /run/secrets +# 3. Environment variables passed into the container +# 4. Environment variables defined in Dockerfile(s) +# 5. Environment variables defined in the /etc/defaults directory (lowest only used for multiline variables) + +# For ease of reading overridden values follow the format: +# ENV_VAR_NAME="ENV_VAR_NAME SOURCE value" +expect "JWT_ADMIN_TOKEN" "JWT_ADMIN_TOKEN confd value" # Confd backend should take precedence +expect "DB_PASSWORD" "DB_PASSWORD secret value" # Secret should take precedence +expect "DB_NAME" "DB_NAME passed in value" # Environment passed into the container should take precedence +expect "DB_USER" "default" # Environment variables defined in Dockerfile should take precedence +expect "JWT_PUBLIC_KEY" "$(cat /etc/defaults/JWT_PUBLIC_KEY)" # Unspecified /etc/defaults value is used. + +# Check templated output from confd backend matches expectations. +diff /opt/keys/jwt/syn-settings.xml <(sed -e "s|{{ getenv \"JWT_ADMIN_TOKEN\" }}|${JWT_ADMIN_TOKEN}|" /etc/confd/templates/syn-settings.xml.tmpl) + +# Check templated output from secrets matches expectations. +diff /opt/keys/jwt/private.key <(echo -n "${JWT_PRIVATE_KEY}") + +# All tests were successful +exit 0 diff --git a/base/tests/ServiceStartsWithDefaults/build.gradle.kts b/base/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..ffac836a --- /dev/null +++ b/base/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,5 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + expectOutput("base", "service confd successfully started") +} diff --git a/base/tests/ServiceStartsWithDefaults/docker-compose.yml b/base/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..331cff6f --- /dev/null +++ b/base/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,12 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: base-servicestartswithdefaults +services: + base: + <<: *common + image: ${BASE:-islandora/base:local} diff --git a/base/tests/SigIntExitCode/build.gradle.kts b/base/tests/SigIntExitCode/build.gradle.kts new file mode 100644 index 00000000..5cd15053 --- /dev/null +++ b/base/tests/SigIntExitCode/build.gradle.kts @@ -0,0 +1,5 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + expectExitCode("base", 130) // 128 + 2 (SIGINT) == 130 +} diff --git a/base/tests/SigIntExitCode/docker-compose.yml b/base/tests/SigIntExitCode/docker-compose.yml new file mode 100644 index 00000000..b10b3dca --- /dev/null +++ b/base/tests/SigIntExitCode/docker-compose.yml @@ -0,0 +1,18 @@ +# file: docker-compose.yml +# +# Tests that when a service exits, it's exit code is used as the return exit code for the container. +version: "3.8" + +x-common: &common + restart: "no" + +name: base-sigintexitcode +services: + base: + <<: *common + image: ${BASE:-islandora/base:local} + volumes: + - ./service:/etc/services.d/test + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/base/tests/SigIntExitCode/service/finish b/base/tests/SigIntExitCode/service/finish new file mode 100755 index 00000000..5672a920 --- /dev/null +++ b/base/tests/SigIntExitCode/service/finish @@ -0,0 +1,6 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# shellcheck disable=SC1091 +source /usr/local/share/s6/finish "${1}" "${2}" diff --git a/base/tests/SigIntExitCode/service/run b/base/tests/SigIntExitCode/service/run new file mode 100755 index 00000000..b3b49857 --- /dev/null +++ b/base/tests/SigIntExitCode/service/run @@ -0,0 +1,5 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +exec sleep 10000 diff --git a/base/tests/SigIntExitCode/test.sh b/base/tests/SigIntExitCode/test.sh new file mode 100755 index 00000000..24d9a3df --- /dev/null +++ b/base/tests/SigIntExitCode/test.sh @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +sleep 10 +echo "s6-rc: info: Send SIGINT to confd service." >&2 +s6-svc -i /run/s6/legacy-services/test + +echo "s6-rc: info: Waiting for exit." >&2 +sleep 100000 diff --git a/base/tests/SigKillExitCode/build.gradle.kts b/base/tests/SigKillExitCode/build.gradle.kts new file mode 100644 index 00000000..420adf31 --- /dev/null +++ b/base/tests/SigKillExitCode/build.gradle.kts @@ -0,0 +1,21 @@ +import plugins.TestsPlugin.DockerComposeUp +import plugins.TestsPlugin.DockerComposeUp.Companion.pool +import java.lang.Thread.sleep +import java.time.Duration.ofSeconds +import java.util.concurrent.CompletableFuture.supplyAsync + +tasks.named("test") { + expectExitCode("base", 137) // 128 + 9 SIGKILL (Bash script does not catch signal) + doFirst { + supplyAsync( + { + // Send TERM after 10 seconds externally. + sleep(ofSeconds(10).toMillis()) + project.exec { + workingDir = projectDir + commandLine = baseArguments + listOf("stop") + } + }, pool + ) + } +} diff --git a/base/tests/SigKillExitCode/docker-compose.yml b/base/tests/SigKillExitCode/docker-compose.yml new file mode 100644 index 00000000..5e23f9e6 --- /dev/null +++ b/base/tests/SigKillExitCode/docker-compose.yml @@ -0,0 +1,15 @@ +# file: docker-compose.yml +# +# Tests that when a service receives a SIGTERM it exits 0 after cleaning up the running services. +version: "3.8" + +x-common: &common + restart: "no" + +name: base-sigkillexitcode +services: + base: + <<: *common + image: ${BASE:-islandora/base:local} + volumes: + - ./service:/etc/services.d/test diff --git a/base/tests/SigKillExitCode/service/finish b/base/tests/SigKillExitCode/service/finish new file mode 100755 index 00000000..5672a920 --- /dev/null +++ b/base/tests/SigKillExitCode/service/finish @@ -0,0 +1,6 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# shellcheck disable=SC1091 +source /usr/local/share/s6/finish "${1}" "${2}" diff --git a/base/tests/SigKillExitCode/service/run b/base/tests/SigKillExitCode/service/run new file mode 100755 index 00000000..85e13ea9 --- /dev/null +++ b/base/tests/SigKillExitCode/service/run @@ -0,0 +1,6 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +trap "sleep 1000" SIGTERM +sleep 10000 diff --git a/base/tests/SigTermExitCode/build.gradle.kts b/base/tests/SigTermExitCode/build.gradle.kts new file mode 100644 index 00000000..25f499fc --- /dev/null +++ b/base/tests/SigTermExitCode/build.gradle.kts @@ -0,0 +1,5 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + expectExitCode("base", 143) // 128 + 15 (SIGTERM) == 143 +} diff --git a/base/tests/SigTermExitCode/docker-compose.yml b/base/tests/SigTermExitCode/docker-compose.yml new file mode 100644 index 00000000..d269eef5 --- /dev/null +++ b/base/tests/SigTermExitCode/docker-compose.yml @@ -0,0 +1,18 @@ +# file: docker-compose.yml +# +# Tests that when a service exits, it's exit code is used as the return exit code for the container. +version: "3.8" + +x-common: &common + restart: "no" + +name: base-sigtermexitcode +services: + base: + <<: *common + image: ${BASE:-islandora/base:local} + volumes: + - ./service:/etc/services.d/test + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/base/tests/SigTermExitCode/service/finish b/base/tests/SigTermExitCode/service/finish new file mode 100755 index 00000000..5672a920 --- /dev/null +++ b/base/tests/SigTermExitCode/service/finish @@ -0,0 +1,6 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# shellcheck disable=SC1091 +source /usr/local/share/s6/finish "${1}" "${2}" diff --git a/base/tests/SigTermExitCode/service/run b/base/tests/SigTermExitCode/service/run new file mode 100755 index 00000000..b3b49857 --- /dev/null +++ b/base/tests/SigTermExitCode/service/run @@ -0,0 +1,5 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +exec sleep 10000 diff --git a/base/tests/SigTermExitCode/test.sh b/base/tests/SigTermExitCode/test.sh new file mode 100755 index 00000000..7639e6a3 --- /dev/null +++ b/base/tests/SigTermExitCode/test.sh @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +sleep 10 +echo "s6-rc: info: Send SIGINT to confd service." >&2 +s6-svc -t /run/s6/legacy-services/test + +echo "s6-rc: info: Waiting for exit." >&2 +sleep 100000 diff --git a/base/tests/SigTermExitHandled/build.gradle.kts b/base/tests/SigTermExitHandled/build.gradle.kts new file mode 100644 index 00000000..45761ae7 --- /dev/null +++ b/base/tests/SigTermExitHandled/build.gradle.kts @@ -0,0 +1,5 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + expectExitCode("base", 15) // 15 (SIGTERM) handled by the test service. +} diff --git a/base/tests/SigTermExitHandled/docker-compose.yml b/base/tests/SigTermExitHandled/docker-compose.yml new file mode 100644 index 00000000..2ba370b6 --- /dev/null +++ b/base/tests/SigTermExitHandled/docker-compose.yml @@ -0,0 +1,18 @@ +# file: docker-compose.yml +# +# Tests that when a service exits, it's exit code is used as the return exit code for the container. +version: "3.8" + +x-common: &common + restart: "no" + +name: base-sigtermexithandled +services: + base: + <<: *common + image: ${BASE:-islandora/base:local} + volumes: + - ./service:/etc/services.d/test + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/base/tests/SigTermExitHandled/service/finish b/base/tests/SigTermExitHandled/service/finish new file mode 100755 index 00000000..5672a920 --- /dev/null +++ b/base/tests/SigTermExitHandled/service/finish @@ -0,0 +1,6 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# shellcheck disable=SC1091 +source /usr/local/share/s6/finish "${1}" "${2}" diff --git a/base/tests/SigTermExitHandled/service/run b/base/tests/SigTermExitHandled/service/run new file mode 100755 index 00000000..06507dd4 --- /dev/null +++ b/base/tests/SigTermExitHandled/service/run @@ -0,0 +1,17 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +declare child +_term() { + local signal=$(($? - 128)) + echo "Caught Signal: ${signal}" + kill -TERM "$child" 2>/dev/null + exit 15 +} +trap "_term" SIGTERM + +sleep 1000000 & +child=$! + +wait "${child}" diff --git a/base/tests/SigTermExitHandled/test.sh b/base/tests/SigTermExitHandled/test.sh new file mode 100755 index 00000000..987458b9 --- /dev/null +++ b/base/tests/SigTermExitHandled/test.sh @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +sleep 10 +echo "s6-rc: info: Send SIGTERM to test service." >&2 +s6-svc -t /run/s6/legacy-services/test + +echo "s6-rc: info: Waiting for exit." >&2 +sleep 100000 diff --git a/blazegraph/.dockerignore b/blazegraph/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/blazegraph/.dockerignore +++ b/blazegraph/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/blazegraph/Dockerfile b/blazegraph/Dockerfile index 379f64c6..467f4802 100644 --- a/blazegraph/Dockerfile +++ b/blazegraph/Dockerfile @@ -1,17 +1,21 @@ -# syntax=docker/dockerfile:experimental -FROM local/tomcat:latest +# syntax=docker/dockerfile:1.5.1 +FROM tomcat -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - BLAZEGRAPH_VERSION="CANDIDATE_2_1_5" && \ - BLAZEGRAPH_FILE="blazegraph.war" && \ - BLAZEGRAPH_URL="https://github.com/blazegraph/database/releases/download/BLAZEGRAPH_RELEASE_${BLAZEGRAPH_VERSION}/${BLAZEGRAPH_FILE}" && \ - BLAZEGRAPH_SHA256="b22f1a1aa8e536443db9a57da63720813374ef59e4021cfa9ad0e98f9a420e85" && \ - download.sh --url "${BLAZEGRAPH_URL}" --sha256 "${BLAZEGRAPH_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-war-into-tomcat.sh --name "bigdata" --file "${DOWNLOAD_CACHE_DIRECTORY}/${BLAZEGRAPH_FILE}" +ARG TARGETARCH +ARG BLAZEGRAPH_VERSION="CANDIDATE_2_1_5" +ARG BLAZEGRAPH_FILE="blazegraph.war" +ARG BLAZEGRAPH_URL="https://github.com/blazegraph/database/releases/download/BLAZEGRAPH_RELEASE_${BLAZEGRAPH_VERSION}/${BLAZEGRAPH_FILE}" +ARG BLAZEGRAPH_SHA256="b22f1a1aa8e536443db9a57da63720813374ef59e4021cfa9ad0e98f9a420e85" -COPY rootfs / +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=blazegraph-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${BLAZEGRAPH_URL}" \ + --sha256 "${BLAZEGRAPH_SHA256}" \ + --dest "/opt/tomcat/webapps/bigdata" \ + && \ + cleanup.sh -RUN mkdir /data && \ - chown tomcat:tomcat /data && \ - chown -R tomcat:tomcat /opt/tomcat +COPY --link rootfs / + +RUN chown -R tomcat:tomcat /opt/tomcat diff --git a/blazegraph/README.md b/blazegraph/README.md index 85a71bfe..778b1b5d 100644 --- a/blazegraph/README.md +++ b/blazegraph/README.md @@ -23,15 +23,5 @@ additional settings, volumes, ports, etc. | :---- | :--------------------------- | | /data | Location of the backing file | -## Logs - -| Path | Description | -| :--------------------------------- | :---------- | -| /opt/tomcat/logs/rules.log | | -| /opt/tomcat/logs/queryLog.csv | | -| /opt/tomcat/logs/queryRunState.log | | -| /opt/tomcat/logs/solutions.csv | | -| /opt/tomcat/logs/sparql.txt | | - [Blazegraph Documentation]: https://github.com/blazegraph/database/wiki/About_Blazegraph [Blazegraph]: https://blazegraph.com/ diff --git a/blazegraph/rootfs/etc/confd/conf.d/RWStore.properties.toml b/blazegraph/rootfs/etc/confd/conf.d/RWStore.properties.toml deleted file mode 100644 index 6a68991a..00000000 --- a/blazegraph/rootfs/etc/confd/conf.d/RWStore.properties.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "RWStore.properties.tmpl" -dest = "/opt/tomcat/webapps/bigdata/WEB-INF/classes/RWStore.properties" -uid = 100 -gid = 1000 -keys = ["/"] diff --git a/blazegraph/rootfs/etc/confd/conf.d/log4j.properties.toml b/blazegraph/rootfs/etc/confd/conf.d/log4j.properties.toml deleted file mode 100644 index 0a634d63..00000000 --- a/blazegraph/rootfs/etc/confd/conf.d/log4j.properties.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "log4j.properties.tmpl" -dest = "/opt/tomcat/webapps/bigdata/WEB-INF/classes/log4j.properties" -uid = 100 -gid = 1000 -keys = ["/"] diff --git a/blazegraph/rootfs/etc/confd/confd.toml b/blazegraph/rootfs/etc/confd/confd.toml deleted file mode 100644 index e6508b2d..00000000 --- a/blazegraph/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/blazegraph" diff --git a/blazegraph/rootfs/etc/cont-init.d/03-blazegraph-setup.sh b/blazegraph/rootfs/etc/cont-init.d/03-blazegraph-setup.sh deleted file mode 100755 index e568d6e1..00000000 --- a/blazegraph/rootfs/etc/cont-init.d/03-blazegraph-setup.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /opt/tomcat/logs/rules.log -chown tomcat:tomcat /opt/tomcat/logs/rules.log - -ln -sf /dev/stdout /opt/tomcat/logs/queryLog.csv -chown tomcat:tomcat /dev/stdout /opt/tomcat/logs/queryLog.csv - -ln -sf /dev/stdout /opt/tomcat/logs/queryRunState.log -chown tomcat:tomcat /dev/stdout /opt/tomcat/logs/queryRunState.log - -ln -sf /dev/stdout /opt/tomcat/logs/solutions.csv -chown tomcat:tomcat /dev/stdout /opt/tomcat/logs/solutions.csv - -ln -sf /dev/stdout /opt/tomcat/logs/sparql.txt -chown tomcat:tomcat /dev/stdout /opt/tomcat/logs/sparql.txt - -# When bind mounting we need to ensure that we -# actually can write to the folder. -chown tomcat:tomcat /data diff --git a/blazegraph/rootfs/etc/confd/templates/RWStore.properties.tmpl b/blazegraph/rootfs/opt/tomcat/webapps/bigdata/WEB-INF/classes/RWStore.properties similarity index 100% rename from blazegraph/rootfs/etc/confd/templates/RWStore.properties.tmpl rename to blazegraph/rootfs/opt/tomcat/webapps/bigdata/WEB-INF/classes/RWStore.properties diff --git a/blazegraph/rootfs/etc/confd/templates/log4j.properties.tmpl b/blazegraph/rootfs/opt/tomcat/webapps/bigdata/WEB-INF/classes/log4j.properties similarity index 84% rename from blazegraph/rootfs/etc/confd/templates/log4j.properties.tmpl rename to blazegraph/rootfs/opt/tomcat/webapps/bigdata/WEB-INF/classes/log4j.properties index 4f5c76f0..fbb2304b 100644 --- a/blazegraph/rootfs/etc/confd/templates/log4j.properties.tmpl +++ b/blazegraph/rootfs/opt/tomcat/webapps/bigdata/WEB-INF/classes/log4j.properties @@ -30,14 +30,12 @@ log4j.appender.dest2=org.apache.log4j.ConsoleAppender log4j.appender.dest2.layout=org.apache.log4j.PatternLayout log4j.appender.dest2.layout.ConversionPattern=%-5p: %r %X{hostname} %X{serviceUUID} %X{taskname} %X{timestamp} %X{resources} %t %l: %m%n -## +## # Rule execution log. This is a formatted log file (comma delimited). log4j.logger.com.bigdata.relation.rule.eval.RuleLog=INFO,ruleLog log4j.additivity.com.bigdata.relation.rule.eval.RuleLog=false -log4j.appender.ruleLog=org.apache.log4j.FileAppender +log4j.appender.ruleLog=org.apache.log4j.ConsoleAppender log4j.appender.ruleLog.Threshold=ALL -log4j.appender.ruleLog.File=/opt/tomcat/logs/rules.log -log4j.appender.ruleLog.Append=true # I find that it is nicer to have this unbuffered since you can see what # is going on and to make sure that I have complete rule evaluation logs # on shutdown. @@ -45,14 +43,12 @@ log4j.appender.ruleLog.BufferedIO=false log4j.appender.ruleLog.layout=org.apache.log4j.PatternLayout log4j.appender.ruleLog.layout.ConversionPattern=%m -## +## # Summary query evaluation log (tab delimited file). Uncomment the next line to enable. #log4j.logger.com.bigdata.bop.engine.QueryLog=INFO,queryLog log4j.additivity.com.bigdata.bop.engine.QueryLog=false -log4j.appender.queryLog=org.apache.log4j.FileAppender +log4j.appender.queryLog=org.apache.log4j.ConsoleAppender log4j.appender.queryLog.Threshold=ALL -log4j.appender.queryLog.File=/opt/tomcat/logs/queryLog.csv -log4j.appender.queryLog.Append=true # I find that it is nicer to have this unbuffered since you can see what # is going on and to make sure that I have complete rule evaluation logs # on shutdown. @@ -60,14 +56,12 @@ log4j.appender.queryLog.BufferedIO=false log4j.appender.queryLog.layout=org.apache.log4j.PatternLayout log4j.appender.queryLog.layout.ConversionPattern=%m -## +## # BOp run state trace (tab delimited file). Uncomment the next line to enable. #log4j.logger.com.bigdata.bop.engine.RunState$TableLog=INFO,queryRunStateLog log4j.additivity.com.bigdata.bop.engine.RunState$TableLog=false -log4j.appender.queryRunStateLog=org.apache.log4j.FileAppender +log4j.appender.queryRunStateLog=org.apache.log4j.ConsoleAppender log4j.appender.queryRunStateLog.Threshold=ALL -log4j.appender.queryRunStateLog.File=/opt/tomcat/logs/queryRunState.log -log4j.appender.queryRunStateLog.Append=true # I find that it is nicer to have this unbuffered since you can see what # is going on and to make sure that I have complete rule evaluation logs # on shutdown. @@ -75,15 +69,13 @@ log4j.appender.queryRunStateLog.BufferedIO=false log4j.appender.queryRunStateLog.layout=org.apache.log4j.PatternLayout log4j.appender.queryRunStateLog.layout.ConversionPattern=%m -## +## # Solutions trace (tab delimited file). Uncomment the next line to enable. #log4j.logger.com.bigdata.bop.engine.SolutionsLog=INFO,solutionsLog log4j.additivity.com.bigdata.bop.engine.SolutionsLog=false log4j.appender.solutionsLog=org.apache.log4j.ConsoleAppender -#log4j.appender.solutionsLog=org.apache.log4j.FileAppender +#log4j.appender.solutionsLog=org.apache.log4j.ConsoleAppender log4j.appender.solutionsLog.Threshold=ALL -log4j.appender.solutionsLog.File=/opt/tomcat/logs/solutions.csv -log4j.appender.solutionsLog.Append=true # I find that it is nicer to have this unbuffered since you can see what # is going on and to make sure that I have complete rule evaluation logs # on shutdown. @@ -91,20 +83,17 @@ log4j.appender.solutionsLog.BufferedIO=false log4j.appender.solutionsLog.layout=org.apache.log4j.PatternLayout log4j.appender.solutionsLog.layout.ConversionPattern=SOLUTION:\t%m -## +## # SPARQL query trace (plain text file). Uncomment 2nd line to enable. log4j.logger.com.bigdata.rdf.sparql.ast.eval.ASTEvalHelper=WARN #log4j.logger.com.bigdata.rdf.sparql.ast.eval.ASTEvalHelper=INFO,sparqlLog log4j.additivity.com.bigdata.rdf.sparql.ast.eval.ASTEvalHelper=false log4j.appender.sparqlLog=org.apache.log4j.ConsoleAppender -#log4j.appender.sparqlLog=org.apache.log4j.FileAppender +#log4j.appender.sparqlLog=org.apache.log4j.ConsoleAppender log4j.appender.sparqlLog.Threshold=ALL -log4j.appender.sparqlLog.File=/opt/tomcat/logs/sparql.txt -log4j.appender.sparqlLog.Append=true # I find that it is nicer to have this unbuffered since you can see what # is going on and to make sure that I have complete rule evaluation logs # on shutdown. log4j.appender.sparqlLog.BufferedIO=false log4j.appender.sparqlLog.layout=org.apache.log4j.PatternLayout log4j.appender.sparqlLog.layout.ConversionPattern=#----------%d-----------tx=%X{tx}\n%m\n - diff --git a/blazegraph/tests/ServiceStartsWithDefaults/docker-compose.yml b/blazegraph/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..2d6b38ec --- /dev/null +++ b/blazegraph/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: blazegraph-servicestartswithdefaults +services: + blazegraph: + <<: *common + image: ${BLAZEGRAPH:-islandora/blazegraph:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/blazegraph/tests/ServiceStartsWithDefaults/test.sh b/blazegraph/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..cae95eb8 --- /dev/null +++ b/blazegraph/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,10 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +wait_20x "http://localhost:8080/bigdata/#status" + +# Service must start for us to get to this point. +exit 0 diff --git a/build.gradle.kts b/build.gradle.kts index e8af902c..64a420ff 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1 @@ -buildscript { - repositories { - gradlePluginPortal() - } - dependencies { - classpath("ca.islandora:isle-gradle-docker-plugin:0.0.1") - } -} -apply(plugin = "ca.islandora.gradle.docker") +apply(plugin = "io.github.nigelgbanks.Isle") diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore new file mode 100644 index 00000000..a2fd048f --- /dev/null +++ b/buildSrc/.gitignore @@ -0,0 +1,8 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build + +# Ignore IDEA project files. +.idea diff --git a/buildSrc/LICENSE b/buildSrc/LICENSE new file mode 100644 index 00000000..01939a54 --- /dev/null +++ b/buildSrc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Islandora-Devops + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/buildSrc/README.md b/buildSrc/README.md new file mode 100644 index 00000000..57028885 --- /dev/null +++ b/buildSrc/README.md @@ -0,0 +1,167 @@ +# ISLE: Gradle Docker Plugin + +[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE) +![CI](https://github.com/Islandora-Devops/isle-gradle-docker-plugin/workflows/CI/badge.svg) + +- [Introduction](#introduction) +- [Requirements](#requirements) +- [Building](#building) + - [Build and Publish the Plugin](#build-and-publish-the-plugin) +- [Using the Plugin](#using-the-plugin) +- [Using the Plugin from Source](#using-the-plugin-from-source) + +## Introduction + +This repository provides a Gradle plugin that supports building interdependent Docker images with [Buildkit] support. + +The plugin is setup such that it will automatically detect which folders should be considered +[projects](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html) and what dependencies exist between them. +The only caveat is that the projects cannot be nested, though that use case does not really apply. + +The dependencies are resolved by parsing the Dockerfile and looking for ``FROM`` +statements to determine which images are required to build it. + +This means to add a new Docker image to the project you do not need to modify the build scripts, simply add a new folder +and place your Dockerfile inside it, and it will be discovered built in the correct order relative to the other images. + +## Requirements + +To build this plugin the following is required: + +- [OpenJDK or Oracle JDK 11+](https://www.java.com/en/download/) + +## Building + +The build scripts rely on Gradle and should function equally well across platforms. The only difference being the script +you call to interact with gradle +(the following assumes you are executing from the **root directory** of the project): + +**Linux or OSX:** + +```bash +./gradlew +``` + +**Windows:** + +```bash +gradlew.bat +``` + +For the remaining examples the **Linux or OSX** call method will be used, if using Windows substitute the call to Gradle +script. + +Gradle is a project/task based build system to query all the available tasks use the following command. + +```bash +./gradlew tasks --all +``` + +Which should return something akin to: + +```bash +> Task :tasks + +------------------------------------------------------------ +Tasks runnable from root project +------------------------------------------------------------ + +Build tasks +----------- +assemble - Assembles the outputs of this project. +build - Assembles and tasks.tests this project. +buildDependents - Assembles and tasks.tests this project and all projects that depend on it. +buildNeeded - Assembles and tasks.tests this project and all projects it depends on. +classes - Assembles main classes. +clean - Deletes the build directory. +jar - Assembles a jar archive containing the main classes. +testClasses - Assembles test classes. + +... +``` + +In Gradle each Project maps onto a folder in the file system path where it is delimited by ``:`` instead of ``/`` (Unix) +or ``\`` (Windows). + +The root project ``:`` can be omitted. + +So if you want to run a particular task ``taskname`` that resided in the project folder ``project/subproject`` you would +specify it like so: + +```bash +./gradlew :project:subproject:taskname +``` + +To get more verbose output from Gradle use the ``--info`` argument like so: + +```bash +./gradlew :PROJECT:TASK --info +``` + +To build all the docker images you can use the following command: + +### Build and Publish the Plugin + +The following will build and test the plugin. + +```bash +./gradlew build +``` + +The following will publish the module to Github packages, which requires you setup a personal access token. + +```bash +export GITHUB_REPOSITORY=Islandora-Devops/isle-gradle-docker-plugin +export GITHUB_ACTOR=nigelgbanks +export GITHUB_TOKEN=XXXXXXXXXXXXXXXXX +./gradlew build publish +``` + +Alternatively you can rely on the Github actions which will publish when a release is made. + +> N.B. It is NOT POSSIBLE to delete/replace packages on a public repository (except *-SNAPSHOT). A new release must be made. + +## Using the Plugin + +To include this plugin for versions 0.11+ add the following to your `build.gradle.kts` file: + +```kotlin +plugins { + id("io.github.nigelgbanks.Isle") version "1.0.11" +} +``` + +## Using the Plugin from Source + +To include this plugin in another project use the following snippet of Kotlin script in your Gradle project with +the `settings.gradle.kts` file that allows the plugin source to be discoverable: + +```kotlin +sourceControl { + gitRepository(uri("file:///PATH_TO_FOLDER/isle-gradle-docker-plugin/.git")) { + producesModule("io.github.nigelgbanks:isle-gradle-docker-plugin") + } +} +``` + +With that in place you can include the plugin in your respective project `build.gradle.kts` file: + +```kotlin +buildscript { + repositories { + gradlePluginPortal() + } + dependencies { + classpath("io.github.nigelgbanks:isle-gradle-docker-plugin") { + version { + branch = "BRANCH_NAME" + } + } + } +} +apply(plugin = "io.github.nigelgbanks.Isle") +``` + +Note that it will only use **committed** changes. + +[Buildkit]: https://github.com/moby/buildkit/blob/main/frontend/dockerfile/docs/experimental.md diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..5cbdaf52 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,75 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +group = "io.github.nigelgbanks" + +repositories { + mavenCentral() + gradlePluginPortal() +} + +plugins { + id("com.gradle.plugin-publish") version "1.1.0" + `java-gradle-plugin` + `kotlin-dsl` +} + +afterEvaluate { + tasks.withType().configureEach { + kotlinOptions { + apiVersion = "1.6" + languageVersion = "1.6" + } + } +} + +dependencies { + implementation("org.apache.commons:commons-io:1.3.2") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.1") + implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.1") +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +gradlePlugin { + website.set("https://github.com/Islandora-Devops/isle-gradle-docker-plugin") + vcsUrl.set("https://github.com/Islandora-Devops/isle-gradle-docker-plugin") + + plugins { + create("Isle") { + id = "io.github.nigelgbanks.Isle" + implementationClass = "plugins.IslePlugin" + displayName = "Isle" + description = "Main gradle plugin for the Islandora Isle project" + tags.set(listOf("isle")) + } + create("IsleDockerHub") { + id = "io.github.nigelgbanks.IsleDockerHub" + implementationClass = "plugins.DockerHubPlugin" + displayName = "IsleDockerHub" + description = "Tasks for managing DockerHub tags, etc." + tags.set(listOf("isle")) + } + create("IsleReports") { + id = "io.github.nigelgbanks.IsleReports" + implementationClass = "plugins.ReportsPlugin" + displayName = "IsleReports" + description = "Generates security reports for a single project" + tags.set(listOf("isle")) + } + create("IsleTests") { + id = "io.github.nigelgbanks.IsleTests" + implementationClass = "plugins.TestsPlugin" + displayName = "IsleTests" + description = "Perform tests with docker-compose files" + tags.set(listOf("isle")) + } + } +} + +extensions.findByName("buildScan")?.withGroovyBuilder { + setProperty("termsOfServiceUrl", "https://gradle.com/terms-of-service") + setProperty("termsOfServiceAgree", "yes") +} diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties new file mode 100644 index 00000000..72a5f139 --- /dev/null +++ b/buildSrc/gradle.properties @@ -0,0 +1,4 @@ +# suppress inspection "UnusedProperty" for whole file +org.gradle.parallel=true +org.gradle.caching=true +version=1.0.17 diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.jar b/buildSrc/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..490fda85 Binary files /dev/null and b/buildSrc/gradle/wrapper/gradle-wrapper.jar differ diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.properties b/buildSrc/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..070cb702 --- /dev/null +++ b/buildSrc/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/buildSrc/gradlew b/buildSrc/gradlew new file mode 100755 index 00000000..2fe81a7d --- /dev/null +++ b/buildSrc/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/buildSrc/gradlew.bat b/buildSrc/gradlew.bat new file mode 100644 index 00000000..62bd9b9c --- /dev/null +++ b/buildSrc/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 00000000..3646e4e6 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "isle-gradle-docker-plugin" diff --git a/buildSrc/src/main/kotlin/plugins/DockerHubPlugin.kt b/buildSrc/src/main/kotlin/plugins/DockerHubPlugin.kt new file mode 100644 index 00000000..cc948384 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugins/DockerHubPlugin.kt @@ -0,0 +1,332 @@ +package plugins + +import com.fasterxml.jackson.core.JsonFactory +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule +import org.apache.commons.io.output.ByteArrayOutputStream +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.* +import org.gradle.workers.WorkAction +import org.gradle.workers.WorkParameters +import org.gradle.workers.WorkQueue +import org.gradle.workers.WorkerExecutor +import plugins.IslePlugin.Companion.isDockerProject +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse +import javax.inject.Inject + + +// Delete inactive tags, and other administrative tasks. +@Suppress("unused") +class DockerHubPlugin : Plugin { + companion object { + // User to use when authenticating against DockerHub. + val Project.dockerHubUsername: String + get() = properties.getOrDefault("isle.dockerhub.user", "islandoracommunity") as String + + // Personal access token use to log in to DockerHub. + val Project.dockerHubPersonalAccessToken: String + get() = properties.getOrDefault("isle.dockerhub.personal.access.token", "") as String + + // The repository to remove tags from. + val Project.dockerHubRepository: String + get() = properties.getOrDefault("isle.dockerhub.repository", "islandora") as String + + // Only remove tags that are marked as "Inactive". + val Project.removeInactiveOnly: Boolean + get() = (properties.getOrDefault("isle.dockerhub.remove.inactive.only", "true") as String).toBoolean() + + // Additional tags aside from branches and tags in the repository to prevent the deletion of. + // List of values separated by comma. + val Project.dockerHubProtectedTags: Set + get() = (properties.getOrDefault("isle.dockerhub.protected.tags", "") as String) + .split(',') + .filter { it.isNotBlank() } + .toSet() + } + + open class ProtectedDockerHubTags : DefaultTask() { + @Input + val images = project.objects.setProperty() + + @Input + val excludeTags = project.objects.setProperty().convention(project.dockerHubProtectedTags) + + @OutputFile + val protectedTagsFile = + project.objects.fileProperty().convention(project.layout.buildDirectory.file("protected.tags.txt")) + + @get:Internal + val protectedTags: Set + get() = protectedTagsFile.get().asFile.readLines().toSet() + + init { + // Always re-run. + outputs.upToDateWhen { false } + } + + @TaskAction + fun exec() { + project.exec { + commandLine = listOf("git", "fetch", "--all") + workingDir = project.projectDir + } + + val gitTags = ByteArrayOutputStream().use { output -> + project.exec { + commandLine = listOf("git", "tag", "-l") + workingDir = project.projectDir + standardOutput = output + } + output.toString() + }.lines() + + val gitBranches = ByteArrayOutputStream().use { output -> + project.exec { + commandLine = listOf("git", "branch", "-r") + workingDir = project.projectDir + standardOutput = output + } + output.toString() + }.lines() + .filterNot { it.contains("^.*/HEAD".toRegex()) } // Ignore HEAD + .map { it.replace(".*/".toRegex(), "") } // Strip remotes. + + val imageTags: Set = (gitTags + gitBranches + excludeTags.get()) + .plus("latest") // Never delete latest + .filter { it.isNotBlank() } + .toSet() + + val archTags = listOf("amd64", "arm64").flatMap { suffix -> + imageTags.map { "${it}-${suffix}" } + } + + val cacheTags = images.get().flatMap { image -> + archTags.map { "${image}-${it}" } + } + + val allTags = imageTags + archTags + cacheTags + + protectedTagsFile.get().asFile.writeText(allTags.joinToString("\n")) + } + } + + open class GetDockerHubAuthenticationToken : DefaultTask() { + + @Input + val dockerHubUsername = project.objects.property().convention(project.dockerHubUsername) + + @Input + val dockerHubPassword = project.objects.property().convention(project.dockerHubPersonalAccessToken) + + // Explicitly not stored to a file as we do not want to leak/persist this value anywhere. + @Internal + val token = project.objects.property() + + @TaskAction + fun exec() { + val objectMapper = ObjectMapper() + val credentials = mapOf("username" to dockerHubUsername.get(), "password" to dockerHubPassword.get()) + val body = objectMapper.writeValueAsString(credentials) + + val client = HttpClient.newBuilder().build() + val request = HttpRequest.newBuilder() + .header("Content-Type", "application/json") + .uri(URI.create("https://hub.docker.com/v2/users/login/")) + .POST(HttpRequest.BodyPublishers.ofString(body)) + .build() + + val response = client.send(request, HttpResponse.BodyHandlers.ofString()) + if (response.statusCode() == 200) { + token.set(objectMapper.readTree(response.body()).get("token").asText().trim()) + } else { + throw GradleException(response.body().toString()) + } + } + } + + open class GetDockerHubTagsEligibleForDeletion : DefaultTask() { + + data class ListTagsResult(val name: String, val tag_status: String) + data class ListTagsResponse(val count: Int, val next: String?, val results: List) + + @Input + val repository = project.objects.property().convention(project.dockerHubRepository) + + @Input + val image = project.objects.property() + + @Input + val protectedTags = project.objects.setProperty() + + @Input + val removeInactiveOnly = project.objects.property().convention(project.removeInactiveOnly) + + @Input + val token = project.objects.property() + + // Explicitly not stored to a file as we do not want to leak/persist this value anywhere. + @OutputFile + val tagsToRemoveFile = + project.objects.fileProperty().convention(project.layout.buildDirectory.file("remove.tags.txt")) + + @get:Internal + val tagsToRemove: Set + get() = tagsToRemoveFile.get().asFile.readText().lines().toSet() + + init { + // Always re-run. + outputs.upToDateWhen { false } + } + + @TaskAction + fun exec() { + val client = HttpClient.newBuilder().build() + val tags = mutableSetOf() + var url = + "https://hub.docker.com/v2/namespaces/${repository.get()}/repositories/${image.get()}/tags?page_size=100" + do { + val request = HttpRequest.newBuilder() + .header("Content-Type", "application/json") + .header("Authorization", "JWT ${token.get()}") + .uri(URI.create(url)) + .build() + + val response = client.send(request, HttpResponse.BodyHandlers.ofString()) + val objectMapper = ObjectMapper(JsonFactory()) + .registerModule(KotlinModule.Builder().build()) + .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + + val jsonResponse = objectMapper.readValue(response.body(), ListTagsResponse::class.java)!! + + var results = jsonResponse.results.filterNot { + protectedTags.get().contains(it.name) + } // Ignore protected tags && active tags. + + if (removeInactiveOnly.get()) { // Ignore "active" tags. + results = results.filter { it.tag_status == "inactive" } + } + tags.addAll(results.map { it.name }) + + url = jsonResponse.next ?: "" + } while (jsonResponse.next != null) + + tagsToRemoveFile.get().asFile.writeText(tags.joinToString("\n")) + } + } + + interface DeleteTagParameters : WorkParameters { + val repository: Property + val image: Property + val tag: Property + val token: Property + } + + abstract class DeleteTagsAction : WorkAction { + override fun execute() { + val request = HttpRequest.newBuilder() + .header("Content-Type", "application/json") + .header("Authorization", "JWT ${parameters.token.get()}") + .DELETE() + .uri(URI.create("https://hub.docker.com/v2/repositories/${parameters.repository.get()}/${parameters.image.get()}/tags/${parameters.tag.get()}")) + .build() + HttpClient.newBuilder().build().send(request, HttpResponse.BodyHandlers.ofString()) + } + } + + + open class DeleteEligibleTags @Inject constructor(private val workerExecutor: WorkerExecutor) : DefaultTask() { + + @Input + val repository = project.objects.property().convention(project.dockerHubRepository) + + @Input + val image = project.objects.property() + + @Input + val tags = project.objects.setProperty() + + @Input + val token = project.objects.property() + + @TaskAction + fun exec() { + val workQueue: WorkQueue = workerExecutor.noIsolation() + tags.get().forEach { + workQueue.submit(DeleteTagsAction::class.java) { + image.set(this@DeleteEligibleTags.image.get()) + repository.set(this@DeleteEligibleTags.repository.get()) + tag.set(it) + token.set(this@DeleteEligibleTags.token.get()) + } + } + } + + } + + override fun apply(pluginProject: Project): Unit = pluginProject.run { + apply() + + val getProtectedDockerHubTags by tasks.registering(ProtectedDockerHubTags::class) { + group = "Isle DockerHub" + description = "Gets the tags which should not be removed by DockerHub cleanup inactive tags task." + images.set(allprojects.filter { it.isDockerProject }.map { it.name }) + } + + val getDockerHubToken by tasks.registering(GetDockerHubAuthenticationToken::class) { + group = "Isle DockerHub" + description = "Gets the login token required for interacting with DockerHub Rest API." + } + + allprojects { + if (isDockerProject) { + val getDockerHubTagsEligibleForDeletion by tasks.registering(GetDockerHubTagsEligibleForDeletion::class) { + group = "Isle DockerHub" + description = + "Gets the tags eligible for removal from DockerHub 'islandora/${project.name}' Repository." + image.set(project.name) + protectedTags.set(getProtectedDockerHubTags.map { it.protectedTags }) + token.set(getDockerHubToken.map { it.token.get() }) + } + + tasks.register("deleteEligibleDockerHubTags") { + group = "Isle DockerHub" + description = "Delete eligible tags from DockerHub 'islandora/${project.name}' Repository." + image.set(project.name) + tags.set(getDockerHubTagsEligibleForDeletion.map { it.tagsToRemove }) + token.set(getDockerHubToken.map { it.token.get() }) + } + } + } + + // Cache repository. + val getDockerHubTagsEligibleForDeletion by tasks.registering(GetDockerHubTagsEligibleForDeletion::class) { + group = "Isle DockerHub" + description = "Gets the tags eligible for removal from DockerHub 'islandora/cache' Repository." + image.set("cache") + protectedTags.set(getProtectedDockerHubTags.map { it.protectedTags }) + token.set(getDockerHubToken.map { it.token.get() }) + } + + tasks.register("deleteEligibleDockerHubTags") { + group = "Isle DockerHub" + description = "Delete eligible tags from DockerHub 'islandora/cache' Repository." + image.set("cache") + tags.set(getDockerHubTagsEligibleForDeletion.map { it.tagsToRemove }) + token.set(getDockerHubToken.map { it.token.get() }) + } + } +} diff --git a/buildSrc/src/main/kotlin/plugins/IslePlugin.kt b/buildSrc/src/main/kotlin/plugins/IslePlugin.kt new file mode 100644 index 00000000..ba51d92f --- /dev/null +++ b/buildSrc/src/main/kotlin/plugins/IslePlugin.kt @@ -0,0 +1,46 @@ +package plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.provider.Property +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.property +import org.gradle.kotlin.dsl.provideDelegate +import org.gradle.kotlin.dsl.withGroovyBuilder + +@Suppress("unused") +class IslePlugin : Plugin { + + companion object { + // Check if the project should have docker related tasks. + val Project.isDockerProject: Boolean + get() = projectDir.resolve("Dockerfile").exists() + } + + override fun apply(pluginProject: Project): Unit = pluginProject.run { + apply() + apply() + apply() + apply() + + extensions.findByName("buildScan")?.withGroovyBuilder { + setProperty("termsOfServiceUrl", "https://gradle.com/terms-of-service") + setProperty("termsOfServiceAgree", "yes") + } + + // Make all build directories relative to the root, only supports projects up to a depth of one for now. + subprojects { + buildDir = rootProject.buildDir.resolve(projectDir.relativeTo(rootDir)) + layout.buildDirectory.set(buildDir) + } + } +} + +inline fun Project.memoizedProperty(crossinline function: () -> T): Property { + val property = objects.property() + val value: T by lazy { function() } + property.set(value) + property.disallowChanges() + property.finalizeValueOnRead() + return property +} diff --git a/buildSrc/src/main/kotlin/plugins/ReportsPlugin.kt b/buildSrc/src/main/kotlin/plugins/ReportsPlugin.kt new file mode 100644 index 00000000..3486d825 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugins/ReportsPlugin.kt @@ -0,0 +1,277 @@ +package plugins + +import org.apache.commons.io.output.NullOutputStream +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.file.RegularFile +import org.gradle.api.tasks.* +import org.gradle.kotlin.dsl.* +import plugins.IslePlugin.Companion.isDockerProject +import plugins.SharedPropertiesPlugin.Companion.execCaptureOutput +import plugins.SharedPropertiesPlugin.Companion.isleRepository +import plugins.SharedPropertiesPlugin.Companion.isleTag +import tasks.DockerPull + +// Generate reports via Syft and Grype. +@Suppress("unused") +class ReportsPlugin : Plugin { + + companion object { + // Configuration for grype. + val Project.grypeConfig: RegularFile? + get() = (properties.getOrDefault("isle.grype.config", "") as String).let { path: String -> + if (path.isNotBlank()) { + project.layout.projectDirectory.file(path).let { file -> + if (file.asFile.exists()) + file + else + null + } + } + null + } + + // Only reports issues that have fixes. + val Project.grypeOnlyFixed: Boolean + get() = (properties.getOrDefault("isle.grype.only-fixed", "false") as String).toBoolean() + + // Triggers build to fail if security vulnerability is discovered. + // If unspecified the build will continue regardless. + // Possible values: negligible, low, medium, high, critical. + // Only reports issues that have fixes. + val Project.grypeFailOnSeverity: String + get() = properties.getOrDefault("isle.grype.fail-on-severity", "") as String + + // The format of reports generated by grype. + // Possible values: table, cyclonedx, json, template. + val Project.grypeFormat: String + get() = properties.getOrDefault("isle.grype.format", "table") as String + } + + // Updates Grype Database. + @CacheableTask + open class UpdateGrypeDB : DefaultTask() { + @Input + val image = project.objects.property() + + @OutputDirectory + val database = project.objects.directoryProperty().convention(project.layout.buildDirectory.dir("grype")) + + @Internal + val uid = project.objects.property() + + @Internal + val gid = project.objects.property() + + private val baseArguments: List + get() = listOf( + "docker", + "run", + "--rm", + "-u", "${uid.get()}:${gid.get()}", + "-e", "GRYPE_DB_CACHE_DIR=/cache", + "-v", "${database.get().asFile.absolutePath}:/cache", + "-v", "/tmp:/tmp", + image.get(), + ) + + private fun upToDate() = project.exec { + commandLine( + baseArguments + listOf( + "db", + "status" + ) + ) + standardOutput = NullOutputStream() + errorOutput = NullOutputStream() + isIgnoreExitValue = true + }.exitValue == 0 + + init { + outputs.upToDateWhen { + // If the database is missing the task will re-run or be restored from cache. + // If the database is present check to make sure it is up-to-date, if not run again. + database.get().asFile.exists() && upToDate() + } + uid.set(project.execCaptureOutput(listOf("id", "-u"), "Failed to get UID").toInt()) + gid.set(project.execCaptureOutput(listOf("id", "-g"), "Failed to get GID").toInt()) + } + + @TaskAction + fun pull() { + project.exec { + commandLine( + baseArguments + listOf( + "db", + "update" + ) + ) + } + } + } + + + // Wrapper around a call to `syft`, please refer to the documentation for more information: + // https://github.com/anchore/syft + @CacheableTask + open class Syft : DefaultTask() { + + // anchore/syft image. + @Input + val syft = project.objects.property() + + // The image to process (assumed to exist locally). + @Input + val image = project.objects.property() + + // A json file representing the generated Software Bill of Materials. + @OutputFile + val sbom = project.objects.fileProperty().convention(project.layout.buildDirectory.file("sbom.json")) + + @TaskAction + fun exec() { + sbom.get().asFile.outputStream().use { output -> + project.exec { + standardOutput = output + commandLine = listOf( + "docker", "container", "run", "--rm", + "-v", "/var/run/docker.sock:/var/run/docker.sock", + syft.get(), + "-o", "json", + image.get() + ) + } + } + } + } + + // Wrapper around a call to `syft`, please refer to the documentation for more information: + // https://github.com/anchore/syft + @CacheableTask + open class Grype : DefaultTask() { + // anchore/grype image. + @Input + val grype = project.objects.property() + + // anchore/grype image. + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) + val database = project.objects.directoryProperty() + + // A json file representing the generated Software Bill of Materials. + @InputFile + @PathSensitive(PathSensitivity.RELATIVE) + val sbom = project.objects.fileProperty() + + @Input + val format = project.objects.property().convention("table") + + @Input + @Optional + val failOn = project.objects.property() + + @InputFile + @Optional + @PathSensitive(PathSensitivity.RELATIVE) + val config = project.objects.fileProperty() + + @Input + val onlyFixed = project.objects.property().convention(false) + + @OutputFile + val report = project.objects.fileProperty().convention(format.flatMap { + val dir = project.layout.buildDirectory + val name = "${project.name}-grype" + when (it) { + "json" -> dir.file("${name}.json") + "table" -> dir.file("${name}.md") + "cyclonedx" -> dir.file("${name}.xml") + else -> dir.file("${name}.txt") + } + }) + + @TaskAction + fun exec() { + sbom.get().asFile.inputStream().use { input -> + report.get().asFile.outputStream().use { output -> + // Arguments to docker. + val command = mutableListOf( + "docker", "container", "run", "--rm", "-i", + "-e", "GRYPE_DB_CACHE_DIR=/cache", + "-e", "GRYPE_DB_AUTO_UPDATE=false", + "-v", "${database.get().asFile.absolutePath}:/cache", + ) + if (config.isPresent) { + command.addAll(listOf("-v", "${config.get().asFile.absolutePath}:/grype.yaml")) + } + // Docker image + command.add(grype.get()) + if (config.isPresent) { + command.addAll(listOf("--config", "/grype.yaml")) + } + // Arguments to grype. + if (failOn.get().isNotBlank()) { + command.addAll(listOf("--fail-on", failOn.get())) + } + if (onlyFixed.get()) { + command.add("--only-fixed") + } + command.addAll(listOf("-o", format.get())) + project.exec { + standardInput = input + standardOutput = output + commandLine = command + } + } + } + } + } + + override fun apply(pluginProject: Project): Unit = pluginProject.run { + apply() + + val pullSyft by tasks.registering(DockerPull::class) { + group = "Isle Reports" + description = "Pull anchore/syft docker image" + image.set("anchore/syft") + } + + val pullGrype by tasks.registering(DockerPull::class) { + group = "Isle Reports" + description = "Pull anchore/grype docker image" + image.set("anchore/grype") + } + + val updateGrypeDB by tasks.registering(UpdateGrypeDB::class) { + group = "Isle Reports" + description = "Update the Grype Database" + image.set(pullGrype.map { it.digestFile.get().asFile.readText().trim() }) + } + + allprojects { + // Auto-apply plugins to relevant projects. + if (isDockerProject) { + val syft by tasks.registering(Syft::class) { + group = "Isle Reports" + description = "Generate a software bill of material with Syft" + syft.set(pullSyft.map { it.digest }) + image.set((properties.getOrDefault("isle.${project.name}.digest", "") as String).ifEmpty { "${project.isleRepository}/${project.name}:${project.isleTag}" }) + } + + tasks.register("grype") { + group = "Isle Reports" + description = "Process the software bill of material with Grype" + grype.set(pullGrype.map { it.digest }) + database.set(updateGrypeDB.flatMap { it.database }) + config.set(grypeConfig) + failOn.set(grypeFailOnSeverity) + format.set(grypeFormat) + onlyFixed.set(grypeOnlyFixed) + sbom.set(syft.flatMap { it.sbom }) + dependsOn(":updateGrypeDB") + } + } + } + } +} diff --git a/buildSrc/src/main/kotlin/plugins/SharedPropertiesPlugin.kt b/buildSrc/src/main/kotlin/plugins/SharedPropertiesPlugin.kt new file mode 100644 index 00000000..4f840c01 --- /dev/null +++ b/buildSrc/src/main/kotlin/plugins/SharedPropertiesPlugin.kt @@ -0,0 +1,84 @@ +package plugins + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.extra +import java.io.ByteArrayOutputStream + +// Calculate once, share everywhere, configuration properties. +// Applied to the root project. +// Should be included before all other plugins. +@Suppress("unused") +class SharedPropertiesPlugin : Plugin { + + companion object { + // Capture stdout from running a command. + fun Project.execCaptureOutput(command: List, message: String) = ByteArrayOutputStream().use { output -> + ByteArrayOutputStream().use { error -> + val result = this.exec { + standardOutput = output + errorOutput = error + commandLine = command + } + error.toString().let { + if (it.isNotBlank()) { + logger.info(it) + } + } + if (result.exitValue != 0) throw RuntimeException(message) + output.toString() + } + }.trim() + + val Project.branch: String + get() = rootProject.extra["git.branch"] as String + + val Project.commit: String + get() = rootProject.extra["git.commit"] as String + + val Project.tag: String + get() = rootProject.extra["git.tag"] as String + + val Project.isLatestTag: Boolean + get() = rootProject.extra["git.latest"] as Boolean + + val Project.isleRepository: String + get() = properties.getOrDefault("isle.repository", "islandora") as String + + val Project.isleTag: String + get() = properties.getOrDefault("isle.tag", "local") as String + + fun String.normalizeDockerTag() = this.replace("""[^a-zA-Z0-9._-]""".toRegex(), "-") + } + + override fun apply(pluginProject: Project): Unit = pluginProject.run { + rootProject.extra["git.branch"] = execCaptureOutput( + listOf("git", "rev-parse", "--abbrev-ref", "HEAD"), + "Failed to get branch." + ).normalizeDockerTag() + + rootProject.extra["git.commit"] = + execCaptureOutput(listOf("git", "rev-parse", "HEAD"), "Failed to get commit hash.") + + rootProject.extra["git.tag"] = try { + execCaptureOutput( + listOf("git", "describe", "--exact-match", "--tags", "HEAD"), + "HEAD is not a tag." + ) + } catch (e: Exception) { + "" + } + + // Latest is true if HEAD is a tag and that tag has the highest semantic value. + // Exclude alpha, betas, etc + rootProject.extra["git.latest"] = execCaptureOutput( + listOf("git", "tag", "-l", "*.*.*", "--sort=version:refname"), + "Could not get tags." + ).lines().last { + !it.contains("-") // Exclude alpha, betas, etc + } == tag + + rootProject.extra["git.sourceDateEpoch"] = + execCaptureOutput(listOf("git", "log", "-1", "--pretty=%ct"), "Failed to get the date of HEAD") + } +} diff --git a/buildSrc/src/main/kotlin/plugins/TestsPlugin.kt b/buildSrc/src/main/kotlin/plugins/TestsPlugin.kt new file mode 100644 index 00000000..2fa6888c --- /dev/null +++ b/buildSrc/src/main/kotlin/plugins/TestsPlugin.kt @@ -0,0 +1,337 @@ +package plugins + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory +import com.fasterxml.jackson.module.kotlin.KotlinModule +import com.fasterxml.jackson.module.kotlin.readValue +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.* +import org.gradle.kotlin.dsl.* +import plugins.IslePlugin.Companion.isDockerProject +import plugins.SharedPropertiesPlugin.Companion.isleRepository +import plugins.SharedPropertiesPlugin.Companion.isleTag +import java.io.BufferedReader +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.InputStreamReader +import java.time.Duration +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit + + +// Generate reports via Syft and Grype. +@Suppress("unused") +class TestsPlugin : Plugin { + + companion object { + // Check if the project should have docker related tasks. + val Project.isDockerComposeProject: Boolean + get() = projectDir.resolve("docker-compose.yml").exists() + + // Pushing may require logging in to the repository, if so these need to be populated. + // The local registry does not require credentials. + val Project.isleTestPull: Boolean + get() = (properties.getOrDefault("isle.test.pull", "false") as String).toBoolean() + } + + + open class DockerCompose : DefaultTask() { + data class DockerComposeFile(val services: Map) { + companion object { + fun deserialize(file: File): DockerComposeFile = + ObjectMapper(YAMLFactory()) + .registerModule(KotlinModule.Builder().build()) + .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .readValue(file) + } + } + + data class Service(val image: String) { + companion object { + @Suppress("RegExpRedundantEscape") + val regex = """\$\{(?[^:]+):-(?.+)\}""".toRegex() + } + + private fun variable() = regex + .matchEntire(image) + ?.groups + ?.get("variable") + ?.value + + fun env(image: String) = + variable() + ?.let { variable -> + variable to image + } + } + + @Internal + val baseArguments = listOf( + "docker", + "compose" + ) + + @Input + val environment = project.objects.mapProperty().convention(project.provider { + val images = project.rootProject.allprojects.filter { it.isDockerProject }.map { it.name } + images.associate { image -> + image.uppercase().replace("-", "_") to (project.properties.getOrDefault( + "isle.${image}.digest", + "" + ) as String).ifEmpty { "${project.isleRepository}/${image}:${project.isleTag}" } + } + }) + + @get:Internal + val dockerCompose by lazy { + DockerComposeFile.deserialize(project.file("docker-compose.yml")) + } + + // Any file might be referenced by the docker-compose.yml file / as a volume, etc. + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) + val context = project.objects.directoryProperty().convention(project.layout.projectDirectory) + } + + @CacheableTask + open class DockerComposeUp : DockerCompose() { + + companion object { + val pool: ExecutorService = Executors.newCachedThreadPool() + } + + @Input + val exitCodeConditions = project.objects.mapProperty>() + + @Input + val outputConditions = project.objects.mapProperty() + + // Capture the log output after exit (sometimes has more text). + @OutputDirectory + val logs = project.objects.directoryProperty().convention(project.layout.buildDirectory) + + init { + // By default, limit max execution time to 5 minutes. + timeout.convention(Duration.ofMinutes(5)) + + // Expect each container exits 0 by default. + exitCodeConditions.putAll(dockerCompose.services.mapValues { setOf(0) }) + } + + // Gets the identifiers of all the services created by the docker compose file. + private val containers by lazy { + ByteArrayOutputStream().use { output -> + project.exec { + workingDir(project.projectDir) + commandLine(baseArguments + listOf("ps", "-aq")) + standardOutput = output + } + output + .toString() + .lines() + .filter { it.isNotBlank() } + } + } + + // Performs an `docker inspect` on all the services created by the docker compose file. + // Builds a map of service names paired with their exit codes. + @get:Internal + protected val exitCodes by lazy { + containers.associate { container -> + ByteArrayOutputStream().use { output -> + project.exec { + workingDir(project.projectDir) + commandLine("docker", "inspect", container) + standardOutput = output + } + output.toString() + }.let { + val node: JsonNode = ObjectMapper().readTree(it) + val service = + node.get(0)!!.get("Config")!!.get("Labels")!!.get("com.docker.compose.service")!!.asText()!! + val exitCode = node.get(0)!!.get("State")!!.get("ExitCode")!!.asInt() + Pair(service, exitCode) + } + } + } + + // Helper for writing tests which need to look for specific exit codes. + fun expectOutput(service: String, output: String) { + outputConditions.put(service, output) + } + + // Helper for writing tests which need to look for specific exit codes. + fun expectExitCode(service: String, exitCode: Int) { + val map = exitCodeConditions.get().toMutableMap() + map[service] = setOf(exitCode) + exitCodeConditions.set(map) + } + + // Helper for writing tests which need to look for specific exit codes. + fun expectExitCodes(service: String, vararg exitCodes: Int) { + val map = exitCodeConditions.get().toMutableMap() + map[service] = exitCodes.toSet() + exitCodeConditions.set(map) + } + + // Monitor output of the given service. + private fun monitorService(service: String, output: String): Triple { + logger.info("""Looking for "$output" in $service logs""") + val reader = CompletableFuture.supplyAsync({ + val start = System.nanoTime() + while ((System.nanoTime() - start) <= timeout.get().toNanos()) { + ByteArrayOutputStream().use { outputStream -> + project.exec { + workingDir = project.projectDir + commandLine = baseArguments + listOf("logs", service) + standardOutput = outputStream + } + output.lines() + }.forEach { line -> + if (line.contains(output)) { + logger.info("""Found "$output" in $service logs""") + return@supplyAsync Triple(service, output, true) + } + } + } + logger.info("""Missing "$output" from $service logs""") + return@supplyAsync Triple(service, output, false) + }, pool) + return reader.get() + } + + @TaskAction + fun up() { + val up = CompletableFuture.supplyAsync( + { + val process = ProcessBuilder().run { + directory(project.projectDir) + command(baseArguments + listOf("up", "--abort-on-container-exit")) + redirectOutput(logs.get().asFile.resolve("up.log")) + redirectErrorStream(true) + environment().putAll(this@DockerComposeUp.environment.get()) + start() + } + if (!process.waitFor(timeout.get().toMillis(), TimeUnit.MILLISECONDS)) { + process.destroyForcibly() + } + process.exitValue() + }, pool + ) + + // Used to fail the task if any condition was not met. + var failedConditions = false + + if (outputConditions.get().isNotEmpty()) { + Thread.sleep(5000) + val logMonitors = outputConditions.get().map { (service, output) -> + CompletableFuture.supplyAsync({ + monitorService(service, output) + }, pool) + }.toTypedArray() + // Will block until found, or timeout. + CompletableFuture.allOf(*logMonitors).join() + // Exit ignoring the exit code for docker-compose as we look at each container instead. + up.complete(0) + // Check for any monitors that failed to find their expected output. + failedConditions = logMonitors.any { !it.get().third } + } + up.join() // Either ended of its own accord or output conditions have all been satisfied. + // Wait for all containers to come down before we check their exit codes. + project.exec { + workingDir = project.projectDir + commandLine = baseArguments + listOf("stop") + } + exitCodes.forEach { (service, _) -> + val process = ProcessBuilder().run { + directory(project.projectDir) + command(baseArguments + listOf("logs", service)) + redirectOutput(logs.get().asFile.resolve("${service}.log")) + redirectErrorStream(true) + start() + }.waitFor() + } + exitCodeConditions.get().forEach { (service, expectedExitCodes) -> + val exitCode = exitCodes[service] + logger.info("Service ($service) exited with: $exitCode, expected ${expectedExitCodes.joinToString(", ")}") + if (!expectedExitCodes.contains(exitCode)) { + failedConditions = true + } + } + if (failedConditions) { + logger.info("Failed Conditions") + throw GradleException("Failed conditions") + } + } + } + + open class DockerComposeDown : DockerCompose() { + + @TaskAction + fun down() { + project.exec { + workingDir(project.projectDir) + commandLine(baseArguments + listOf("down", "-v")) + } + } + } + + override fun apply(pluginProject: Project): Unit = pluginProject.run { + apply() + + allprojects { + // Auto-apply plugins to relevant projects in the "tests" folder of docker projects. + if (isDockerProject) { + subprojects { + if (isDockerComposeProject) { + val cleanUpBefore by tasks.registering(DockerComposeDown::class) { + group = "Isle Tests" + description = "Clean up resources before running test (if interrupted externally, etc)" + } + + // Placeholder which can be overridden in tests. + val setUp by tasks.registering(DockerCompose::class) { + group = "Isle Tests" + description = "Prepare to run test" + dependsOn(cleanUpBefore) + } + + val cleanUpAfter by tasks.registering(DockerComposeDown::class) { + group = "Isle Tests" + description = "Clean up resources after running test" + } + + tasks.register("test") { + group = "Isle Tests" + description = "Perform test" + dependsOn(setUp) + //finalizedBy(cleanUpAfter) + doFirst { + if (project.isleTestPull) { + project.exec { + workingDir = project.projectDir + commandLine = baseArguments + listOf("pull", "--ignore-pull-failures") + environment = this@register.environment.get() as Map + } + } + } + } + } + } + tasks.register("test") { + description = "Test docker image(s)" + dependsOn(project.subprojects.mapNotNull { it.tasks.matching { task -> task.name == "test" } }) + } + } + } + } +} diff --git a/buildSrc/src/main/kotlin/tasks/DockerPull.kt b/buildSrc/src/main/kotlin/tasks/DockerPull.kt new file mode 100644 index 00000000..7d63ffe7 --- /dev/null +++ b/buildSrc/src/main/kotlin/tasks/DockerPull.kt @@ -0,0 +1,67 @@ +package tasks + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.commons.io.output.ByteArrayOutputStream +import org.apache.commons.io.output.NullOutputStream +import org.gradle.api.DefaultTask +import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.property + +// Pulls down a docker image if not already present. +// https://docs.docker.com/engine/reference/commandline/pull +open class DockerPull : DefaultTask() { + @Input + val image = project.objects.property() + + @OutputFile + val digestFile = project.objects.fileProperty().convention(image.flatMap { + project.layout.buildDirectory.file(it.replace(Regex("""[:/]"""), ".") + ".digest") + }) + + @get:Internal + val digest: String + get() = digestFile.get().asFile.readText().trim() + + private fun exists() = digestFile.get().asFile.let { file -> + file.exists() && file.readText().trim().let { digest -> + project.exec { + commandLine("docker", "inspect", digest) + standardOutput = NullOutputStream() + errorOutput = NullOutputStream() + isIgnoreExitValue = true + }.exitValue == 0 + } + } + + init { + logging.captureStandardOutput(LogLevel.INFO) + logging.captureStandardError(LogLevel.INFO) + + outputs.upToDateWhen { + exists() + } + } + + @TaskAction + fun pull() { + project.exec { + commandLine("docker", "pull", image.get()) + } + ByteArrayOutputStream().use { output -> + project.exec { + commandLine("docker", "inspect", image.get()) + standardOutput = output + } + output.toString() + }.let { output -> + val node: JsonNode = ObjectMapper().readTree(output) + val content = node.first().get("RepoDigests").first().asText().trim() + digestFile.get().asFile.writeText(content) + } + } +} diff --git a/cantaloupe/.dockerignore b/cantaloupe/.dockerignore index b43bf86b..7c52df64 100644 --- a/cantaloupe/.dockerignore +++ b/cantaloupe/.dockerignore @@ -1 +1,5 @@ +build.gradle.kts +README.dockerhub.md README.md +tests +tests/**/* diff --git a/cantaloupe/Dockerfile b/cantaloupe/Dockerfile index 5608255d..2d69baff 100644 --- a/cantaloupe/Dockerfile +++ b/cantaloupe/Dockerfile @@ -1,28 +1,266 @@ -# syntax=docker/dockerfile:experimental -FROM local/tomcat:latest +# syntax=docker/dockerfile:1.5.1 +FROM java + +ARG TARGETARCH +ARG CANTALOUPE_VERSION="5.0.5" +ARG CANTALOUPE_FILE="cantaloupe-${CANTALOUPE_VERSION}.zip" +ARG CANTALOUPE_URL="https://github.com/cantaloupe-project/cantaloupe/releases/download/v${CANTALOUPE_VERSION}/${CANTALOUPE_FILE}" +ARG CANTALOUPE_SHA256="f8494ff940841e7b897b22d680e4bf87baf8fb1d6ced87117538dd5abaa1fc34" + +EXPOSE 8182 + +WORKDIR /opt/cantaloupe + +# Note: Kakadu is not fully free and cannot be used for commercial purposes, +# without purchasing the appropriate license. +# As such the binaries are also not included here, although this image can be extended +# to include them. If you do so be aware you do not violate the terms of their licence. +# +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=cantaloupe-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${CANTALOUPE_URL}" \ + --sha256 "${CANTALOUPE_SHA256}" \ + --dest "/opt/cantaloupe" \ + --strip \ + deps \ + && \ + mv "/opt/cantaloupe/cantaloupe-${CANTALOUPE_VERSION}.jar" "/opt/cantaloupe/cantaloupe.jar" && \ + cleanup.sh # Opted for OpenJPG over Kakadu but that could be changed. -# For reference see: https://cantaloupe-project.github.io/manual/3.3/processors.html -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh \ - imagemagick \ +# For reference see: https://cantaloupe-project.github.io/manual/5.0/processors.html +# +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=cantaloupe-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ ffmpeg \ - openjpeg-tools + openjpeg-tools \ + && \ + create-service-user.sh --name cantaloupe --group jwt /data /opt/cantaloupe/logs && \ + cleanup.sh -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - CANTALOUPE_VERSION="4.1.5" && \ - CANTALOUPE_FILE="cantaloupe-${CANTALOUPE_VERSION}.zip" && \ - CANTALOUPE_URL="https://github.com/medusa-project/cantaloupe/releases/download/v${CANTALOUPE_VERSION}/${CANTALOUPE_FILE}" && \ - CANTALOUPE_SHA256="a117061727f1de1c0f514659ec537c080a7f540199643244d1c9cbb50d73027d" && \ - download.sh --url "${CANTALOUPE_URL}" --sha256 "${CANTALOUPE_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - unzip "${DOWNLOAD_CACHE_DIRECTORY}/${CANTALOUPE_FILE}" -d /tmp && \ - CANTALOUPE_UNPACKED="${CANTALOUPE_FILE%.zip}" && \ - install-war-into-tomcat.sh --name "cantaloupe" --file "/tmp/${CANTALOUPE_UNPACKED}/${CANTALOUPE_UNPACKED}.war" && \ - rm -fr "/tmp/${CANTALOUPE_UNPACKED}" && \ - mkdir /data && \ - chown tomcat:tomcat /data && \ - chown -R tomcat:tomcat /opt/tomcat +ENV \ + CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_KEY= \ + CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_NAME= \ + CANTALOUPE_AZURESTORAGECACHE_CONTAINER_NAME= \ + CANTALOUPE_AZURESTORAGECACHE_OBJECT_KEY_PREFIX= \ + CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_KEY= \ + CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_NAME= \ + CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CACHE_ENABLED="true" \ + CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CACHE_MAX_SIZE="5M" \ + CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CHUNK_SIZE="512K" \ + CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_ENABLED="true" \ + CANTALOUPE_AZURESTORAGESOURCE_CONTAINER_NAME= \ + CANTALOUPE_AZURESTORAGESOURCE_LOOKUP_STRATEGY="BasicLookupStrategy" \ + CANTALOUPE_BASE_URI= \ + CANTALOUPE_CACHE_CLIENT_ENABLED="true" \ + CANTALOUPE_CACHE_CLIENT_MAX_AGE="2592000" \ + CANTALOUPE_CACHE_CLIENT_MUST_REVALIDATE="false" \ + CANTALOUPE_CACHE_CLIENT_NO_CACHE="false" \ + CANTALOUPE_CACHE_CLIENT_NO_STORE="false" \ + CANTALOUPE_CACHE_CLIENT_NO_TRANSFORM="true" \ + CANTALOUPE_CACHE_CLIENT_PRIVATE="false" \ + CANTALOUPE_CACHE_CLIENT_PROXY_REVALIDATE="false" \ + CANTALOUPE_CACHE_CLIENT_PUBLIC="true" \ + CANTALOUPE_CACHE_CLIENT_SHARED_MAX_AGE= \ + CANTALOUPE_CACHE_SERVER_DERIVATIVE_ENABLED="false" \ + CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS="2592000" \ + CANTALOUPE_CACHE_SERVER_DERIVATIVE= \ + CANTALOUPE_CACHE_SERVER_INFO_ENABLED="true" \ + CANTALOUPE_CACHE_SERVER_PURGE_MISSING="false" \ + CANTALOUPE_CACHE_SERVER_RESOLVE_FIRST="false" \ + CANTALOUPE_CACHE_SERVER_SOURCE_TTL_SECONDS="2592000" \ + CANTALOUPE_CACHE_SERVER_SOURCE="FilesystemCache" \ + CANTALOUPE_CACHE_SERVER_WORKER_ENABLED="false" \ + CANTALOUPE_CACHE_SERVER_WORKER_INTERVAL="86400" \ + CANTALOUPE_DELEGATE_SCRIPT_ENABLED="false" \ + CANTALOUPE_DELEGATE_SCRIPT_PATHNAME="delegates.rb" \ + CANTALOUPE_ENDPOINT_ADMIN_ENABLED="false" \ + CANTALOUPE_ENDPOINT_ADMIN_SECRET= \ + CANTALOUPE_ENDPOINT_ADMIN_USERNAME="admin" \ + CANTALOUPE_ENDPOINT_API_ENABLED="false" \ + CANTALOUPE_ENDPOINT_API_SECRET= \ + CANTALOUPE_ENDPOINT_API_USERNAME= \ + CANTALOUPE_ENDPOINT_HEALTH_DEPENDENCY_CHECK="false" \ + CANTALOUPE_ENDPOINT_IIIF_1_ENABLED="false" \ + CANTALOUPE_ENDPOINT_IIIF_2_ENABLED="true" \ + CANTALOUPE_ENDPOINT_IIIF_3_ENABLED="true" \ + CANTALOUPE_ENDPOINT_IIIF_MIN_SIZE="64" \ + CANTALOUPE_ENDPOINT_IIIF_MIN_TILE_SIZE="512" \ + CANTALOUPE_ENDPOINT_IIIF_RESTRICT_TO_SIZES="false" \ + CANTALOUPE_FFMPEGPROCESSOR_PATH_TO_BINARIES= \ + CANTALOUPE_FILESYSTEMCACHE_DIR_DEPTH="3" \ + CANTALOUPE_FILESYSTEMCACHE_DIR_NAME_LENGTH="2" \ + CANTALOUPE_FILESYSTEMCACHE_PATHNAME="/data" \ + CANTALOUPE_FILESYSTEMSOURCE_BASICLOOKUPSTRATEGY_PATH_PREFIX="/var/www/drupal/web/" \ + CANTALOUPE_FILESYSTEMSOURCE_BASICLOOKUPSTRATEGY_PATH_SUFFIX= \ + CANTALOUPE_FILESYSTEMSOURCE_LOOKUP_STRATEGY="BasicLookupStrategy" \ + CANTALOUPE_GROKPROCESSOR_PATH_TO_BINARIES= \ + CANTALOUPE_HEAPCACHE_PERSIST_FILESYSTEM_PATHNAME="/data/heap.cache" \ + CANTALOUPE_HEAPCACHE_PERSIST="false" \ + CANTALOUPE_HEAPCACHE_TARGET_SIZE="2G" \ + CANTALOUPE_HTTP_ACCEPT_QUEUE_LIMIT= \ + CANTALOUPE_HTTP_ENABLED="true" \ + CANTALOUPE_HTTP_HOST="0.0.0.0" \ + CANTALOUPE_HTTP_MAX_THREADS= \ + CANTALOUPE_HTTP_MIN_THREADS= \ + CANTALOUPE_HTTP_PORT="8182" \ + CANTALOUPE_HTTPS_ENABLED="false" \ + CANTALOUPE_HTTPS_HOST="0.0.0.0" \ + CANTALOUPE_HTTPS_KEY_PASSWORD="password" \ + CANTALOUPE_HTTPS_KEY_STORE_PASSWORD="password" \ + CANTALOUPE_HTTPS_KEY_STORE_PATH="/path/to/keystore.jks" \ + CANTALOUPE_HTTPS_KEY_STORE_TYPE="JKS" \ + CANTALOUPE_HTTPS_PORT="8183" \ + CANTALOUPE_HTTPSOURCE_ALLOW_INSECURE="false" \ + CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_AUTH_BASIC_SECRET= \ + CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_AUTH_BASIC_USERNAME= \ + CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_URL_PREFIX= \ + CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_URL_SUFFIX= \ + CANTALOUPE_HTTPSOURCE_CHUNKING_CACHE_ENABLED="true" \ + CANTALOUPE_HTTPSOURCE_CHUNKING_CACHE_MAX_SIZE="5M" \ + CANTALOUPE_HTTPSOURCE_CHUNKING_CHUNK_SIZE="512K" \ + CANTALOUPE_HTTPSOURCE_CHUNKING_ENABLED="true" \ + CANTALOUPE_HTTPSOURCE_LOOKUP_STRATEGY="BasicLookupStrategy" \ + CANTALOUPE_HTTPSOURCE_REQUEST_TIMEOUT= \ + CANTALOUPE_JDBCCACHE_CONNECTION_TIMEOUT="10" \ + CANTALOUPE_JDBCCACHE_DERIVATIVE_IMAGE_TABLE="derivative_cache" \ + CANTALOUPE_JDBCCACHE_INFO_TABLE="info_cache" \ + CANTALOUPE_JDBCCACHE_PASSWORD="password" \ + CANTALOUPE_JDBCCACHE_URL="jdbc:postgresql://database:5432/cantaloupe" \ + CANTALOUPE_JDBCCACHE_USER="admin" \ + CANTALOUPE_JDBCSOURCE_CONNECTION_TIMEOUT="10" \ + CANTALOUPE_JDBCSOURCE_PASSWORD="password" \ + CANTALOUPE_JDBCSOURCE_URL="jdbc:postgresql://database:5432/cantaloupe" \ + CANTALOUPE_JDBCSOURCE_USER="admin" \ + CANTALOUPE_LOG_ACCESS_CONSOLEAPPENDER_ENABLED="true" \ + CANTALOUPE_LOG_ACCESS_FILEAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_ACCESS_FILEAPPENDER_PATHNAME="/opt/cantaloupe/logs/cantaloupe.access.log" \ + CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_PATHNAME="/opt/cantaloupe/logs/cantaloupe.access.log" \ + CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_POLICY="TimeBasedRollingPolicy" \ + CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN="/opt/cantaloupe/logs/cantaloupe.access-%d{yyyy-MM-dd}.log" \ + CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY="30" \ + CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_FACILITY="LOCAL0" \ + CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_HOST= \ + CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_PORT="514" \ + CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_ENABLED="true" \ + CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_LOGSTASH_ENABLED="false" \ + CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_LOGSTASH_ENABLED="false" \ + CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_PATHNAME="/opt/cantaloupe/logs/cantaloupe.application.log" \ + CANTALOUPE_LOG_APPLICATION_LEVEL="debug" \ + CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_LOGSTASH_ENABLED="false" \ + CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_PATHNAME="/opt/cantaloupe/logs/cantaloupe.application.log" \ + CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_POLICY="TimeBasedRollingPolicy" \ + CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN="/opt/cantaloupe/logs/cantaloupe.application-%d{yyyy-MM-dd}.log" \ + CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY="30" \ + CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_FACILITY="LOCAL0" \ + CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_HOST= \ + CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_PORT="514" \ + CANTALOUPE_LOG_ERROR_FILEAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_ERROR_FILEAPPENDER_LOGSTASH_ENABLED="false" \ + CANTALOUPE_LOG_ERROR_FILEAPPENDER_PATHNAME="/opt/cantaloupe/logs/cantaloupe.error.log" \ + CANTALOUPE_LOG_ERROR_RESPONSES="false" \ + CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_ENABLED="false" \ + CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_LOGSTASH_ENABLED="false" \ + CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_PATHNAME="/opt/cantaloupe/logs/cantaloupe.error.log" \ + CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_POLICY="TimeBasedRollingPolicy" \ + CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN="/opt/cantaloupe/logs/cantaloupe.error-%d{yyyy-MM-dd}.log" \ + CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY="30" \ + CANTALOUPE_MAX_PIXELS="10000000" \ + CANTALOUPE_MAX_SCALE="1.0" \ + CANTALOUPE_META_IDENTIFIER_TRANSFORMER_STANDARDMETAIDENTIFIERTRANSFORMER_DELIMITER=";" \ + CANTALOUPE_META_IDENTIFIER_TRANSFORMER="StandardMetaIdentifierTransformer" \ + CANTALOUPE_OPENJPEGPROCESSOR_PATH_TO_BINARIES= \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_ENABLED="false" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_IMAGE="/path/to/overlay_png" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_INSET="10" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_HEIGHT_THRESHOLD="300" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_WIDTH_THRESHOLD="400" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_POSITION="bottom right" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_BACKGROUND_COLOR="rgba(0, 0, 0, 100)" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_COLOR="white" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_MIN_SIZE="18" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_SIZE="24" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_WEIGHT="1.0" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT="Helvetica" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_GLYPH_SPACING="0.02" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_COLOR="black" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_WIDTH="1" \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING="Copyright. All rights reserved." \ + CANTALOUPE_OVERLAYS_BASICSTRATEGY_TYPE="image" \ + CANTALOUPE_OVERLAYS_STRATEGY="BasicStrategy" \ + CANTALOUPE_PRINT_STACK_TRACE_ON_ERROR_PAGES="true" \ + CANTALOUPE_PROCESSOR_BACKGROUND_COLOR="white" \ + CANTALOUPE_PROCESSOR_DOWNSCALE_FILTER="bicubic" \ + CANTALOUPE_PROCESSOR_DOWNSCALE_LINEAR="false" \ + CANTALOUPE_PROCESSOR_DPI="150" \ + CANTALOUPE_PROCESSOR_FALLBACK_RETRIEVAL_STRATEGY="DownloadStrategy" \ + CANTALOUPE_PROCESSOR_IMAGEIO_BMP_READER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_GIF_READER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_GIF_WRITER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_JPG_READER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_JPG_WRITER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_PNG_READER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_PNG_WRITER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_TIF_READER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_TIF_WRITER= \ + CANTALOUPE_PROCESSOR_IMAGEIO_XPM_READER= \ + CANTALOUPE_PROCESSOR_JPG_PROGRESSIVE="true" \ + CANTALOUPE_PROCESSOR_JPG_QUALITY="80" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_AVI="FfmpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_BMP="Java2dProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_FALLBACK="Java2dProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_FLV="FfmpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_GIF="Java2dProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JP2="OpenJpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JPG="TurboJpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MOV="FfmpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MP4="FfmpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MPG="FfmpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_PDF="PDFBox" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_PNG="Java2dProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_TIF="Java2dProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_WEBM="FfmpegProcessor" \ + CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_XPM= \ + CANTALOUPE_PROCESSOR_PDF_MAX_MEMORY_BYTES="-1" \ + CANTALOUPE_PROCESSOR_PDF_SCRATCH_FILE_ENABLED="false" \ + CANTALOUPE_PROCESSOR_SELECTION_STRATEGY="AutomaticSelectionStrategy" \ + CANTALOUPE_PROCESSOR_SHARPEN="0" \ + CANTALOUPE_PROCESSOR_STREAM_RETRIEVAL_STRATEGY="StreamStrategy" \ + CANTALOUPE_PROCESSOR_TIF_COMPRESSION="LZW" \ + CANTALOUPE_PROCESSOR_UPSCALE_FILTER="bicubic" \ + CANTALOUPE_REDISCACHE_DATABASE="0" \ + CANTALOUPE_REDISCACHE_HOST="localhost" \ + CANTALOUPE_REDISCACHE_PASSWORD= \ + CANTALOUPE_REDISCACHE_PORT="6379" \ + CANTALOUPE_REDISCACHE_SSL="false" \ + CANTALOUPE_S3CACHE_ACCESS_KEY_ID= \ + CANTALOUPE_S3CACHE_BUCKET_NAME= \ + CANTALOUPE_S3CACHE_ENDPOINT= \ + CANTALOUPE_S3CACHE_OBJECT_KEY_PREFIX= \ + CANTALOUPE_S3CACHE_REGION= \ + CANTALOUPE_S3CACHE_SECRET_KEY= \ + CANTALOUPE_S3SOURCE_ACCESS_KEY_ID= \ + CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_BUCKET_NAME= \ + CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_PATH_PREFIX= \ + CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_PATH_SUFFIX= \ + CANTALOUPE_S3SOURCE_CHUNKING_CACHE_ENABLED="true" \ + CANTALOUPE_S3SOURCE_CHUNKING_CACHE_MAX_SIZE="5M" \ + CANTALOUPE_S3SOURCE_CHUNKING_CHUNK_SIZE="512K" \ + CANTALOUPE_S3SOURCE_CHUNKING_ENABLED="true" \ + CANTALOUPE_S3SOURCE_ENDPOINT= \ + CANTALOUPE_S3SOURCE_LOOKUP_STRATEGY="BasicLookupStrategy" \ + CANTALOUPE_S3SOURCE_REGION= \ + CANTALOUPE_S3SOURCE_SECRET_KEY= \ + CANTALOUPE_SLASH_SUBSTITUTE= \ + CANTALOUPE_SOURCE_DELEGATE="false" \ + CANTALOUPE_SOURCE_STATIC="HttpSource" \ + CANTALOUPE_TEMP_PATHNAME= -COPY rootfs / +COPY --link rootfs / diff --git a/cantaloupe/README.dockerhub.md b/cantaloupe/README.dockerhub.md new file mode 100644 index 00000000..79d00019 --- /dev/null +++ b/cantaloupe/README.dockerhub.md @@ -0,0 +1,35 @@ +# Cantaloupe + +Docker image for [Cantaloupe] version 5.0.5. + +Please refer to the [Cantaloupe Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Cantaloupe], and allow you +to view on . + +```bash +docker run --rm -ti -p 8182:8182 islandora/cantaloupe +``` + +## Dependencies + +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](../java/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Volumes + +| Path | Description | +| :---- | :------------------- | +| /data | [Cantaloupe Caching] | + +## Settings + +Please see the +[documentation](https://github.com/Islandora-Devops/isle-buildkit/tree/main/cantaloupe#settings) +in Github as the settings here exceed the file length supported by Docker Hub. + +[Cantaloupe Caching]: https://cantaloupe-project.github.io/manual/3.1/caching.html +[Cantaloupe Documentation]: https://cantaloupe-project.github.io/manual/3.1/getting-started.html +[Cantaloupe Logs]: https://cantaloupe-project.github.io/manual/3.1/logging.html +[Cantaloupe]: https://cantaloupe-project.github.io/ diff --git a/cantaloupe/README.md b/cantaloupe/README.md index 26b129f4..44aaae53 100644 --- a/cantaloupe/README.md +++ b/cantaloupe/README.md @@ -1,20 +1,20 @@ # Cantaloupe -Docker image for [Cantaloupe] version 3.3.1. +Docker image for [Cantaloupe] version 5.0.5. Please refer to the [Cantaloupe Documentation] for more in-depth information. As a quick example this will bring up an instance of [Cantaloupe], and allow you -to view on . +to view on . ```bash -docker run --rm -ti -p 80:80 islandora/cantaloupe +docker run --rm -ti -p 8182:8182 islandora/cantaloupe ``` ## Dependencies -Requires `islandora/tomcat` docker image to build. Please refer to the -[Tomcat Image README](../tomcat/README.md) for additional information including +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](../java/README.md) for additional information including additional settings, volumes, ports, etc. ## Volumes @@ -25,191 +25,229 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | -| :------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--------------------------------------------------------- | -| CANTALOUPE_HTTP_ENABLED | /cantaloupe/http/enabled | true | -| CANTALOUPE_HTTP_HOST | /cantaloupe/http/host | 0.0.0.0 | -| CANTALOUPE_HTTP_PORT | /cantaloupe/http/port | 8182 | -| CANTALOUPE_HTTPS_ENABLED | /cantaloupe/https/enabled | false | -| CANTALOUPE_HTTPS_HOST | /cantaloupe/https/host | 0.0.0.0 | -| CANTALOUPE_HTTPS_PORT | /cantaloupe/https/port | 8183 | -| CANTALOUPE_HTTPS_KEY_STORE_TYPE | /cantaloupe/https/key/store/type | JKS | -| CANTALOUPE_HTTPS_KEY_STORE_PASSWORD | /cantaloupe/https/key/store/password | password | -| CANTALOUPE_HTTPS_KEY_STORE_PATH | /cantaloupe/https/key/store/path | /path/to/keystore.jks | -| CANTALOUPE_HTTPS_KEY_PASSWORD | /cantaloupe/https/key/password | password | -| CANTALOUPE_AUTH_BASIC_ENABLED | /cantaloupe/auth/basic/enabled | false | -| CANTALOUPE_AUTH_BASIC_USERNAME | /cantaloupe/auth/basic/username | admin | -| CANTALOUPE_AUTH_BASIC_SECRET | /cantaloupe/auth/basic/secret | password | -| CANTALOUPE_ADMIN_ENABLED | /cantaloupe/admin/enabled | true | -| CANTALOUPE_ADMIN_PASSWORD | /cantaloupe/admin/password | password | -| CANTALOUPE_BASE_URI | /cantaloupe/base/uri | | -| CANTALOUPE_SLASH_SUBSTITUTE | /cantaloupe/slash/substitute | | -| CANTALOUPE_MAX_PIXELS | /cantaloupe/max/pixels | 400000000 | -| CANTALOUPE_PRINT_STACK_TRACE_ON_ERROR_PAGES | /cantaloupe/print/stack/trace/on/error/pages | true | -| CANTALOUPE_DELEGATE_SCRIPT_ENABLED | /cantaloupe/delegate/script/enabled | false | -| CANTALOUPE_DELEGATE_SCRIPT_PATHNAME | /cantaloupe/delegate/script/pathname | delegates.rb | -| CANTALOUPE_DELEGATE_SCRIPT_CACHE_ENABLED | /cantaloupe/delegate/script/cache/enabled | false | -| CANTALOUPE_ENDPOINT_IIIF_1_ENABLED | /cantaloupe/endpoint/iiif/1/enabled | true | -| CANTALOUPE_ENDPOINT_IIIF_2_ENABLED | /cantaloupe/endpoint/iiif/2/enabled | true | -| CANTALOUPE_ENDPOINT_IIIF_CONTENT_DISPOSITION | /cantaloupe/endpoint/iiif/content/disposition | inline | -| CANTALOUPE_ENDPOINT_IIIF_MIN_TILE_SIZE | /cantaloupe/endpoint/iiif/min/tile/size | 1024 | -| CANTALOUPE_ENDPOINT_IIIF_2_RESTRICT_TO_SIZES | /cantaloupe/endpoint/iiif/2/restrict/to/sizes | false | -| CANTALOUPE_ENDPOINT_API_ENABLED | /cantaloupe/endpoint/api/enabled | false | -| CANTALOUPE_ENDPOINT_API_USERNAME | /cantaloupe/endpoint/api/username | | -| CANTALOUPE_ENDPOINT_API_SECRET | /cantaloupe/endpoint/api/secret | | -| CANTALOUPE_RESOLVER_STATIC | /cantaloupe/resolver/static | HttpResolver | -| CANTALOUPE_RESOLVER_DELEGATE | /cantaloupe/resolver/delegate | false | -| CANTALOUPE_FILESYSTEMRESOLVER_LOOKUP_STRATEGY | /cantaloupe/filesystemresolver/lookup/strategy | BasicLookupStrategy | -| CANTALOUPE_FILESYSTEMRESOLVER_BASICLOOKUPSTRATEGY_PATH_PREFIX | /cantaloupe/filesystemresolver/basiclookupstrategy/path/prefix | /var/www/drupal/web/ | -| CANTALOUPE_FILESYSTEMRESOLVER_BASICLOOKUPSTRATEGY_PATH_SUFFIX | /cantaloupe/filesystemresolver/basiclookupstrategy/path/suffix | | -| CANTALOUPE_HTTPRESOLVER_LOOKUP_STRATEGY | /cantaloupe/httpresolver/lookup/strategy | BasicLookupStrategy | -| CANTALOUPE_HTTPRESOLVER_BASICLOOKUPSTRATEGY_URL_PREFIX | /cantaloupe/httpresolver/basiclookupstrategy/url/prefix | | -| CANTALOUPE_HTTPRESOLVER_BASICLOOKUPSTRATEGY_URL_SUFFIX | /cantaloupe/httpresolver/basiclookupstrategy/url/suffix | | -| CANTALOUPE_HTTPRESOLVER_AUTH_BASIC_USERNAME | /cantaloupe/httpresolver/auth/basic/username | | -| CANTALOUPE_HTTPRESOLVER_AUTH_BASIC_SECRET | /cantaloupe/httpresolver/auth/basic/secret | | -| CANTALOUPE_JDBCRESOLVER_URL | /cantaloupe/jdbcresolver/url | jdbc:postgresql://database:5432/cantaloupe | -| CANTALOUPE_JDBCRESOLVER_USER | /cantaloupe/jdbcresolver/user | admin | -| CANTALOUPE_JDBCRESOLVER_PASSWORD | /cantaloupe/jdbcresolver/password | password | -| CANTALOUPE_JDBCRESOLVER_CONNECTION_TIMEOUT | /cantaloupe/jdbcresolver/connection/timeout | 10 | -| CANTALOUPE_AMAZONS3RESOLVER_ACCESS_KEY_ID | /cantaloupe/amazons3resolver/access/key/id | | -| CANTALOUPE_AMAZONS3RESOLVER_SECRET_KEY | /cantaloupe/amazons3resolver/secret/key | | -| CANTALOUPE_AMAZONS3RESOLVER_BUCKET_NAME | /cantaloupe/amazons3resolver/bucket/name | | -| CANTALOUPE_AMAZONS3RESOLVER_BUCKET_REGION | /cantaloupe/amazons3resolver/bucket/region | | -| CANTALOUPE_AMAZONS3RESOLVER_LOOKUP_STRATEGY | /cantaloupe/amazons3resolver/lookup/strategy | BasicLookupStrategy | -| CANTALOUPE_AZURESTORAGERESOLVER_ACCOUNT_NAME | /cantaloupe/azurestorageresolver/account/name | | -| CANTALOUPE_AZURESTORAGERESOLVER_ACCOUNT_KEY | /cantaloupe/azurestorageresolver/account/key | | -| CANTALOUPE_AZURESTORAGERESOLVER_CONTAINER_NAME | /cantaloupe/azurestorageresolver/container/name | | -| CANTALOUPE_AZURESTORAGERESOLVER_LOOKUP_STRATEGY | /cantaloupe/azurestorageresolver/lookup/strategy | BasicLookupStrategy | -| CANTALOUPE_PROCESSOR_AVI | /cantaloupe/processor/avi | FfmpegProcessor | -| CANTALOUPE_PROCESSOR_BMP | /cantaloupe/processor/bmp | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_DCM | /cantaloupe/processor/dcm | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_GIF | /cantaloupe/processor/gif | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_JP2 | /cantaloupe/processor/jp2 | OpenJpegProcessor | -| CANTALOUPE_PROCESSOR_JPG | /cantaloupe/processor/jpg | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_MOV | /cantaloupe/processor/mov | FfmpegProcessor | -| CANTALOUPE_PROCESSOR_MP4 | /cantaloupe/processor/mp4 | FfmpegProcessor | -| CANTALOUPE_PROCESSOR_MPG | /cantaloupe/processor/mpg | FfmpegProcessor | -| CANTALOUPE_PROCESSOR_PDF | /cantaloupe/processor/pdf | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_PNG | /cantaloupe/processor/png | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_TIF | /cantaloupe/processor/tif | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_WEBM | /cantaloupe/processor/webm | FfmpegProcessor | -| CANTALOUPE_PROCESSOR_WEBP | /cantaloupe/processor/webp | ImageMagickProcessor | -| CANTALOUPE_PROCESSOR_FALLBACK | /cantaloupe/processor/fallback | Java2dProcessor | -| CANTALOUPE_PROCESSOR_NORMALIZE | /cantaloupe/processor/normalize | false | -| CANTALOUPE_PROCESSOR_BACKGROUND_COLOR | /cantaloupe/processor/background/color | black | -| CANTALOUPE_PROCESSOR_DOWNSCALE_FILTER | /cantaloupe/processor/downscale/filter | bicubic | -| CANTALOUPE_PROCESSOR_UPSCALE_FILTER | /cantaloupe/processor/upscale/filter | bicubic | -| CANTALOUPE_PROCESSOR_SHARPEN | /cantaloupe/processor/sharpen | 0 | -| CANTALOUPE_PROCESSOR_JPG_PROGRESSIVE | /cantaloupe/processor/jpg/progressive | true | -| CANTALOUPE_PROCESSOR_JPG_QUALITY | /cantaloupe/processor/jpg/quality | 80 | -| CANTALOUPE_PROCESSOR_TIF_COMPRESSION | /cantaloupe/processor/tif/compression | LZW | -| CANTALOUPE_STREAMPROCESSOR_RETRIEVAL_STRATEGY | /cantaloupe/streamprocessor/retrieval/strategy | StreamStrategy | -| CANTALOUPE_FFMPEGPROCESSOR_PATH_TO_BINARIES | /cantaloupe/ffmpegprocessor/path/to/binaries | | -| CANTALOUPE_GRAPHICSMAGICKPROCESSOR_PATH_TO_BINARIES | /cantaloupe/graphicsmagickprocessor/path/to/binaries | | -| CANTALOUPE_IMAGEMAGICKPROCESSOR_PATH_TO_BINARIES | /cantaloupe/imagemagickprocessor/path/to/binaries | | -| CANTALOUPE_KAKADUPROCESSOR_PATH_TO_BINARIES | /cantaloupe/kakaduprocessor/path/to/binaries | | -| CANTALOUPE_OPENJPEGPROCESSOR_PATH_TO_BINARIES | /cantaloupe/openjpegprocessor/path/to/binaries | | -| CANTALOUPE_PDFBOXPROCESSOR_DPI | /cantaloupe/pdfboxprocessor/dpi | 150 | -| CANTALOUPE_CACHE_CLIENT_ENABLED | /cantaloupe/cache/client/enabled | true | -| CANTALOUPE_CACHE_CLIENT_MAX_AGE | /cantaloupe/cache/client/max/age | 2592000 | -| CANTALOUPE_CACHE_CLIENT_SHARED_MAX_AGE | /cantaloupe/cache/client/shared/max/age | | -| CANTALOUPE_CACHE_CLIENT_PUBLIC | /cantaloupe/cache/client/public | true | -| CANTALOUPE_CACHE_CLIENT_PRIVATE | /cantaloupe/cache/client/private | false | -| CANTALOUPE_CACHE_CLIENT_NO_CACHE | /cantaloupe/cache/client/no/cache | false | -| CANTALOUPE_CACHE_CLIENT_NO_STORE | /cantaloupe/cache/client/no/store | false | -| CANTALOUPE_CACHE_CLIENT_MUST_REVALIDATE | /cantaloupe/cache/client/must/revalidate | false | -| CANTALOUPE_CACHE_CLIENT_PROXY_REVALIDATE | /cantaloupe/cache/client/proxy/revalidate | false | -| CANTALOUPE_CACHE_CLIENT_NO_TRANSFORM | /cantaloupe/cache/client/no/transform | true | -| CANTALOUPE_CACHE_SOURCE | /cantaloupe/cache/source | FilesystemCache | -| CANTALOUPE_CACHE_DERIVATIVE | /cantaloupe/cache/derivative | FilesystemCache | -| CANTALOUPE_CACHE_SERVER_TTL_SECONDS | /cantaloupe/cache/server/ttl/seconds | 2592000 | -| CANTALOUPE_CACHE_SERVER_PURGE_MISSING | /cantaloupe/cache/server/purge/missing | false | -| CANTALOUPE_CACHE_SERVER_RESOLVE_FIRST | /cantaloupe/cache/server/resolve/first | false | -| CANTALOUPE_CACHE_SERVER_WORKER_ENABLED | /cantaloupe/cache/server/worker/enabled | false | -| CANTALOUPE_CACHE_SERVER_WORKER_INTERVAL | /cantaloupe/cache/server/worker/interval | 86400 | -| CANTALOUPE_FILESYSTEMCACHE_PATHNAME | /cantaloupe/filesystemcache/pathname | /data | -| CANTALOUPE_FILESYSTEMCACHE_DIR_DEPTH | /cantaloupe/filesystemcache/dir/depth | 3 | -| CANTALOUPE_FILESYSTEMCACHE_DIR_NAME_LENGTH | /cantaloupe/filesystemcache/dir/name/length | 2 | -| CANTALOUPE_JDBCCACHE_URL | /cantaloupe/jdbccache/url | jdbc:postgresql://database:5432/cantaloupe | -| CANTALOUPE_JDBCCACHE_USER | /cantaloupe/jdbccache/user | admin | -| CANTALOUPE_JDBCCACHE_PASSWORD | /cantaloupe/jdbccache/password | password | -| CANTALOUPE_JDBCCACHE_CONNECTION_TIMEOUT | /cantaloupe/jdbccache/connection/timeout | 10 | -| CANTALOUPE_JDBCCACHE_DERIVATIVE_IMAGE_TABLE | /cantaloupe/jdbccache/derivative/image/table | derivative_cache | -| CANTALOUPE_JDBCCACHE_INFO_TABLE | /cantaloupe/jdbccache/info/table | info_cache | -| CANTALOUPE_AMAZONS3CACHE_ACCESS_KEY_ID | /cantaloupe/amazons3cache/access/key/id | | -| CANTALOUPE_AMAZONS3CACHE_SECRET_KEY | /cantaloupe/amazons3cache/secret/key | | -| CANTALOUPE_AMAZONS3CACHE_BUCKET_NAME | /cantaloupe/amazons3cache/bucket/name | | -| CANTALOUPE_AMAZONS3CACHE_BUCKET_REGION | /cantaloupe/amazons3cache/bucket/region | | -| CANTALOUPE_AMAZONS3CACHE_OBJECT_KEY_PREFIX | /cantaloupe/amazons3cache/object/key/prefix | | -| CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_NAME | /cantaloupe/azurestoragecache/account/name | | -| CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_KEY | /cantaloupe/azurestoragecache/account/key | | -| CANTALOUPE_AZURESTORAGECACHE_CONTAINER_NAME | /cantaloupe/azurestoragecache/container/name | | -| CANTALOUPE_AZURESTORAGECACHE_OBJECT_KEY_PREFIX | /cantaloupe/azurestoragecache/object/key/prefix | | -| CANTALOUPE_OVERLAYS_ENABLED | /cantaloupe/overlays/enabled | false | -| CANTALOUPE_OVERLAYS_STRATEGY | /cantaloupe/overlays/strategy | BasicStrategy | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_TYPE | /cantaloupe/overlays/basicstrategy/type | image | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_IMAGE | /cantaloupe/overlays/basicstrategy/image | /path/to/overlay.png | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING | /cantaloupe/overlays/basicstrategy/string | Copyright. All rights reserved. | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT | /cantaloupe/overlays/basicstrategy/string/font | Helvetica | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_SIZE | /cantaloupe/overlays/basicstrategy/string/font/size | 24 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_MIN_SIZE | /cantaloupe/overlays/basicstrategy/string/font/min/size | 18 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_WEIGHT | /cantaloupe/overlays/basicstrategy/string/font/weight | 1.0 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_GLYPH_SPACING | /cantaloupe/overlays/basicstrategy/string/glyph/spacing | 0.02 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_COLOR | /cantaloupe/overlays/basicstrategy/string/color | white | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_COLOR | /cantaloupe/overlays/basicstrategy/string/stroke/color | black | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_WIDTH | /cantaloupe/overlays/basicstrategy/string/stroke/width | 1 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_BACKGROUND_COLOR | /cantaloupe/overlays/basicstrategy/string/background/color | rgba(0, 0, 0, 100) | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_POSITION | /cantaloupe/overlays/basicstrategy/position | bottom right | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_INSET | /cantaloupe/overlays/basicstrategy/inset | 10 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_WIDTH_THRESHOLD | /cantaloupe/overlays/basicstrategy/output/width/threshold | 400 | -| CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_HEIGHT_THRESHOLD | /cantaloupe/overlays/basicstrategy/output/height/threshold | 300 | -| CANTALOUPE_REDACTION_ENABLED | /cantaloupe/redaction/enabled | false | -| CANTALOUPE_METADATA_PRESERVE | /cantaloupe/metadata/preserve | false | -| CANTALOUPE_METADATA_RESPECT_ORIENTATION | /cantaloupe/metadata/respect/orientation | false | -| CANTALOUPE_LOG_APPLICATION_LEVEL | /cantaloupe/log/application/level | debug | -| CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_ENABLED | /cantaloupe/log/application/consoleappender/enabled | false | -| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_ENABLED | /cantaloupe/log/application/fileappender/enabled | false | -| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_PATHNAME | /cantaloupe/log/application/fileappender/pathname | /opt/tomcat/logs/cantaloupe.application.log | -| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_ENABLED | /cantaloupe/log/application/rollingfileappender/enabled | true | -| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_PATHNAME | /cantaloupe/log/application/rollingfileappender/pathname | /opt/tomcat/logs/cantaloupe.application.log | -| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_POLICY | /cantaloupe/log/application/rollingfileappender/policy | TimeBasedRollingPolicy | -| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | /cantaloupe/log/application/rollingfileappender/timebasedrollingpolicy/filename/pattern | /opt/tomcat/logs/cantaloupe.application-%d{yyyy-MM-dd}.log | -| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | /cantaloupe/log/application/rollingfileappender/timebasedrollingpolicy/max/history | 30 | -| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_ENABLED | /cantaloupe/log/application/syslogappender/enabled | false | -| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_HOST | /cantaloupe/log/application/syslogappender/host | | -| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_PORT | /cantaloupe/log/application/syslogappender/port | 514 | -| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_FACILITY | /cantaloupe/log/application/syslogappender/facility | LOCAL0 | -| CANTALOUPE_LOG_ERROR_CONSOLEAPPENDER_ENABLED | /cantaloupe/log/error/consoleappender/enabled | false | -| CANTALOUPE_LOG_ERROR_FILEAPPENDER_ENABLED | /cantaloupe/log/error/fileappender/enabled | false | -| CANTALOUPE_LOG_ERROR_FILEAPPENDER_PATHNAME | /cantaloupe/log/error/fileappender/pathname | /opt/tomcat/logs/cantaloupe.error.log | -| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_ENABLED | /cantaloupe/log/error/rollingfileappender/enabled | true | -| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_PATHNAME | /cantaloupe/log/error/rollingfileappender/pathname | /opt/tomcat/logs/cantaloupe.error.log | -| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_POLICY | /cantaloupe/log/error/rollingfileappender/policy | TimeBasedRollingPolicy | -| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | /cantaloupe/log/error/rollingfileappender/timebasedrollingpolicy/filename/pattern | /opt/tomcat/logs/cantaloupe.error-%d{yyyy-MM-dd}.log | -| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | /cantaloupe/log/error/rollingfileappender/timebasedrollingpolicy/max/history | 30 | -| CANTALOUPE_LOG_ERROR_SYSLOGAPPENDER_ENABLED | /cantaloupe/log/error/syslogappender/enabled | false | -| CANTALOUPE_LOG_ERROR_SYSLOGAPPENDER_HOST | /cantaloupe/log/error/syslogappender/host | | -| CANTALOUPE_LOG_ERROR_SYSLOGAPPENDER_PORT | /cantaloupe/log/error/syslogappender/port | 514 | -| CANTALOUPE_LOG_ERROR_SYSLOGAPPENDER_FACILITY | /cantaloupe/log/error/syslogappender/facility | LOCAL0 | -| CANTALOUPE_LOG_ACCESS_CONSOLEAPPENDER_ENABLED | /cantaloupe/log/access/consoleappender/enabled | false | -| CANTALOUPE_LOG_ACCESS_FILEAPPENDER_ENABLED | /cantaloupe/log/access/fileappender/enabled | false | -| CANTALOUPE_LOG_ACCESS_FILEAPPENDER_PATHNAME | /cantaloupe/log/access/fileappender/pathname | /opt/tomcat/logs/cantaloupe.access.log | -| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_ENABLED | /cantaloupe/log/access/rollingfileappender/enabled | true | -| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_PATHNAME | /cantaloupe/log/access/rollingfileappender/pathname | /opt/tomcat/logs/cantaloupe.access.log | -| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_POLICY | /cantaloupe/log/access/rollingfileappender/policy | TimeBasedRollingPolicy | -| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | /cantaloupe/log/access/rollingfileappender/timebasedrollingpolicy/filename/pattern | /opt/tomcat/logs/cantaloupe.access-%d{yyyy-MM-dd}.log | -| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | /cantaloupe/log/access/rollingfileappender/timebasedrollingpolicy/max/history | 30 | -| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_ENABLED | /cantaloupe/log/access/syslogappender/enabled | false | -| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_HOST | /cantaloupe/log/access/syslogappender/host | | -| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_PORT | /cantaloupe/log/access/syslogappender/port | 514 | -| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_FACILITY | /cantaloupe/log/access/syslogappender/facility | LOCAL0 | - -## Logs - -| Path | Description | -| :------------------------------------------ | :---------------- | -| /opt/tomcat/logs/cantaloupe.access.log | [Cantaloupe Logs] | -| /opt/tomcat/logs/cantaloupe.application.log | [Cantaloupe Logs] | +| Environment Variable | Default | +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------- | +| CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_KEY | | +| CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_NAME | | +| CANTALOUPE_AZURESTORAGECACHE_CONTAINER_NAME | | +| CANTALOUPE_AZURESTORAGECACHE_OBJECT_KEY_PREFIX | | +| CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_KEY | | +| CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_NAME | | +| CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CACHE_ENABLED | "true" | +| CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CACHE_MAX_SIZE | "5M" | +| CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CHUNK_SIZE | "512K" | +| CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_ENABLED | "true" | +| CANTALOUPE_AZURESTORAGESOURCE_CONTAINER_NAME | | +| CANTALOUPE_AZURESTORAGESOURCE_LOOKUP_STRATEGY | "BasicLookupStrategy" | +| CANTALOUPE_BASE_URI | | +| CANTALOUPE_CACHE_CLIENT_ENABLED | "true" | +| CANTALOUPE_CACHE_CLIENT_MAX_AGE | "2592000" | +| CANTALOUPE_CACHE_CLIENT_MUST_REVALIDATE | "false" | +| CANTALOUPE_CACHE_CLIENT_NO_CACHE | "false" | +| CANTALOUPE_CACHE_CLIENT_NO_STORE | "false" | +| CANTALOUPE_CACHE_CLIENT_NO_TRANSFORM | "true" | +| CANTALOUPE_CACHE_CLIENT_PRIVATE | "false" | +| CANTALOUPE_CACHE_CLIENT_PROXY_REVALIDATE | "false" | +| CANTALOUPE_CACHE_CLIENT_PUBLIC | "true" | +| CANTALOUPE_CACHE_CLIENT_SHARED_MAX_AGE | | +| CANTALOUPE_CACHE_SERVER_DERIVATIVE_ENABLED | "false" | +| CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS | "2592000" | +| CANTALOUPE_CACHE_SERVER_DERIVATIVE | | +| CANTALOUPE_CACHE_SERVER_INFO_ENABLED | "true" | +| CANTALOUPE_CACHE_SERVER_PURGE_MISSING | "false" | +| CANTALOUPE_CACHE_SERVER_RESOLVE_FIRST | "false" | +| CANTALOUPE_CACHE_SERVER_SOURCE_TTL_SECONDS | "2592000" | +| CANTALOUPE_CACHE_SERVER_SOURCE | "FilesystemCache" | +| CANTALOUPE_CACHE_SERVER_WORKER_ENABLED | "false" | +| CANTALOUPE_CACHE_SERVER_WORKER_INTERVAL | "86400" | +| CANTALOUPE_DELEGATE_SCRIPT_ENABLED | "false" | +| CANTALOUPE_DELEGATE_SCRIPT_PATHNAME | "delegates.rb" | +| CANTALOUPE_ENDPOINT_ADMIN_ENABLED | "false" | +| CANTALOUPE_ENDPOINT_ADMIN_SECRET | | +| CANTALOUPE_ENDPOINT_ADMIN_USERNAME | "admin" | +| CANTALOUPE_ENDPOINT_API_ENABLED | "false" | +| CANTALOUPE_ENDPOINT_API_SECRET | | +| CANTALOUPE_ENDPOINT_API_USERNAME | | +| CANTALOUPE_ENDPOINT_HEALTH_DEPENDENCY_CHECK | "false" | +| CANTALOUPE_ENDPOINT_IIIF_1_ENABLED | "false" | +| CANTALOUPE_ENDPOINT_IIIF_2_ENABLED | "true" | +| CANTALOUPE_ENDPOINT_IIIF_3_ENABLED | "true" | +| CANTALOUPE_ENDPOINT_IIIF_MIN_SIZE | "64" | +| CANTALOUPE_ENDPOINT_IIIF_MIN_TILE_SIZE | "512" | +| CANTALOUPE_ENDPOINT_IIIF_RESTRICT_TO_SIZES | "false" | +| CANTALOUPE_FFMPEGPROCESSOR_PATH_TO_BINARIES | | +| CANTALOUPE_FILESYSTEMCACHE_DIR_DEPTH | "3" | +| CANTALOUPE_FILESYSTEMCACHE_DIR_NAME_LENGTH | "2" | +| CANTALOUPE_FILESYSTEMCACHE_PATHNAME | "/data" | +| CANTALOUPE_FILESYSTEMSOURCE_BASICLOOKUPSTRATEGY_PATH_PREFIX | "/var/www/drupal/web/" | +| CANTALOUPE_FILESYSTEMSOURCE_BASICLOOKUPSTRATEGY_PATH_SUFFIX | | +| CANTALOUPE_FILESYSTEMSOURCE_LOOKUP_STRATEGY | "BasicLookupStrategy" | +| CANTALOUPE_GROKPROCESSOR_PATH_TO_BINARIES | | +| CANTALOUPE_HEAPCACHE_PERSIST_FILESYSTEM_PATHNAME | "/data/heap.cache" | +| CANTALOUPE_HEAPCACHE_PERSIST | "false" | +| CANTALOUPE_HEAPCACHE_TARGET_SIZE | "2G" | +| CANTALOUPE_HTTP_ACCEPT_QUEUE_LIMIT | | +| CANTALOUPE_HTTP_ENABLED | "true" | +| CANTALOUPE_HTTP_HOST | "0.0.0.0" | +| CANTALOUPE_HTTP_MAX_THREADS | | +| CANTALOUPE_HTTP_MIN_THREADS | | +| CANTALOUPE_HTTP_PORT | "8182" | +| CANTALOUPE_HTTPS_ENABLED | "false" | +| CANTALOUPE_HTTPS_HOST | "0.0.0.0" | +| CANTALOUPE_HTTPS_KEY_PASSWORD | "password" | +| CANTALOUPE_HTTPS_KEY_STORE_PASSWORD | "password" | +| CANTALOUPE_HTTPS_KEY_STORE_PATH | "/path/to/keystore.jks" | +| CANTALOUPE_HTTPS_KEY_STORE_TYPE | "JKS" | +| CANTALOUPE_HTTPS_PORT | "8183" | +| CANTALOUPE_HTTPSOURCE_ALLOW_INSECURE | "false" | +| CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_AUTH_BASIC_SECRET | | +| CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_AUTH_BASIC_USERNAME | | +| CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_URL_PREFIX | | +| CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_URL_SUFFIX | | +| CANTALOUPE_HTTPSOURCE_CHUNKING_CACHE_ENABLED | "true" | +| CANTALOUPE_HTTPSOURCE_CHUNKING_CACHE_MAX_SIZE | "5M" | +| CANTALOUPE_HTTPSOURCE_CHUNKING_CHUNK_SIZE | "512K" | +| CANTALOUPE_HTTPSOURCE_CHUNKING_ENABLED | "true" | +| CANTALOUPE_HTTPSOURCE_LOOKUP_STRATEGY | "BasicLookupStrategy" | +| CANTALOUPE_HTTPSOURCE_REQUEST_TIMEOUT | | +| CANTALOUPE_JDBCCACHE_CONNECTION_TIMEOUT | "10" | +| CANTALOUPE_JDBCCACHE_DERIVATIVE_IMAGE_TABLE | "derivative_cache" | +| CANTALOUPE_JDBCCACHE_INFO_TABLE | "info_cache" | +| CANTALOUPE_JDBCCACHE_PASSWORD | "password" | +| CANTALOUPE_JDBCCACHE_URL | "jdbc:postgresql://database:5432/cantaloupe" | +| CANTALOUPE_JDBCCACHE_USER | "admin" | +| CANTALOUPE_JDBCSOURCE_CONNECTION_TIMEOUT | "10" | +| CANTALOUPE_JDBCSOURCE_PASSWORD | "password" | +| CANTALOUPE_JDBCSOURCE_URL | "jdbc:postgresql://database:5432/cantaloupe" | +| CANTALOUPE_JDBCSOURCE_USER | "admin" | +| CANTALOUPE_LOG_ACCESS_CONSOLEAPPENDER_ENABLED | "true" | +| CANTALOUPE_LOG_ACCESS_FILEAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_ACCESS_FILEAPPENDER_PATHNAME | "/opt/cantaloupe/logs/cantaloupe.access.log" | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_PATHNAME | "/opt/cantaloupe/logs/cantaloupe.access.log" | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_POLICY | "TimeBasedRollingPolicy" | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | "/opt/cantaloupe/logs/cantaloupe.access-%d{yyyy-MM-dd}.log" | +| CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | "30" | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_FACILITY | "LOCAL0" | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_HOST | | +| CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_PORT | "514" | +| CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_ENABLED | "true" | +| CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_LOGSTASH_ENABLED | "false" | +| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_LOGSTASH_ENABLED | "false" | +| CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_PATHNAME | "/opt/cantaloupe/logs/cantaloupe.application.log" | +| CANTALOUPE_LOG_APPLICATION_LEVEL | "debug" | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_LOGSTASH_ENABLED | "false" | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_PATHNAME | "/opt/cantaloupe/logs/cantaloupe.application.log" | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_POLICY | "TimeBasedRollingPolicy" | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | "/opt/cantaloupe/logs/cantaloupe.application-%d{yyyy-MM-dd}.log" | +| CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | "30" | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_FACILITY | "LOCAL0" | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_HOST | | +| CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_PORT | "514" | +| CANTALOUPE_LOG_ERROR_FILEAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_ERROR_FILEAPPENDER_LOGSTASH_ENABLED | "false" | +| CANTALOUPE_LOG_ERROR_FILEAPPENDER_PATHNAME | "/opt/cantaloupe/logs/cantaloupe.error.log" | +| CANTALOUPE_LOG_ERROR_RESPONSES | "false" | +| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_ENABLED | "false" | +| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_LOGSTASH_ENABLED | "false" | +| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_PATHNAME | "/opt/cantaloupe/logs/cantaloupe.error.log" | +| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_POLICY | "TimeBasedRollingPolicy" | +| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN | "/opt/cantaloupe/logs/cantaloupe.error-%d{yyyy-MM-dd}.log" | +| CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY | "30" | +| CANTALOUPE_MAX_PIXELS | "10000000" | +| CANTALOUPE_MAX_SCALE | "1.0" | +| CANTALOUPE_META_IDENTIFIER_TRANSFORMER_STANDARDMETAIDENTIFIERTRANSFORMER_DELIMITER | ";" | +| CANTALOUPE_META_IDENTIFIER_TRANSFORMER | "StandardMetaIdentifierTransformer" | +| CANTALOUPE_OPENJPEGPROCESSOR_PATH_TO_BINARIES | | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_ENABLED | "false" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_IMAGE | "/path/to/overlay_png" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_INSET | "10" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_HEIGHT_THRESHOLD | "300" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_WIDTH_THRESHOLD | "400" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_POSITION | "bottom right" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_BACKGROUND_COLOR | "rgba(0, 0, 0, 100)" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_COLOR | "white" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_MIN_SIZE | "18" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_SIZE | "24" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_WEIGHT | "1.0" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT | "Helvetica" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_GLYPH_SPACING | "0.02" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_COLOR | "black" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_WIDTH | "1" | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING | "Copyright. All rights reserved." | +| CANTALOUPE_OVERLAYS_BASICSTRATEGY_TYPE | "image" | +| CANTALOUPE_OVERLAYS_STRATEGY | "BasicStrategy" | +| CANTALOUPE_PRINT_STACK_TRACE_ON_ERROR_PAGES | "true" | +| CANTALOUPE_PROCESSOR_BACKGROUND_COLOR | "white" | +| CANTALOUPE_PROCESSOR_DOWNSCALE_FILTER | "bicubic" | +| CANTALOUPE_PROCESSOR_DOWNSCALE_LINEAR | "false" | +| CANTALOUPE_PROCESSOR_DPI | "150" | +| CANTALOUPE_PROCESSOR_FALLBACK_RETRIEVAL_STRATEGY | "DownloadStrategy" | +| CANTALOUPE_PROCESSOR_IMAGEIO_BMP_READER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_GIF_READER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_GIF_WRITER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_JPG_READER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_JPG_WRITER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_PNG_READER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_PNG_WRITER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_TIF_READER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_TIF_WRITER | | +| CANTALOUPE_PROCESSOR_IMAGEIO_XPM_READER | | +| CANTALOUPE_PROCESSOR_JPG_PROGRESSIVE | "true" | +| CANTALOUPE_PROCESSOR_JPG_QUALITY | "80" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_AVI | "FfmpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_BMP | "Java2dProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_FALLBACK | "Java2dProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_FLV | "FfmpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_GIF | "Java2dProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JP2 | "OpenJpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JPG | "TurboJpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MOV | "FfmpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MP4 | "FfmpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MPG | "FfmpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_PDF | "PDFBox" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_PNG | "Java2dProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_TIF | "Java2dProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_WEBM | "FfmpegProcessor" | +| CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_XPM | | +| CANTALOUPE_PROCESSOR_PDF_MAX_MEMORY_BYTES | "-1" | +| CANTALOUPE_PROCESSOR_PDF_SCRATCH_FILE_ENABLED | "false" | +| CANTALOUPE_PROCESSOR_SELECTION_STRATEGY | "AutomaticSelectionStrategy" | +| CANTALOUPE_PROCESSOR_SHARPEN | "0" | +| CANTALOUPE_PROCESSOR_STREAM_RETRIEVAL_STRATEGY | "StreamStrategy" | +| CANTALOUPE_PROCESSOR_TIF_COMPRESSION | "LZW" | +| CANTALOUPE_PROCESSOR_UPSCALE_FILTER | "bicubic" | +| CANTALOUPE_REDISCACHE_DATABASE | "0" | +| CANTALOUPE_REDISCACHE_HOST | "localhost" | +| CANTALOUPE_REDISCACHE_PASSWORD | | +| CANTALOUPE_REDISCACHE_PORT | "6379" | +| CANTALOUPE_REDISCACHE_SSL | "false" | +| CANTALOUPE_S3CACHE_ACCESS_KEY_ID | | +| CANTALOUPE_S3CACHE_BUCKET_NAME | | +| CANTALOUPE_S3CACHE_ENDPOINT | | +| CANTALOUPE_S3CACHE_OBJECT_KEY_PREFIX | | +| CANTALOUPE_S3CACHE_REGION | | +| CANTALOUPE_S3CACHE_SECRET_KEY | | +| CANTALOUPE_S3SOURCE_ACCESS_KEY_ID | | +| CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_BUCKET_NAME | | +| CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_PATH_PREFIX | | +| CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_PATH_SUFFIX | | +| CANTALOUPE_S3SOURCE_CHUNKING_CACHE_ENABLED | "true" | +| CANTALOUPE_S3SOURCE_CHUNKING_CACHE_MAX_SIZE | "5M" | +| CANTALOUPE_S3SOURCE_CHUNKING_CHUNK_SIZE | "512K" | +| CANTALOUPE_S3SOURCE_CHUNKING_ENABLED | "true" | +| CANTALOUPE_S3SOURCE_ENDPOINT | | +| CANTALOUPE_S3SOURCE_LOOKUP_STRATEGY | "BasicLookupStrategy" | +| CANTALOUPE_S3SOURCE_REGION | | +| CANTALOUPE_S3SOURCE_SECRET_KEY | | +| CANTALOUPE_SLASH_SUBSTITUTE | | +| CANTALOUPE_SOURCE_DELEGATE | "false" | +| CANTALOUPE_SOURCE_STATIC | "HttpSource" | +| CANTALOUPE_TEMP_PATHNAME | | [Cantaloupe Caching]: https://cantaloupe-project.github.io/manual/3.1/caching.html [Cantaloupe Documentation]: https://cantaloupe-project.github.io/manual/3.1/getting-started.html diff --git a/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml b/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml index 65a5bda1..7c89f007 100644 --- a/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml +++ b/cantaloupe/rootfs/etc/confd/conf.d/cataloupe.properties.toml @@ -1,6 +1,6 @@ [template] src = "cantaloupe.properties.tmpl" -dest = "/opt/tomcat/conf/cantaloupe.properties" +dest = "/opt/cantaloupe/cantaloupe.properties" uid = 100 gid = 1000 mode = "0640" diff --git a/cantaloupe/rootfs/etc/confd/conf.d/setenv.sh.toml b/cantaloupe/rootfs/etc/confd/conf.d/setenv.sh.toml deleted file mode 100644 index 7f0fbd2f..00000000 --- a/cantaloupe/rootfs/etc/confd/conf.d/setenv.sh.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "setenv.sh.tmpl" -dest = "/opt/tomcat/bin/setenv.sh" -uid = 100 -gid = 1000 -keys = ["/java/opts", "/catalina/opts"] diff --git a/cantaloupe/rootfs/etc/confd/confd.toml b/cantaloupe/rootfs/etc/confd/confd.toml deleted file mode 100644 index 5ad14b76..00000000 --- a/cantaloupe/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/cantaloupe" diff --git a/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl b/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl index a38458ac..1604cc86 100644 --- a/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl +++ b/cantaloupe/rootfs/etc/confd/templates/cantaloupe.properties.tmpl @@ -1,122 +1,304 @@ ########################################################################### -# GENERAL SETTINGS +# Sample Cantaloupe configuration file +# +# Copy this file to `cantaloupe.properties` and edit as desired. +# +# Keys may change from version to version. See the "Upgrading" section of +# the website. +# +# Most changes will take effect without restarting. Those that won't are +# marked with "!!". ########################################################################### -temp_pathname = {{ getv "/temp/pathname" "" }} -http.enabled = {{ getv "/http/enabled" "true" }} -http.host = {{ getv "/http/host" "0.0.0.0" }} -http.port = {{ getv "/http/port" "8182" }} -https.enabled = {{ getv "/https/enabled" "false" }} -https.host = {{ getv "/https/host" "0.0.0.0" }} -https.port = {{ getv "/https/port" "8183" }} -https.key_store_type = {{ getv "/https/key/store/type" "JKS" }} -https.key_store_password = {{ getv "/https/key/store/password" "password" }} -https.key_store_path = {{ getv "/https/key/store/path" "/path/to/keystore.jks" }} -https.key_password = {{ getv "/https/key/password" "password" }} -auth.basic.enabled = {{ getv "/auth/basic/enabled" "false" }} -auth.basic.username = {{ getv "/auth/basic/username" "admin" }} -auth.basic.secret = {{ getv "/auth/basic/secret" "password" }} -admin.enabled = {{ getv "/admin/enabled" "true" }} -admin.password = {{ getv "/admin/password" "password" }} -base_uri = {{ getv "/base/uri" "" }} -slash_substitute = {{ getv "/slash/substitute" "" }} -max_pixels = {{ getv "/max/pixels" "400000000" }} -print_stack_trace_on_error_pages = {{ getv "/print/stack/trace/on/error/pages" "true" }} -scale_constraints.delimiter = {{ getv "/scale/constraints/delimiter" "-" }} +# !! Leave blank to use the JVM default temporary directory. +temp_pathname = {{ getenv "CANTALOUPE_TEMP_PATHNAME" }} + +# !! Configures the HTTP server. (Standalone mode only.) +http.enabled = {{ getenv "CANTALOUPE_HTTP_ENABLED" }} +http.host = {{ getenv "CANTALOUPE_HTTP_HOST" }} +http.port = {{ getenv "CANTALOUPE_HTTP_PORT" }} + +# !! Configures the HTTPS server. (Standalone mode only.) +https.enabled = {{ getenv "CANTALOUPE_HTTPS_ENABLED" }} +https.host = {{ getenv "CANTALOUPE_HTTPS_HOST" }} +https.port = {{ getenv "CANTALOUPE_HTTPS_PORT" }} + +# !! Available values are `JKS` and `PKCS12`. (Standalone mode only.) +https.key_store_type = {{ getenv "CANTALOUPE_HTTPS_KEY_STORE_TYPE" }} +https.key_store_password = {{ getenv "CANTALOUPE_HTTPS_KEY_STORE_PASSWORD" }} +https.key_store_path = {{ getenv "CANTALOUPE_HTTPS_KEY_STORE_PATH" }} +https.key_password = {{ getenv "CANTALOUPE_HTTPS_KEY_PASSWORD" }} + +# !! Constrains the size of the web server's thread pool. Leave blank to +# use the defaults. +http.min_threads = {{ getenv "CANTALOUPE_HTTP_MIN_THREADS" }} +http.max_threads = {{ getenv "CANTALOUPE_HTTP_MAX_THREADS" }} + +# !! Maximum size of the request queue. Leave blank to use the default. +http.accept_queue_limit = {{ getenv "CANTALOUPE_HTTP_ACCEPT_QUEUE_LIMIT" }} + +# Base URI to use for internal links, such as Link headers and JSON-LD +# @id values, in a reverse-proxy context. This should only be used when +# X-Forwarded-* headers cannot be used instead. (See the user manual.) +base_uri = {{ getenv "CANTALOUPE_BASE_URI" }} + +# Normally, slashes in a URI path component must be percent-encoded as +# "%2F". If your proxy is not able to pass these through without decoding, +# you can define an alternate character or character sequence to substitute +# for a slash. Supply the non-percent-encoded version here, and use the +# percent-encoded version in URLs. +slash_substitute = {{ getenv "CANTALOUPE_SLASH_SUBSTITUTE" }} + +# Maximum number of pixels to return in a response, to prevent overloading +# the server. Requests for more pixels than this will receive an error +# response. Set to 0 for no maximum. +max_pixels = {{ getenv "CANTALOUPE_MAX_PIXELS" }} + +# Maximum scale to allow (1.0 = full scale; 0 = no maximum). +max_scale = {{ getenv "CANTALOUPE_MAX_SCALE" }} + +# A meta-identifier is a superset of an identifier that includes other +# information like a page number and/or scale constraint. A meta-identifier +# transformer transforms a meta-identifier to and from a string in a URI +# path component. +# Available transformers include `StandardMetaIdentifierTransformer` and +# `DelegateMetaIdentifierTransformer`. See the user manual for more +# information about meta-identifiers and these options. +meta_identifier.transformer = {{ getenv "CANTALOUPE_META_IDENTIFIER_TRANSFORMER" }} + +# Character sequence that separates the components of a meta-identifier in +# the identifier portion of a URI. +meta_identifier.transformer.StandardMetaIdentifierTransformer.delimiter = {{ getenv "CANTALOUPE_META_IDENTIFIER_TRANSFORMER_STANDARDMETAIDENTIFIERTRANSFORMER_DELIMITER" }} + +# If true, HTTP >= 400-level responses are logged at WARN and ERROR level. +# This may result in multiple log statements for the same error, but it may +# also help diagnose errors that have evaded logging. +log_error_responses = {{ getenv "CANTALOUPE_LOG_ERROR_RESPONSES" }} + +print_stack_trace_on_error_pages = {{ getenv "CANTALOUPE_PRINT_STACK_TRACE_ON_ERROR_PAGES" }} ########################################################################### # DELEGATE SCRIPT ########################################################################### -delegate_script.enabled = {{ getv "/delegate/script/enabled" "false" }} -delegate_script.pathname = {{ getv "/delegate/script/pathname" "delegates.rb" }} -delegate_script.cache.enabled = {{ getv "/delegate/script/cache/enabled" "false" }} +# Enables the delegate script: a Ruby script containing various delegate +# methods. (See the user manual.) +delegate_script.enabled = {{ getenv "CANTALOUPE_DELEGATE_SCRIPT_ENABLED" }} + +# !! This can be an absolute path, or a filename; if only a filename is +# specified, it will be searched for in the same folder as this file, and +# then the current working directory. +delegate_script.pathname = {{ getenv "CANTALOUPE_DELEGATE_SCRIPT_PATHNAME" }} ########################################################################### # ENDPOINTS ########################################################################### -endpoint.iiif.1.enabled = {{ getv "/endpoint/iiif/1/enabled" "true" }} -endpoint.iiif.2.enabled = {{ getv "/endpoint/iiif/2/enabled" "true" }} -endpoint.iiif.content_disposition = {{ getv "/endpoint/iiif/content/disposition" "inline" }} -endpoint.iiif.min_size = {{ getv "/endpoint/iiif/min//size" "64" }} -endpoint.iiif.min_tile_size = {{ getv "/endpoint/iiif/min/tile/size" "1024" }} -endpoint.iiif.restrict_to_sizes = {{ getv "/endpoint/iiif/restrict/to/sizes" "false" }} -endpoint.api.enabled = {{ getv "/endpoint/api/enabled" "false" }} -endpoint.api.username = {{ getv "/endpoint/api/username" "" }} -endpoint.api.secret = {{ getv "/endpoint/api/secret" "" }} -endpoint.admin.enabled = {{ getv "/endpoint/admin/enabled" "false" }} -endpoint.admin.username = {{ getv "/endpoint/admin/username" "admin" }} -endpoint.admin.secret = {{ getv "/endpoint/admin/secret" "" }} +# Enables the IIIF Image API 1.x endpoint, at /iiif/1. +endpoint.iiif.1.enabled = {{ getenv "CANTALOUPE_ENDPOINT_IIIF_1_ENABLED" }} + +# Enables the IIIF Image API 2.x endpoint, at /iiif/2. +endpoint.iiif.2.enabled = {{ getenv "CANTALOUPE_ENDPOINT_IIIF_2_ENABLED" }} + +# Enables the IIIF Image API 3.x endpoint, at /iiif/3. +endpoint.iiif.3.enabled = {{ getenv "CANTALOUPE_ENDPOINT_IIIF_3_ENABLED" }} + +# Minimum size that will be used in info.json `sizes` keys. +endpoint.iiif.min_size = {{ getenv "CANTALOUPE_ENDPOINT_IIIF_MIN_SIZE" }} + +# Minimum size that will be used in info.json `tiles` keys. The user manual +# explains how these are calculated. +endpoint.iiif.min_tile_size = {{ getenv "CANTALOUPE_ENDPOINT_IIIF_MIN_TILE_SIZE" }} + +# If true, requests for sizes other than those contained in an information +# response will be denied. +endpoint.iiif.restrict_to_sizes = {{ getenv "CANTALOUPE_ENDPOINT_IIIF_RESTRICT_TO_SIZES" }} + +# Enables the Control Panel, at /admin. +endpoint.admin.enabled = {{ getenv "CANTALOUPE_ENDPOINT_ADMIN_ENABLED" }} +endpoint.admin.username = {{ getenv "CANTALOUPE_ENDPOINT_ADMIN_USERNAME" }} +endpoint.admin.secret = {{ getenv "CANTALOUPE_ENDPOINT_ADMIN_SECRET" }} + +# Enables the administrative HTTP API. (See the user manual.) +endpoint.api.enabled = {{ getenv "CANTALOUPE_ENDPOINT_API_ENABLED" }} + +# HTTP Basic credentials to access the HTTP API. +endpoint.api.username = {{ getenv "CANTALOUPE_ENDPOINT_API_USERNAME" }} +endpoint.api.secret = {{ getenv "CANTALOUPE_ENDPOINT_API_SECRET" }} + +# If true, sources and caches will be checked, resulting in a more robust +# but slower health check. Set this to false if these services already have +# their own health checks. +endpoint.health.dependency_check = {{ getenv "CANTALOUPE_ENDPOINT_HEALTH_DEPENDENCY_CHECK" }} ########################################################################### # SOURCES ########################################################################### -source.static = {{ getv "/source/static" "HttpSource" }} -source.delegate = {{ getv "/source/delegate" "false" }} +# Uses one source for all requests. Available values are `FilesystemSource`, +# `HttpSource`, `JdbcSource`, `S3Source`, and `AzureStorageSource`. +source.static = {{ getenv "CANTALOUPE_SOURCE_STATIC" }} + +# If true, `source.static` will be overridden, and the `source()` delegate +# method will be used to select a source per-request. +source.delegate = {{ getenv "CANTALOUPE_SOURCE_DELEGATE" }} #---------------------------------------- # FilesystemSource #---------------------------------------- -FilesystemSource.lookup_strategy = {{ getv "/filesystemsource/lookup/strategy" "BasicLookupStrategy" }} -FilesystemSource.BasicLookupStrategy.path_prefix = {{ getv "/filesystemsource/basiclookupstrategy/path/prefix" "/var/www/drupal/web/" }} -FilesystemSource.BasicLookupStrategy.path_suffix = {{ getv "/filesystemsource/basiclookupstrategy/path/suffix" "" }} +# How to look up files. Allowed values are `BasicLookupStrategy` and +# `ScriptLookupStrategy`. ScriptLookupStrategy uses the delegate script for +# dynamic lookups; see the user manual. +FilesystemSource.lookup_strategy = {{ getenv "CANTALOUPE_FILESYSTEMSOURCE_LOOKUP_STRATEGY" }} + +# Server-side path that will be prefixed to the identifier in the URL. +# Trailing slash is important! +FilesystemSource.BasicLookupStrategy.path_prefix = {{ getenv "CANTALOUPE_FILESYSTEMSOURCE_BASICLOOKUPSTRATEGY_PATH_PREFIX" }} + +# Server-side path or extension that will be suffixed to the identifier in +# the URL. +FilesystemSource.BasicLookupStrategy.path_suffix = {{ getenv "CANTALOUPE_FILESYSTEMSOURCE_BASICLOOKUPSTRATEGY_PATH_SUFFIX" }} #---------------------------------------- # HttpSource #---------------------------------------- -HttpSource.allow_insecure = {{ getv "/httpsource/allow/insecure" "false" }} -HttpSource.request_timeout = {{ getv "/httpsource/request/timeout" "" }} -HttpSource.lookup_strategy = {{ getv "/httpsource/lookup/strategy" "BasicLookupStrategy" }} -HttpSource.BasicLookupStrategy.url_prefix = {{ getv "/httpsource/basiclookupstrategy/url/prefix" "" }} -HttpSource.BasicLookupStrategy.url_suffix = {{ getv "/httpsource/basiclookupstrategy/url/suffix" "" }} -HttpSource.auth.basic.username = {{ getv "/httpsource/auth/basic/username" "" }} -HttpSource.auth.basic.secret = {{ getv "/httpsource/auth/basic/secret" "" }} -HttpSource.chunking.enabled = {{ getv "/httpsource/chunking/enabled" "true" }} -HttpSource.chunking.chunk_size = {{ getv "/httpsource/chunking/chunk/size" "512K" }} -HttpSource.chunking.cache.enabled = {{ getv "/httpsource/chunking/cache/enabled" "true" }} -HttpSource.chunking.cache.max_size = {{ getv "/httpsource/chunking/cache/max/size" "5M" }} +# Trusts insecure certificates and cipher suites. +HttpSource.allow_insecure = {{ getenv "CANTALOUPE_HTTPSOURCE_ALLOW_INSECURE" }} -#---------------------------------------- -# JdbcSource -#---------------------------------------- +# Request timeout in seconds. +HttpSource.request_timeout = {{ getenv "CANTALOUPE_HTTPSOURCE_REQUEST_TIMEOUT" }} + +# Tells HttpSource how to look up resources. Allowed values are +# `BasicLookupStrategy` and `ScriptLookupStrategy`. ScriptLookupStrategy +# uses a delegate method for dynamic lookups; see the user manual. +HttpSource.lookup_strategy = {{ getenv "CANTALOUPE_HTTPSOURCE_LOOKUP_STRATEGY" }} + +# URL that will be prefixed to the identifier in the request URL. +# Trailing slash is important! +HttpSource.BasicLookupStrategy.url_prefix = {{ getenv "CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_URL_PREFIX" }} + +# Path, extension, query string, etc. that will be suffixed to the +# identifier in the request URL. +HttpSource.BasicLookupStrategy.url_suffix = {{ getenv "CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_URL_SUFFIX" }} + +# Enables access to resources that require HTTP Basic authentication. +HttpSource.BasicLookupStrategy.auth.basic.username = {{ getenv "CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_AUTH_BASIC_USERNAME" }} +HttpSource.BasicLookupStrategy.auth.basic.secret = {{ getenv "CANTALOUPE_HTTPSOURCE_BASICLOOKUPSTRATEGY_AUTH_BASIC_SECRET" }} + +# Read data in chunks when it may be more efficient. (This also may end up +# being less efficient, depending on many variables; see the user manual.) +HttpSource.chunking.enabled = {{ getenv "CANTALOUPE_HTTPSOURCE_CHUNKING_ENABLED" }} + +# Chunk size. +HttpSource.chunking.chunk_size = {{ getenv "CANTALOUPE_HTTPSOURCE_CHUNKING_CHUNK_SIZE" }} -JdbcSource.url = {{ getv "/jdbcsoure/url" "jdbc:postgresql://database:5432/cantaloupe" }} -JdbcSource.user = {{ getv "/jdbcsoure/user" "admin" }} -JdbcSource.password = {{ getv "/jdbcsoure/password" "password" }} -JdbcSource.connection_timeout = {{ getv "/jdbcsoure/connection/timeout" "10" }} +# The per-request chunk cache caches downloaded chunks in memory during +# a request, and clears them when the request is complete. +HttpSource.chunking.cache.enabled = {{ getenv "CANTALOUPE_HTTPSOURCE_CHUNKING_CACHE_ENABLED" }} + +# Max per-request chunk cache size. +HttpSource.chunking.cache.max_size = {{ getenv "CANTALOUPE_HTTPSOURCE_CHUNKING_CACHE_MAX_SIZE" }} #---------------------------------------- # S3Source #---------------------------------------- -S3Source.endpoint = {{ getv "/s3source/endpoint" "" }} -S3Source.access_key_id = {{ getv "/s3source/access/key/id" "" }} -S3Source.secret_key = {{ getv "/s3source/secret/key" "" }} -S3Source.lookup_strategy = {{ getv "/s3source/lookup/strategy" "BasicLookupStrategy" }} -S3Source.BasicLookupStrategy.bucket.name = {{ getv "/s3source/basiclookupstrategy/bucket/name" "" }} -S3Source.BasicLookupStrategy.path_prefix = {{ getv "/s3source/basiclookupstrategy/path/prefix" "" }} -S3Source.BasicLookupStrategy.path_suffix = {{ getv "/s3source/basiclookupstrategy/path/suffix" "" }} -S3Source.chunking.enabled = {{ getv "/s3source/chunking/enabled" "true" }} -S3Source.chunking.chunk_size = {{ getv "/s3source/chunking/chunk/size" "512K" }} -S3Source.chunking.cache.enabled = {{ getv "/s3source/chunking/cache/enabled" "true" }} -S3Source.chunking.cache.max_size = {{ getv "/s3source/chunking/cache/max/size" "5M" }} +# !! Endpoint URI. Only needed for non-AWS endpoints. +S3Source.endpoint = {{ getenv "CANTALOUPE_S3SOURCE_ENDPOINT" }} + +# !! AWS region. Only needed for AWS endpoints. +S3Source.region = {{ getenv "CANTALOUPE_S3SOURCE_REGION" }} + +# !! Credentials for your AWS account. +# See: http://aws.amazon.com/security-credentials +# Note that this info can be obtained from elsewhere rather than setting +# it here; see the user manual. +S3Source.access_key_id = {{ getenv "CANTALOUPE_S3SOURCE_ACCESS_KEY_ID" }} +S3Source.secret_key = {{ getenv "CANTALOUPE_S3SOURCE_SECRET_KEY" }} + +# How to look up objects. Allowed values are `BasicLookupStrategy` and +# `ScriptLookupStrategy`. ScriptLookupStrategy uses a delegate method for +# dynamic lookups; see the user manual. +S3Source.lookup_strategy = {{ getenv "CANTALOUPE_S3SOURCE_LOOKUP_STRATEGY" }} + +# !! Name of the bucket containing images to be served. +S3Source.BasicLookupStrategy.bucket.name = {{ getenv "CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_BUCKET_NAME" }} + +# Path within the bucket that will be prefixed to the identifier in the URL. +# Trailing slash is important! +S3Source.BasicLookupStrategy.path_prefix = {{ getenv "CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_PATH_PREFIX" }} + +# Path or extension that will be suffixed to the identifier in the URL. +S3Source.BasicLookupStrategy.path_suffix = {{ getenv "CANTALOUPE_S3SOURCE_BASICLOOKUPSTRATEGY_PATH_SUFFIX" }} + +# Read data in chunks when it may be more efficient. (This also may end up +# being less efficient, depending on many variables; see the user manual.) +S3Source.chunking.enabled = {{ getenv "CANTALOUPE_S3SOURCE_CHUNKING_ENABLED" }} + +# Chunk size. +S3Source.chunking.chunk_size = {{ getenv "CANTALOUPE_S3SOURCE_CHUNKING_CHUNK_SIZE" }} + +# The per-request chunk cache caches downloaded chunks in memory during +# a request, and clears them when the request is complete. +S3Source.chunking.cache.enabled = {{ getenv "CANTALOUPE_S3SOURCE_CHUNKING_CACHE_ENABLED" }} + +# Max per-request chunk cache size. +S3Source.chunking.cache.max_size = {{ getenv "CANTALOUPE_S3SOURCE_CHUNKING_CACHE_MAX_SIZE" }} #---------------------------------------- # AzureStorageSource #---------------------------------------- -AzureStorageSource.account_name = {{ getv "/azurestoragesource/account/name" "" }} -AzureStorageSource.account_key = {{ getv "/azurestoragesource/account/key" "" }} -AzureStorageSource.container_name = {{ getv "/azurestoragesource/container/name" "" }} -AzureStorageSource.lookup_strategy = {{ getv "/azurestoragesource/lookup/strategy" "BasicLookupStrategy" }} -AzureStorageSource.chunking.enabled = {{ getv "/azurestoragesource/chunking/enabled" "true" }} -AzureStorageSource.chunking.chunk_size = {{ getv "/azurestoragesource/chunking/chunk/size" "512K" }} -AzureStorageSource.chunking.cache.enabled = {{ getv "/azurestoragesource/chunking/cache/enabled" "true" }} -AzureStorageSource.chunking.cache.max_size = {{ getv "/azurestoragesource/chunking/cache/max/size" "5M" }} +# !! Name of your Azure account. +# Leave blank if using URI with a SAS token in your object key. +AzureStorageSource.account_name = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_NAME" }} + +# !! Key of your Azure account. +# Leave blank if using URI with a SAS token in your object key. +AzureStorageSource.account_key = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_ACCOUNT_KEY" }} + +# !! Name of the container containing images to be served. +# Leave blank if using URI with the container in your object key. +AzureStorageSource.container_name = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_CONTAINER_NAME" }} + +# Tells AzureStorageSource how to look up objects. Allowed values are +# `BasicLookupStrategy` and `ScriptLookupStrategy`. ScriptLookupStrategy +# uses a delegate method for dynamic lookups; see the user manual. +AzureStorageSource.lookup_strategy = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_LOOKUP_STRATEGY" }} + +# Read data in chunks when it may be more efficient. (This also may end up +# being less efficient, depending on many variables; see the user manual.) +AzureStorageSource.chunking.enabled = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_ENABLED" }} + +# Chunk size. +AzureStorageSource.chunking.chunk_size = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CHUNK_SIZE" }} + +# The per-request chunk cache caches downloaded chunks in memory during +# a request, and clears them when the request is complete. +AzureStorageSource.chunking.cache.enabled = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CACHE_ENABLED" }} + +# Max per-request chunk cache size. +AzureStorageSource.chunking.cache.max_size = {{ getenv "CANTALOUPE_AZURESTORAGESOURCE_CHUNKING_CACHE_MAX_SIZE" }} + +#---------------------------------------- +# JdbcSource +#---------------------------------------- + +# Note: JdbcSource requires some delegate methods to be implemented in +# addition to the configuration here, and a JDBC driver to be installed on +# the classpath; see the user manual. + +# !! +JdbcSource.url = {{ getenv "CANTALOUPE_JDBCSOURCE_URL" }} +# !! +JdbcSource.user = {{ getenv "CANTALOUPE_JDBCSOURCE_USER" }} +# !! +JdbcSource.password = {{ getenv "CANTALOUPE_JDBCSOURCE_PASSWORD" }} + +# !! Connection timeout in seconds. +JdbcSource.connection_timeout = {{ getenv "CANTALOUPE_JDBCSOURCE_CONNECTION_TIMEOUT" }} ########################################################################### # PROCESSORS @@ -126,207 +308,374 @@ AzureStorageSource.chunking.cache.max_size = {{ getv "/azurestoragesource/chunki # Processor Selection #---------------------------------------- -processor.selection_strategy = {{ getv "/processor/selection/strategy" "ManualSelectionStrategy" }} -processor.ManualSelectionStrategy.avi = {{ getv "/processor/manualselectionstrategy/avi" "FfmpegProcessor" }} -processor.ManualSelectionStrategy.bmp = {{ getv "/processor/manualselectionstrategy/bmp" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.dcm = {{ getv "/processor/manualselectionstrategy/dcm" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.gif = {{ getv "/processor/manualselectionstrategy/gif" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.jp2 = {{ getv "/processor/manualselectionstrategy/jp2" "OpenJpegProcessor" }} -processor.ManualSelectionStrategy.jpg = {{ getv "/processor/manualselectionstrategy/jpg" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.mov = {{ getv "/processor/manualselectionstrategy/mov" "FfmpegProcessor" }} -processor.ManualSelectionStrategy.mp4 = {{ getv "/processor/manualselectionstrategy/mp4" "FfmpegProcessor" }} -processor.ManualSelectionStrategy.mpg = {{ getv "/processor/manualselectionstrategy/mpg" "FfmpegProcessor" }} -processor.ManualSelectionStrategy.pdf = {{ getv "/processor/manualselectionstrategy/pdf" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.png = {{ getv "/processor/manualselectionstrategy/png" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.tif = {{ getv "/processor/manualselectionstrategy/tif" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.webm = {{ getv "/processor/manualselectionstrategy/webm" "FfmpegProcessor" }} -processor.ManualSelectionStrategy.webp = {{ getv "/processor/manualselectionstrategy/webp" "ImageMagickProcessor" }} -processor.ManualSelectionStrategy.fallback = {{ getv "/processor/manualselectionstrategy/fallback" "Java2dProcessor" }} +# * If set to `AutomaticSelectionStrategy`, a "best" available processor +# will be selected per-request based on formats and installed +# dependencies. +# * If set to `ManualSelectionStrategy`, a processor will be chosen based +# on the rest of the keys in this section. +processor.selection_strategy = {{ getenv "CANTALOUPE_PROCESSOR_SELECTION_STRATEGY" }} + +# Built-in processors are `Java2dProcessor`, TurboJpegProcessor`, +# `KakaduNativeProcessor`, `OpenJpegProcessor`, `GrokProcessor`,`JaiProcessor`, +# `PdfBoxProcessor`, and `FfmpegProcessor`. +# Some of these have third-party dependencies and won't work out-of-the-box. + +# These format-specific definitions are optional. +processor.ManualSelectionStrategy.avi = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_AVI" }} +processor.ManualSelectionStrategy.bmp = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_BMP" }} +processor.ManualSelectionStrategy.flv = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_FLV" }} +processor.ManualSelectionStrategy.gif = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_GIF" }} +processor.ManualSelectionStrategy.jp2 = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JP2" }} +processor.ManualSelectionStrategy.jpg = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_JPG" }} +processor.ManualSelectionStrategy.mov = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MOV" }} +processor.ManualSelectionStrategy.mp4 = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MP4" }} +processor.ManualSelectionStrategy.mpg = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_MPG" }} +processor.ManualSelectionStrategy.pdf = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_PDF" }} +processor.ManualSelectionStrategy.png = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_PNG" }} +processor.ManualSelectionStrategy.tif = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_TIF" }} +processor.ManualSelectionStrategy.webm = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_WEBM" }} +processor.ManualSelectionStrategy.xpm = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_XPM" }} + +# Fall back to this processor for any formats not assigned above. +processor.ManualSelectionStrategy.fallback = {{ getenv "CANTALOUPE_PROCESSOR_MANUALSELECTIONSTRATEGY_FALLBACK" }} #---------------------------------------- # Global Processor Configuration #---------------------------------------- -processor.dpi = {{ getv "/processor/dpi" "150" }} -processor.normalize = {{ getv "/processor/normalize" "false" }} -processor.background_color = {{ getv "/processor/background/color" "black" }} -processor.downscale_filter = {{ getv "/processor/downscale/filter" "bicubic" }} -processor.upscale_filter = {{ getv "/processor/upscale/filter" "bicubic" }} -processor.sharpen = {{ getv "/processor/sharpen" "0" }} -processor.jpg.progressive = {{ getv "/processor/jpg/progressive" "true" }} -processor.jpg.quality = {{ getv "/processor/jpg/quality" "80" }} -processor.tif.compression = {{ getv "/processor/tif/compression" "LZW" }} -processor.stream_retrieval_strategy = {{ getv "/processor/stream/retrieval/strategy" "StreamStrategy" }} -processor.fallback_retrieval_strategy = {{ getv "/processor/fallback/retrieval/strategy" "DownloadStrategy" }} +# Controls how content is fed to processors from stream-based sources. +# * `StreamStrategy` will try to stream a source image from a source when +# possible, and use `processor.fallback_retrieval_strategy` otherwise. +# * `DownloadStrategy` will download it to a temporary file, and delete +# it after the request is complete. +# * `CacheStrategy` will download it into the source cache using +# FilesystemCache, which must also be configured. (This will perform a +# lot better than DownloadStrategy if you can spare the disk space.) +processor.stream_retrieval_strategy = {{ getenv "CANTALOUPE_PROCESSOR_STREAM_RETRIEVAL_STRATEGY" }} + +# Controls how an incompatible StreamSource + FileProcessor combination is +# dealt with. +# * `DownloadStrategy` and `CacheStrategy` work the same as above. +# * `AbortStrategy` causes the request to fail. +processor.fallback_retrieval_strategy = {{ getenv "CANTALOUPE_PROCESSOR_FALLBACK_RETRIEVAL_STRATEGY" }} + +# Resolution of vector rasterization (of e.g. PDFs) at a scale of 1. +processor.dpi = {{ getenv "CANTALOUPE_PROCESSOR_DPI" }} + +# Color of the background when an image is rotated or alpha-flattened, for +# output formats that don't support transparency. +# This may not be respected for indexed color derivative images. +processor.background_color = {{ getenv "CANTALOUPE_PROCESSOR_BACKGROUND_COLOR" }} + +# Available values are `bell`, `bspline`, `bicubic`, `box`, `hermite`, +# `lanczos3`, `mitchell`, `triangle`. (JaiProcessor & KakaduNativeProcessor +# ignore these.) +processor.downscale_filter = {{ getenv "CANTALOUPE_PROCESSOR_DOWNSCALE_FILTER" }} +processor.upscale_filter = {{ getenv "CANTALOUPE_PROCESSOR_UPSCALE_FILTER" }} + +# If true, images are downscaled in a linear color space, which is more +# accurate. This only works with mono-resolution (non-pyramidal) images. It +# also may impair performance. +processor.downscale_linear = {{ getenv "CANTALOUPE_PROCESSOR_DOWNSCALE_LINEAR" }} + +# Intensity of an unsharp mask from 0 to 1. +processor.sharpen = {{ getenv "CANTALOUPE_PROCESSOR_SHARPEN" }} + +# Progressive JPEGs are usually more compact. +processor.jpg.progressive = {{ getenv "CANTALOUPE_PROCESSOR_JPG_PROGRESSIVE" }} + +# JPEG output quality (1-100). +processor.jpg.quality = {{ getenv "CANTALOUPE_PROCESSOR_JPG_QUALITY" }} + +# TIFF output compression type. Available values are `Deflate`, `JPEG`, +# `LZW`, and `RLE`. Leave blank for no compression. +processor.tif.compression = {{ getenv "CANTALOUPE_PROCESSOR_TIF_COMPRESSION" }} #---------------------------------------- # ImageIO Plugin Preferences #---------------------------------------- -processor.imageio.bmp.reader = {{ getv "/processor/imageio/bmp/reader" "" }} -processor.imageio.gif.reader = {{ getv "/processor/imageio/gif/reader" "" }} -processor.imageio.gif.writer = {{ getv "/processor/imageio/gif/writer" "" }} -processor.imageio.jpg.reader = {{ getv "/processor/imageio/jpg/reader" "" }} -processor.imageio.jpg.writer = {{ getv "/processor/imageio/jpg/writer" "" }} -processor.imageio.png.reader = {{ getv "/processor/imageio/png/reader" "" }} -processor.imageio.png.writer = {{ getv "/processor/imageio/png/writer" "" }} -processor.imageio.tif.reader = {{ getv "/processor/imageio/tif/reader" "" }} -processor.imageio.tif.writer = {{ getv "/processor/imageio/tif/writer" "" }} -processor.imageio.xpm.reader = {{ getv "/processor/imageio/xpm/reader" "" }} +# These override the default plugins used by the application and should not +# normally be changed. +processor.imageio.bmp.reader = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_BMP_READER" }} +processor.imageio.gif.reader = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_GIF_READER" }} +processor.imageio.gif.writer = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_GIF_WRITER" }} +processor.imageio.jpg.reader = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_JPG_READER" }} +processor.imageio.jpg.writer = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_JPG_WRITER" }} +processor.imageio.png.reader = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_PNG_READER" }} +processor.imageio.png.writer = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_PNG_WRITER" }} +processor.imageio.tif.reader = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_TIF_READER" }} +processor.imageio.tif.writer = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_TIF_WRITER" }} +processor.imageio.xpm.reader = {{ getenv "CANTALOUPE_PROCESSOR_IMAGEIO_XPM_READER" }} #---------------------------------------- # FfmpegProcessor #---------------------------------------- -FfmpegProcessor.path_to_binaries = {{ getv "/ffmpegprocessor/path/to/binaries" "" }} +# Optional absolute path of the directory containing the FFmpeg binaries. +# Overrides the PATH. +FfmpegProcessor.path_to_binaries = {{ getenv "CANTALOUPE_FFMPEGPROCESSOR_PATH_TO_BINARIES" }} #---------------------------------------- # OpenJpegProcessor #---------------------------------------- -OpenJpegProcessor.path_to_binaries = {{ getv "/openjpegprocessor/path/to/binaries" "" }} +# Optional absolute path of the directory containing opj_decompress. +# Overrides the PATH. +OpenJpegProcessor.path_to_binaries = {{ getenv "CANTALOUPE_OPENJPEGPROCESSOR_PATH_TO_BINARIES" }} + +#---------------------------------------- +# GrokProcessor +#---------------------------------------- + +# Optional absolute path of the directory containing grk_decompress. +# Overrides the PATH. +GrokProcessor.path_to_binaries = {{ getenv "CANTALOUPE_GROKPROCESSOR_PATH_TO_BINARIES" }} + +#---------------------------------------- +# PdfBoxProcessor +#---------------------------------------- + +# The following will enable disk to be used as well as memory during +# PDF loading in PdfBoxProcessor. If `max_memory_bytes` is -1 it +# will use unlimited memory. +processor.pdf.scratch_file_enabled = {{ getenv "CANTALOUPE_PROCESSOR_PDF_SCRATCH_FILE_ENABLED" }} +processor.pdf.max_memory_bytes = {{ getenv "CANTALOUPE_PROCESSOR_PDF_MAX_MEMORY_BYTES" }} ########################################################################### # CLIENT-SIDE CACHING ########################################################################### -cache.client.enabled = {{ getv "/cache/client/enabled" "true" }} -cache.client.max_age = {{ getv "/cache/client/max/age" "2592000" }} -cache.client.shared_max_age = {{ getv "/cache/client/shared/max/age" "" }} -cache.client.public = {{ getv "/cache/client/public" "true" }} -cache.client.private = {{ getv "/cache/client/private" "false" }} -cache.client.no_cache = {{ getv "/cache/client/no/cache" "false" }} -cache.client.no_store = {{ getv "/cache/client/no/store" "false" }} -cache.client.must_revalidate = {{ getv "/cache/client/must/revalidate" "false" }} -cache.client.proxy_revalidate = {{ getv "/cache/client/proxy/revalidate" "false" }} -cache.client.no_transform = {{ getv "/cache/client/no/transform" "true" }} +# Whether to enable the response Cache-Control header. +cache.client.enabled = {{ getenv "CANTALOUPE_CACHE_CLIENT_ENABLED" }} + +cache.client.max_age = {{ getenv "CANTALOUPE_CACHE_CLIENT_MAX_AGE" }} +cache.client.shared_max_age = {{ getenv "CANTALOUPE_CACHE_CLIENT_SHARED_MAX_AGE" }} +cache.client.public = {{ getenv "CANTALOUPE_CACHE_CLIENT_PUBLIC" }} +cache.client.private = {{ getenv "CANTALOUPE_CACHE_CLIENT_PRIVATE" }} +cache.client.no_cache = {{ getenv "CANTALOUPE_CACHE_CLIENT_NO_CACHE" }} +cache.client.no_store = {{ getenv "CANTALOUPE_CACHE_CLIENT_NO_STORE" }} +cache.client.must_revalidate = {{ getenv "CANTALOUPE_CACHE_CLIENT_MUST_REVALIDATE" }} +cache.client.proxy_revalidate = {{ getenv "CANTALOUPE_CACHE_CLIENT_PROXY_REVALIDATE" }} +cache.client.no_transform = {{ getenv "CANTALOUPE_CACHE_CLIENT_NO_TRANSFORM" }} ########################################################################### # SERVER-SIDE CACHING ########################################################################### -cache.server.source = {{ getv "/cache/server/source" "FilesystemCache" }} -cache.server.source.ttl_seconds = {{ getv "/cache/server/source/ttl/seconds" "2592000" }} -cache.server.derivative.enabled = {{ getv "/cache/server/derivative/enabled" "false" }} -cache.server.derivative = {{ getv "/cache/server/derivative" "" }} -cache.server.derivative.ttl_seconds = {{ getv "/cache/server/derivative/ttl/seconds" "2592000" }} -cache.server.info.enabled = {{ getv "/cache/server/info/enabled" "true" }} -cache.server.purge_missing = {{ getv "/cache/server/purge/missing" "false" }} -cache.server.resolve_first = {{ getv "/cache/server/resolve/first" "false" }} -cache.server.worker.enabled = {{ getv "/cache/server/worker/enabled" "false" }} -cache.server.worker.interval = {{ getv "/cache/server/worker/interval" "86400" }} +# N.B.: The source cache may be used if the +# `processor.stream_retrieval_strategy` and/or +# `processor.fallback_retrieval_strategy` keys are set to `CacheStrategy`. + +# FilesystemCache is the only available source cache. +cache.server.source = {{ getenv "CANTALOUPE_CACHE_SERVER_SOURCE" }} + +# Amount of time source cache content remains valid. Set to blank or 0 +# for forever. +cache.server.source.ttl_seconds = {{ getenv "CANTALOUPE_CACHE_SERVER_SOURCE_TTL_SECONDS" }} + +# Enables the derivative (processed image) cache. +cache.server.derivative.enabled = {{ getenv "CANTALOUPE_CACHE_SERVER_DERIVATIVE_ENABLED" }} + +# Available values are `FilesystemCache`, `JdbcCache`, `RedisCache`, +# `HeapCache`, `S3Cache`, and `AzureStorageCache`. +cache.server.derivative = {{ getenv "CANTALOUPE_CACHE_SERVER_DERIVATIVE" }} + +# Amount of time derivative cache content remains valid. Set to blank or 0 +# for forever. +cache.server.derivative.ttl_seconds = {{ getenv "CANTALOUPE_CACHE_SERVER_DERIVATIVE_TTL_SECONDS" }} + +# Whether to use the Java heap as a "level 1" cache for image infos, either +# independently or in front of a "level 2" derivative cache (if enabled). +cache.server.info.enabled = {{ getenv "CANTALOUPE_CACHE_SERVER_INFO_ENABLED" }} + +# If true, when a source reports that the requested source image has gone +# missing, all cached information relating to it (if any) will be deleted. +# (This is effectively always false when cache.server.resolve_first is also +# false.) +cache.server.purge_missing = {{ getenv "CANTALOUPE_CACHE_SERVER_PURGE_MISSING" }} + +# If true, the source image will be confirmed to exist before a cached copy +# is returned. If false, the cached copy will be returned without checking. +# Resolving first is safer but slower. +cache.server.resolve_first = {{ getenv "CANTALOUPE_CACHE_SERVER_RESOLVE_FIRST" }} + +# !! Enables the cache worker, which periodically purges invalid cache +# items in the background. +cache.server.worker.enabled = {{ getenv "CANTALOUPE_CACHE_SERVER_WORKER_ENABLED" }} + +# !! The cache worker will wait this many seconds before starting its +# next shift. +cache.server.worker.interval = {{ getenv "CANTALOUPE_CACHE_SERVER_WORKER_INTERVAL" }} #---------------------------------------- # FilesystemCache #---------------------------------------- -FilesystemCache.pathname = {{ getv "/filesystemcache/pathname" "/data" }} -FilesystemCache.dir.depth = {{ getv "/filesystemcache/dir/depth" "3" }} -FilesystemCache.dir.name_length = {{ getv "/filesystemcache/dir/name/length" "2" }} +# If this directory does not exist, it will be created automatically. +FilesystemCache.pathname = {{ getenv "CANTALOUPE_FILESYSTEMCACHE_PATHNAME" }} + +# Levels of folder hierarchy in which to store cached images. Deeper depth +# results in fewer files per directory. Set to 0 to disable subdirectories. +# Purge the cache after changing this. +FilesystemCache.dir.depth = {{ getenv "CANTALOUPE_FILESYSTEMCACHE_DIR_DEPTH" }} + +# Number of characters in tree directory names. Should be set to +# 16^n < (max number of directory entries your filesystem can deal with). +# Purge the cache after changing this. +FilesystemCache.dir.name_length = {{ getenv "CANTALOUPE_FILESYSTEMCACHE_DIR_NAME_LENGTH" }} #---------------------------------------- # HeapCache #---------------------------------------- -HeapCache.target_size = {{ getv "/heapcache/target/size" "2G" }} -HeapCache.persist = {{ getv "/heapcache/persist" "false" }} -HeapCache.persist.filesystem.pathname = {{ getv "/heapcache/persist/filesystem/pathname" "/var/cache/cantaloupe/heap.cache" }} +# Target cache size, in bytes or a number ending in M, MB, G, GB, etc. +# This is not a hard limit, and may be transiently exceeded. +# Ensure your heap can accommodate this size. +HeapCache.target_size = {{ getenv "CANTALOUPE_HEAPCACHE_TARGET_SIZE" }} + +# If true, the cache contents will be written to a file on exit and during +# cache worker shifts, and read back in at startup. +HeapCache.persist = {{ getenv "CANTALOUPE_HEAPCACHE_PERSIST" }} + +# When the contents are persisted, this specifies the location of the cache +# file. If the parent directory does not exist, it will be created +# automatically. +HeapCache.persist.filesystem.pathname = {{ getenv "CANTALOUPE_HEAPCACHE_PERSIST_FILESYSTEM_PATHNAME" }} #---------------------------------------- # JdbcCache #---------------------------------------- -JdbcCache.url = {{ getv "/jdbccache/url" "jdbc:postgresql://database:5432/cantaloupe" }} -JdbcCache.user = {{ getv "/jdbccache/user" "admin" }} -JdbcCache.password = {{ getv "/jdbccache/password" "password" }} -JdbcCache.connection_timeout = {{ getv "/jdbccache/connection/timeout" "10" }} -JdbcCache.derivative_image_table = {{ getv "/jdbccache/derivative/image/table" "derivative_cache" }} -JdbcCache.info_table = {{ getv "/jdbccache/info/table" "info_cache" }} +# !! +JdbcCache.url = {{ getenv "CANTALOUPE_JDBCCACHE_URL" }} +# !! +JdbcCache.user = {{ getenv "CANTALOUPE_JDBCCACHE_USER" }} +# !! +JdbcCache.password = {{ getenv "CANTALOUPE_JDBCCACHE_PASSWORD" }} -#---------------------------------------- -# AmazonS3Cache -#---------------------------------------- +# !! Connection timeout in seconds. +JdbcCache.connection_timeout = {{ getenv "CANTALOUPE_JDBCCACHE_CONNECTION_TIMEOUT" }} -AmazonS3Cache.bucket.name = {{ getv "/amazons3cache/bucket/name" "" }}} -AmazonS3Cache.bucket.region = {{ getv "/amazons3cache/bucket/region" "" }}} -AmazonS3Cache.object_key_prefix = {{ getv "/amazons3cache/object/key/prefix" "" }}} +# These must be created manually; see the user manual. +JdbcCache.derivative_image_table = {{ getenv "CANTALOUPE_JDBCCACHE_DERIVATIVE_IMAGE_TABLE" }} +JdbcCache.info_table = {{ getenv "CANTALOUPE_JDBCCACHE_INFO_TABLE" }} #---------------------------------------- # S3Cache #---------------------------------------- -S3Cache.endpoint = {{ getv "/s3cache/endpoint" "" }} -S3Cache.access_key_id = {{ getv "/s3cache/access/key/id" "" }} -S3Cache.secret_key = {{ getv "/s3cache/secret/key" "" }}} -S3Cache.bucket.name = {{ getv "/s3cache/bucket/name" "" }}} -S3Cache.bucket.region = {{ getv "/s3cache/bucket/region" "" }}} -S3Cache.object_key_prefix = {{ getv "/s3cache/object/key/prefix" "" }}} -S3Cache.max_connections = {{ getv "/s3cache/max/connections" "" }}} +# !! Endpoint URI. Only needed for non-AWS endpoints. +S3Cache.endpoint = {{ getenv "CANTALOUPE_S3CACHE_ENDPOINT" }} + +# !! AWS region. Only needed for AWS endpoints. +S3Cache.region = {{ getenv "CANTALOUPE_S3CACHE_REGION" }} +# !! Credentials for your AWS account. +# See: http://aws.amazon.com/security-credentials +# Note that this info can be obtained from elsewhere rather than setting it +# here; see the user manual. +S3Cache.access_key_id = {{ getenv "CANTALOUPE_S3CACHE_ACCESS_KEY_ID" }} +S3Cache.secret_key = {{ getenv "CANTALOUPE_S3CACHE_SECRET_KEY" }} + +# !! Name of a bucket to use to hold cached data. +S3Cache.bucket.name = {{ getenv "CANTALOUPE_S3CACHE_BUCKET_NAME" }} + +# !! String that will be prefixed to object keys. +S3Cache.object_key_prefix = {{ getenv "CANTALOUPE_S3CACHE_OBJECT_KEY_PREFIX" }} #---------------------------------------- # AzureStorageCache #---------------------------------------- -AzureStorageCache.account_name = {{ getv "/azurestoragecache/account/name" "" }} -AzureStorageCache.account_key = {{ getv "/azurestoragecache/account/key" "" }} -AzureStorageCache.container_name = {{ getv "/azurestoragecache/container/name" "" }} -AzureStorageCache.object_key_prefix = {{ getv "/azurestoragecache/object/key/prefix" "" }} +# !! Credentials for your Azure account. +AzureStorageCache.account_name = {{ getenv "CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_NAME" }} +AzureStorageCache.account_key = {{ getenv "CANTALOUPE_AZURESTORAGECACHE_ACCOUNT_KEY" }} -#---------------------------------------- -# RedisCache -#---------------------------------------- +# !! Name of the container containing cached images. +AzureStorageCache.container_name = {{ getenv "CANTALOUPE_AZURESTORAGECACHE_CONTAINER_NAME" }} -RedisCache.host = {{ getv "/rediscache/host" "localhost" }} -RedisCache.port = {{ getv "/rediscache/port" "6379" }} -RedisCache.ssl = {{ getv "/rediscache/ssl" "false" }} -RedisCache.password = {{ getv "/rediscache/password" "" }} -RedisCache.database = {{ getv "/rediscache/database" "0" }} +# !! String that will be prefixed to object keys. +AzureStorageCache.object_key_prefix = {{ getenv "CANTALOUPE_AZURESTORAGECACHE_OBJECT_KEY_PREFIX" }} #---------------------------------------- -# DynamoDBCache +# RedisCache #---------------------------------------- -DynamoDBCache.endpoint = {{ getv "dynamodbcache/endpoint" "" }} -DynamoDBCache.table.name = {{ getv "dynamodbcache/table/name" "CantaloupeDynamoDBCache" }} -DynamoDBCache.access_key_id = {{ getv "dynamodbcache/access/key/id" "" }} -DynamoDBCache.secret_key = {{ getv "dynamodbcache/sectre/key" "" }} +# !! Redis connection info. +RedisCache.host = {{ getenv "CANTALOUPE_REDISCACHE_HOST" }} +RedisCache.port = {{ getenv "CANTALOUPE_REDISCACHE_PORT" }} +RedisCache.ssl = {{ getenv "CANTALOUPE_REDISCACHE_SSL" }} +RedisCache.password = {{ getenv "CANTALOUPE_REDISCACHE_PASSWORD" }} +RedisCache.database = {{ getenv "CANTALOUPE_REDISCACHE_DATABASE" }} ########################################################################### # OVERLAYS ########################################################################### -overlays.enabled = {{ getv "/overlays/enabled" "false" }} -overlays.strategy = {{ getv "/overlays/strategy" "BasicStrategy" }} -overlays.BasicStrategy.type = {{ getv "/overlays/basicstrategy/type" "image" }} -overlays.BasicStrategy.image = {{ getv "/overlays/basicstrategy/image" "/path/to/overlay.png" }} -overlays.BasicStrategy.string = {{ getv "/overlays/basicstrategy/string" "Copyright. All rights reserved." }} -overlays.BasicStrategy.string.font = {{ getv "/overlays/basicstrategy/string/font" "Helvetica" }} -overlays.BasicStrategy.string.font.size = {{ getv "/overlays/basicstrategy/string/font/size" "24" }} -overlays.BasicStrategy.string.font.min_size = {{ getv "/overlays/basicstrategy/string/font/min/size" "18" }} -overlays.BasicStrategy.string.font.weight = {{ getv "/overlays/basicstrategy/string/font/weight" "1.0" }} -overlays.BasicStrategy.string.glyph_spacing = {{ getv "/overlays/basicstrategy/string/glyph/spacing" "0.02" }} -overlays.BasicStrategy.string.color = {{ getv "/overlays/basicstrategy/string/color" "white" }} -overlays.BasicStrategy.string.stroke.color = {{ getv "/overlays/basicstrategy/string/stroke/color" "black" }} -overlays.BasicStrategy.string.stroke.width = {{ getv "/overlays/basicstrategy/string/stroke/width" "1" }} -overlays.BasicStrategy.string.background.color = {{ getv "/overlays/basicstrategy/string/background/color" "rgba(0, 0, 0, 100)" }} -overlays.BasicStrategy.position = {{ getv "/overlays/basicstrategy/position" "bottom right" }} -overlays.BasicStrategy.inset = {{ getv "/overlays/basicstrategy/inset" "10" }} -overlays.BasicStrategy.output_width_threshold = {{ getv "/overlays/basicstrategy/output/width/threshold" "400" }} -overlays.BasicStrategy.output_height_threshold = {{ getv "/overlays/basicstrategy/output/height/threshold" "300" }} +# Controls how overlays are configured. `BasicStrategy` will use the +# `overlays.BasicStrategy.*` keys in this section. `ScriptStrategy` will +# use a delegate method. (See the user manual.) +overlays.strategy = {{ getenv "CANTALOUPE_OVERLAYS_STRATEGY" }} -########################################################################### -# REDACTIONS -########################################################################### +# Whether to enable overlays using the BasicStrategy. +overlays.BasicStrategy.enabled = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_ENABLED" }} -redaction.enabled = {{ getv "/redaction/enabled" "false" }} +# `image` or `string`. +overlays.BasicStrategy.type = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_TYPE" }} -########################################################################### -# METADATA -########################################################################### +# Absolute path or URL of the overlay image. Must be a PNG file. +overlays.BasicStrategy.image = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_IMAGE" }} + +# Overlay text. +overlays.BasicStrategy.string = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING" }} + +# For a list of possible values, launch with the -list-fonts argument. +overlays.BasicStrategy.string.font = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT" }} + +# Font size in points. +overlays.BasicStrategy.string.font.size = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_SIZE" }} + +# If the string doesn't fit in the image at the above size, the largest size +# at which it does fit will be used, down to this. +overlays.BasicStrategy.string.font.min_size = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_MIN_SIZE" }} + +# Font weight. 1 = regular, 2 = bold. Unfortunately, many fonts don't +# support fractional weights. +overlays.BasicStrategy.string.font.weight = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_FONT_WEIGHT" }} + +# Point spacing between glyphs, typically between -0.1 and 0.1. +overlays.BasicStrategy.string.glyph_spacing = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_GLYPH_SPACING" }} + +# CSS color syntax is supported. +overlays.BasicStrategy.string.color = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_COLOR" }} -metadata.preserve = {{ getv "/metadata/preserve" "false" }} -metadata.respect_orientation = {{ getv "/metadata/respect/orientation" "false" }} +# CSS color syntax is supported. +overlays.BasicStrategy.string.stroke.color = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_COLOR" }} + +# Stroke width in pixels. +overlays.BasicStrategy.string.stroke.width = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_STROKE_WIDTH" }} + +# Color of a rectangular background to draw under the string. +# CSS color syntax and alpha are supported. +overlays.BasicStrategy.string.background.color = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_STRING_BACKGROUND_COLOR" }} + +# Allowed values: `top left`, `top center`, `top right`, `left center`, +# `center`, `right center`, `bottom left`, `bottom center`, `bottom right`, +# `repeat` (images only), `scaled` (images only). +overlays.BasicStrategy.position = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_POSITION" }} + +# Pixel margin between the overlay and the image edge. Does not apply to +# `repeat` position. +overlays.BasicStrategy.inset = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_INSET" }} + +# Output images less than this many pixels wide will not receive an overlay. +# Set to 0 to add the overlay regardless. +overlays.BasicStrategy.output_width_threshold = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_WIDTH_THRESHOLD" }} + +# Output images less than this many pixels tall will not receive an overlay. +# Set to 0 to add the overlay regardless. +overlays.BasicStrategy.output_height_threshold = {{ getenv "CANTALOUPE_OVERLAYS_BASICSTRATEGY_OUTPUT_HEIGHT_THRESHOLD" }} ########################################################################### # LOGGING @@ -336,50 +685,70 @@ metadata.respect_orientation = {{ getv "/metadata/respect/orientation" "false" } # Application Log #---------------------------------------- -log.application.level = {{ getv "/log/application/level" "debug" }} -log.application.ConsoleAppender.enabled = {{ getv "/log/application/consoleappender/enabled" "false" }} -log.application.ConsoleAppender.logstash.enabled = {{ getv "/log/application/consoleappender/logstash/enabled" "false" }} -log.application.FileAppender.enabled = {{ getv "/log/application/fileappender/enabled" "false" }} -log.application.FileAppender.logstash.enabled = {{ getv "/log/application/fileappender/logstash/enabled" "false" }} -log.application.FileAppender.pathname = {{ getv "/log/application/fileappender/pathname" "/opt/tomcat/logs/cantaloupe.application.log" }} -log.application.RollingFileAppender.enabled = {{ getv "/log/application/rollingfileappender/enabled" "true" }} -log.application.RollingFileAppender.logstash.enabled = {{ getv "/log/application/rollingfileappender/logstash/enabled" "false" }} -log.application.RollingFileAppender.pathname = {{ getv "/log/application/rollingfileappender/pathname" "/opt/tomcat/logs/cantaloupe.application.log" }} -log.application.RollingFileAppender.policy = {{ getv "/log/application/rollingfileappender/policy" "TimeBasedRollingPolicy" }} -log.application.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getv "/log/application/rollingfileappender/timebasedrollingpolicy/filename/pattern" "/opt/tomcat/logs/cantaloupe.application-%d{yyyy-MM-dd}.log" }} -log.application.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getv "/log/application/rollingfileappender/timebasedrollingpolicy/max/history" "30" }} -log.application.SyslogAppender.enabled = {{ getv "/log/application/syslogappender/enabled" "false" }} -log.application.SyslogAppender.host = {{ getv "/log/application/syslogappender/host" "" }} -log.application.SyslogAppender.port = {{ getv "/log/application/syslogappender/port" "514" }} -log.application.SyslogAppender.facility = {{ getv "/log/application/syslogappender/facility" "LOCAL0" }} +# `trace`, `debug`, `info`, `warn`, `error`, `all`, or `off` +log.application.level = {{ getenv "CANTALOUPE_LOG_APPLICATION_LEVEL" }} +log.application.ConsoleAppender.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_ENABLED" }} +log.application.ConsoleAppender.logstash.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_CONSOLEAPPENDER_LOGSTASH_ENABLED" }} + +# N.B.: Don't enable FileAppender and RollingFileAppender simultaneously! +log.application.FileAppender.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_ENABLED" }} +log.application.FileAppender.logstash.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_LOGSTASH_ENABLED" }} +log.application.FileAppender.pathname = {{ getenv "CANTALOUPE_LOG_APPLICATION_FILEAPPENDER_PATHNAME" }} + +log.application.RollingFileAppender.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_ENABLED" }} +log.application.RollingFileAppender.logstash.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_LOGSTASH_ENABLED" }} +log.application.RollingFileAppender.pathname = {{ getenv "CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_PATHNAME" }} +log.application.RollingFileAppender.policy = {{ getenv "CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_POLICY" }} +log.application.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getenv "CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN" }} +log.application.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getenv "CANTALOUPE_LOG_APPLICATION_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY" }} + +# See the "SyslogAppender" section for a list of facilities: +# http://logback.qos.ch/manual/appenders.html +log.application.SyslogAppender.enabled = {{ getenv "CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_ENABLED" }} +log.application.SyslogAppender.host = {{ getenv "CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_HOST" }} +log.application.SyslogAppender.port = {{ getenv "CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_PORT" }} +log.application.SyslogAppender.facility = {{ getenv "CANTALOUPE_LOG_APPLICATION_SYSLOGAPPENDER_FACILITY" }} #---------------------------------------- # Error Log #---------------------------------------- -log.error.FileAppender.enabled = {{ getv "/log/error/fileappender/enabled" "false" }} -log.error.FileAppender.logstash.enabled = {{ getv "/log/error/fileappender/logstash/enabled" "false" }} -log.error.FileAppender.pathname = {{ getv "/log/error/fileappender/pathname" "/opt/tomcat/logs/cantaloupe.error.log" }} -log.error.RollingFileAppender.enabled = {{ getv "/log/error/rollingfileappender/enabled" "true" }} -log.error.RollingFileAppender.logstash.enabled = {{ getv "/log/error/rollingfileappender/logstash/enabled" "false" }} -log.error.RollingFileAppender.pathname = {{ getv "/log/error/rollingfileappender/pathname" "/opt/tomcat/logs/cantaloupe.error.log" }} -log.error.RollingFileAppender.policy = {{ getv "/log/error/rollingfileappender/policy" "TimeBasedRollingPolicy" }} -log.error.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getv "/log/error/rollingfileappender/timebasedrollingpolicy/filename/pattern" "/opt/tomcat/logs/cantaloupe.error-%d{yyyy-MM-dd}.log" }} -log.error.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getv "/log/error/rollingfileappender/timebasedrollingpolicy/max/history" "30" }} +# Application log messages with a severity of WARN or greater can be copied +# into a dedicated error log, which may make them easier to spot. + +# N.B.: Don't enable FileAppender and RollingFileAppender simultaneously! +log.error.FileAppender.enabled = {{ getenv "CANTALOUPE_LOG_ERROR_FILEAPPENDER_ENABLED" }} +log.error.FileAppender.logstash.enabled = {{ getenv "CANTALOUPE_LOG_ERROR_FILEAPPENDER_LOGSTASH_ENABLED" }} +log.error.FileAppender.pathname = {{ getenv "CANTALOUPE_LOG_ERROR_FILEAPPENDER_PATHNAME" }} + +log.error.RollingFileAppender.enabled = {{ getenv "CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_ENABLED" }} +log.error.RollingFileAppender.logstash.enabled = {{ getenv "CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_LOGSTASH_ENABLED" }} +log.error.RollingFileAppender.pathname = {{ getenv "CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_PATHNAME" }} +log.error.RollingFileAppender.policy = {{ getenv "CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_POLICY" }} +log.error.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getenv "CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN" }} +log.error.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getenv "CANTALOUPE_LOG_ERROR_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY" }} #---------------------------------------- # Access Log #---------------------------------------- -log.access.ConsoleAppender.enabled = {{ getv "/log/access/consoleappender/enabled" "false" }} -log.access.FileAppender.enabled = {{ getv "/log/access/fileappender/enabled" "false" }} -log.access.FileAppender.pathname = {{ getv "/log/access/fileappender/pathname" "/opt/tomcat/logs/cantaloupe.access.log" }} -log.access.RollingFileAppender.enabled = {{ getv "/log/access/rollingfileappender/enabled" "true" }} -log.access.RollingFileAppender.pathname = {{ getv "/log/access/rollingfileappender/pathname" "/opt/tomcat/logs/cantaloupe.access.log" }} -log.access.RollingFileAppender.policy = {{ getv "/log/access/rollingfileappender/policy" "TimeBasedRollingPolicy" }} -log.access.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getv "/log/access/rollingfileappender/timebasedrollingpolicy/filename/pattern" "/opt/tomcat/logs/cantaloupe.access-%d{yyyy-MM-dd}.log" }} -log.access.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getv "/log/access/rollingfileappender/timebasedrollingpolicy/max/history" "30" }} -log.access.SyslogAppender.enabled = {{ getv "/log/access/syslogappender/enabled" "false" }} -log.access.SyslogAppender.host = {{ getv "/log/access/syslogappender/host" "" }} -log.access.SyslogAppender.port = {{ getv "/log/access/syslogappender/port" "514" }} -log.access.SyslogAppender.facility = {{ getv "/log/access/syslogappender/facility" "LOCAL0" }} +log.access.ConsoleAppender.enabled = {{ getenv "CANTALOUPE_LOG_ACCESS_CONSOLEAPPENDER_ENABLED" }} + +# N.B.: Don't enable FileAppender and RollingFileAppender simultaneously! +log.access.FileAppender.enabled = {{ getenv "CANTALOUPE_LOG_ACCESS_FILEAPPENDER_ENABLED" }} +log.access.FileAppender.pathname = {{ getenv "CANTALOUPE_LOG_ACCESS_FILEAPPENDER_PATHNAME" }} + +# RollingFileAppender is an alternative to using something like +# FileAppender + logrotate. +log.access.RollingFileAppender.enabled = {{ getenv "CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_ENABLED" }} +log.access.RollingFileAppender.pathname = {{ getenv "CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_PATHNAME" }} +log.access.RollingFileAppender.policy = {{ getenv "CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_POLICY" }} +log.access.RollingFileAppender.TimeBasedRollingPolicy.filename_pattern = {{ getenv "CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_FILENAME_PATTERN" }} +log.access.RollingFileAppender.TimeBasedRollingPolicy.max_history = {{ getenv "CANTALOUPE_LOG_ACCESS_ROLLINGFILEAPPENDER_TIMEBASEDROLLINGPOLICY_MAX_HISTORY" }} + +# See the "SyslogAppender" section for a list of facilities: +# http://logback.qos.ch/manual/appenders.html +log.access.SyslogAppender.enabled = {{ getenv "CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_ENABLED" }} +log.access.SyslogAppender.host = {{ getenv "CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_HOST" }} +log.access.SyslogAppender.port = {{ getenv "CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_PORT" }} +log.access.SyslogAppender.facility = {{ getenv "CANTALOUPE_LOG_ACCESS_SYSLOGAPPENDER_FACILITY" }} diff --git a/cantaloupe/rootfs/etc/confd/templates/setenv.sh.tmpl b/cantaloupe/rootfs/etc/confd/templates/setenv.sh.tmpl deleted file mode 100755 index b46973fa..00000000 --- a/cantaloupe/rootfs/etc/confd/templates/setenv.sh.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -export JAVA_OPTS="{{ getv "/java/opts" "" }}" -export CATALINA_OPTS="{{ getv "/catalina/opts" "" }}" -export CATALINA_OPTS="${CATALINA_OPTS} -Dcantaloupe.config=/opt/tomcat/conf/cantaloupe.properties" -export CATALINA_OPTS="${CATALINA_OPTS} -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true" -export CATALINA_OPTS="${CATALINA_OPTS} -Dorg.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true" diff --git a/cantaloupe/rootfs/etc/cont-init.d/02-cantoloupe-install.sh b/cantaloupe/rootfs/etc/cont-init.d/02-cantoloupe-install.sh deleted file mode 100755 index 6a271751..00000000 --- a/cantaloupe/rootfs/etc/cont-init.d/02-cantoloupe-install.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -e - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /opt/tomcat/logs/cantaloupe.access.log -chown tomcat:tomcat /opt/tomcat/logs/cantaloupe.access.log - -ln -sf /dev/stderr /opt/tomcat/logs/cantaloupe.error.log -chown tomcat:tomcat /opt/tomcat/logs/cantaloupe.error.log diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/dependencies.d/ready b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/finish b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/run b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/run new file mode 100755 index 00000000..ac871195 --- /dev/null +++ b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/run @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e + +# When bind mounting we need to ensure that we +# actually can write to the folder. +chown cantaloupe:cantaloupe /data + +exec s6-setuidgid cantaloupe java -Dcantaloupe.config=/opt/cantaloupe/cantaloupe.properties -jar /opt/cantaloupe/cantaloupe.jar diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/type b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe/type @@ -0,0 +1 @@ +longrun diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/cantaloupe b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/cantaloupe new file mode 100644 index 00000000..e69de29b diff --git a/cantaloupe/rootfs/opt/cantaloupe/delegates.rb b/cantaloupe/rootfs/opt/cantaloupe/delegates.rb new file mode 100644 index 00000000..e75df76c --- /dev/null +++ b/cantaloupe/rootfs/opt/cantaloupe/delegates.rb @@ -0,0 +1,389 @@ +## +# Sample Ruby delegate script containing stubs and documentation for all +# available delegate methods. See the user manual for more information. +# +# The application will create an instance of this class early in the request +# cycle and dispose of it at the end of the request cycle. Instances don't need +# to be thread-safe, but sharing information across instances (requests) +# **does** need to be done thread-safely. +# +# This version of the script works with Cantaloupe version >= 5. +# +class CustomDelegate + + ## + # Attribute for the request context, which is a hash containing information + # about the current request. + # + # This attribute will be set by the server before any other methods are + # called. Methods can access its keys like: + # + # ``` + # identifier = context['identifier'] + # ``` + # + # The hash will contain the following keys in response to all requests: + # + # * `client_ip` [String] Client IP address. + # * `cookies` [Hash] Hash of cookie name-value pairs. + # * `full_size` [Hash] Hash with `width` and `height` + # keys corresponding to the pixel dimensions of the + # source image. + # * `identifier` [String] Image identifier. + # * `local_uri` [String] URI seen by the application, which may be + # different from `request_uri` when operating behind a + # reverse-proxy server. + # * `metadata` [Hash] Embedded image metadata. Object + # structure varies depending on the source image. + # See the `metadata()` method. + # * `page_count` [Integer] Page count. + # * `page_number` [Integer] Page number. + # * `request_headers` [Hash] Hash of header name-value pairs. + # * `request_uri` [String] URI requested by the client. + # * `scale_constraint` [Array] Two-element array with scale + # constraint numerator at position 0 and denominator at + # position 1. + # + # It will contain the following additional string keys in response to image + # requests, after the image has been accessed: + # + # * `operations` [Array>] Array of operations in + # order of application. Only operations that are not + # no-ops will be included. Every hash contains a `class` + # key corresponding to the operation class name, which + # will be one of the `e.i.l.c.operation.Operation` + # implementations. + # * `output_format` [String] Output format media (MIME) type. + # * `resulting_size` [Hash] Hash with `width` and `height` + # keys corresponding to the pixel dimensions of the + # resulting image after all operations have been applied. + # + # @return [Hash] Request context. + # + attr_accessor :context + + ## + # Deserializes the given meta-identifier string into a hash of its component + # parts. + # + # This method is used only when the `meta_identifier.transformer` + # configuration key is set to `DelegateMetaIdentifierTransformer`. + # + # The hash contains the following keys: + # + # * `identifier` [String] Required. + # * `page_number` [Integer] Optional. + # * `scale_constraint` [Array] Two-element array with scale + # constraint numerator at position 0 and denominator at + # position 1. Optional. + # + # @param meta_identifier [String] + # @return Hash See above. The return value should be + # compatible with the argument to + # {serialize_meta_identifier}. + # + def deserialize_meta_identifier(meta_identifier) + end + + ## + # Serializes the given meta-identifier hash. + # + # This method is used only when the `meta_identifier.transformer` + # configuration key is set to `DelegateMetaIdentifierTransformer`. + # + # See {deserialize_meta_identifier} for a description of the hash structure. + # + # @param components [Hash] + # @return [String] Serialized meta-identifier compatible with the argument to + # {deserialize_meta_identifier}. + # + def serialize_meta_identifier(components) + end + + ## + # Returns authorization status for the current request. This method is called + # upon all requests to all public endpoints early in the request cycle, + # before the image has been accessed. This means that some context keys (like + # `full_size`) will not be available yet. + # + # This method should implement all possible authorization logic except that + # which requires any of the context keys that aren't yet available. This will + # ensure efficient authorization failures. + # + # Implementations should assume that the underlying resource is available, + # and not try to check for it. + # + # Possible return values: + # + # 1. Boolean true/false, indicating whether the request is fully authorized + # or not. If false, the client will receive a 403 Forbidden response. + # 2. Hash with a `status_code` key. + # a. If it corresponds to an integer from 200-299, the request is + # authorized. + # b. If it corresponds to an integer from 300-399: + # i. If the hash also contains a `location` key corresponding to a + # URI string, the request will be redirected to that URI using + # that code. + # ii. If the hash also contains `scale_numerator` and + # `scale_denominator` keys, the request will be + # redirected using that code to a virtual reduced-scale version of + # the source image. + # c. If it corresponds to 401, the hash must include a `challenge` key + # corresponding to a WWW-Authenticate header value. + # + # @param options [Hash] Empty hash. + # @return [Boolean,Hash] See above. + # + def pre_authorize(options = {}) + true + end + + ## + # Returns authorization status for the current request. Will be called upon + # all requests to all public image (not information) endpoints. + # + # This is a counterpart of `pre_authorize()` that is invoked later in the + # request cycle, once more information about the underlying image has become + # available. It should only contain logic that depends on context keys that + # contain information about the source image (like `full_size`, `metadata`, + # etc.) + # + # Implementations should assume that the underlying resource is available, + # and not try to check for it. + # + # @param options [Hash] Empty hash. + # @return [Boolean,Hash] See the documentation of + # `pre_authorize()`. + # + def authorize(options = {}) + true + end + + ## + # Adds additional keys to an Image API 2.x information response. See the + # [IIIF Image API 2.1](http://iiif.io/api/image/2.1/#image-information) + # specification and "endpoints" section of the user manual. + # + # @param options [Hash] Empty hash. + # @return [Hash] Hash to merge into an Image API 2.x information response. + # Return an empty hash to add nothing. + # + def extra_iiif2_information_response_keys(options = {}) + {} + end + + ## + # Adds additional keys to an Image API 3.x information response. See the + # [IIIF Image API 3.0](http://iiif.io/api/image/3.0/#image-information) + # specification and "endpoints" section of the user manual. + # + # @param options [Hash] Empty hash. + # @return [Hash] Hash to merge into an Image API 3.x information response. + # Return an empty hash to add nothing. + # + def extra_iiif3_information_response_keys(options = {}) + {} + end + + ## + # Tells the server which source to use for the given identifier. + # + # @param options [Hash] Empty hash. + # @return [String] Source name. + # + def source(options = {}) + end + + ## + # N.B.: this method should not try to perform authorization. `authorize()` + # should be used instead. + # + # @param options [Hash] Empty hash. + # @return [String,nil] Blob key of the image corresponding to the given + # identifier, or nil if not found. + # + def azurestoragesource_blob_key(options = {}) + end + + ## + # N.B.: this method should not try to perform authorization. `authorize()` + # should be used instead. + # + # @param options [Hash] Empty hash. + # @return [String,nil] Absolute pathname of the image corresponding to the + # given identifier, or nil if not found. + # + def filesystemsource_pathname(options = {}) + end + + ## + # Returns one of the following: + # + # 1. String URI + # 2. Hash with the following keys: + # * `uri` [String] (required) + # * `username` [String] For HTTP Basic authentication (optional). + # * `secret` [String] For HTTP Basic authentication (optional). + # * `headers` [Hash] Hash of request headers (optional). + # 3. nil if not found. + # + # N.B.: this method should not try to perform authorization. `authorize()` + # should be used instead. + # + # @param options [Hash] Empty hash. + # @return See above. + # + def httpsource_resource_info(options = {}) + return { "uri" => context['identifier'], "headers" => { "authorization" => context['request_headers']['authorization'] } } + end + + ## + # N.B.: this method should not try to perform authorization. `authorize()` + # should be used instead. + # + # @param options [Hash] Empty hash. + # @return [String] Identifier of the image corresponding to the given + # identifier in the database. + # + def jdbcsource_database_identifier(options = {}) + end + + ## + # Returns either the media (MIME) type of an image, or an SQL statement that + # can be used to retrieve it, if it is stored in the database. In the latter + # case, the "SELECT" and "FROM" clauses should be in uppercase in order to + # be autodetected. If nil is returned, the media type will be inferred some + # other way, such as by identifier extension or magic bytes. + # + # @param options [Hash] Empty hash. + # @return [String, nil] + # + def jdbcsource_media_type(options = {}) + end + + ## + # @param options [Hash] Empty hash. + # @return [String] SQL statement that selects the BLOB corresponding to the + # value returned by `jdbcsource_database_identifier()`. + # + def jdbcsource_lookup_sql(options = {}) + end + + ## + # N.B.: this method should not try to perform authorization. `authorize()` + # should be used instead. + # + # @param options [Hash] Empty hash. + # @return [Hash,nil] Hash containing `bucket` and `key` keys; + # or nil if not found. + # + def s3source_object_info(options = {}) + end + + ## + # Tells the server what overlay, if any, to apply to an image. Called upon + # all image requests to any endpoint if overlays are enabled and the overlay + # strategy is set to `ScriptStrategy` in the application configuration. + # + # Return values: + # + # 1. For string overlays, a hash with the following keys: + # * `background_color` [String] CSS-compliant RGA(A) color. + # * `color` [String] CSS-compliant RGA(A) color. + # * `font` [String] Font name. Launch with the -list-fonts + # argument to see a list of available fonts. + # * `font_min_size` [Integer] Minimum font size in points (ignored + # when `word_wrap` is true). + # * `font_size` [Integer] Font size in points. + # * `font_weight` [Float] Font weight based on 1. + # * `glyph_spacing` [Float] Glyph spacing based on 0. + # * `inset` [Integer] Pixels of inset. + # * `position` [String] Position like `top left`, `center right`, + # etc. + # * `string` [String] String to draw. + # * `stroke_color` [String] CSS-compliant RGB(A) text outline color. + # * `stroke_width` [Float] Text outline width in pixels. + # * `word_wrap` [Boolean] Whether to wrap long lines within + # `string`. + # 2. For image overlays, a hash with the following keys: + # * `image` [String] Image pathname or URL. + # * `position` [String] See above. + # * `inset` [Integer] See above. + # 3. nil for no overlay. + # + # @param options [Hash] Empty hash. + # @return See above. + # + def overlay(options = {}) + end + + ## + # Tells the server what regions of an image to redact in response to a + # particular request. Will be called upon all image requests to any endpoint. + # + # @param options [Hash] Empty hash. + # @return [Array>] Array of hashes, each with `x`, `y`, + # `width`, and `height` keys; or an empty array if no redactions are + # to be applied. + # + def redactions(options = {}) + [] + end + + ## + # Returns XMP metadata to embed in the derivative image. + # + # Source image metadata is available in the `metadata` context key, and has + # the following structure: + # + # ``` + # { + # "exif": { + # "tagSet": "Baseline TIFF", + # "fields": { + # "Field1Name": value, + # "Field2Name": value, + # "EXIFIFD": { + # "tagSet": "EXIF", + # "fields": { + # "Field1Name": value, + # "Field2Name": value + # } + # } + # } + # }, + # "iptc": [ + # "Field1Name": value, + # "Field2Name": value + # ], + # "xmp_string": "...", + # "xmp_model": https://jena.apache.org/documentation/javadoc/jena/org/apache/jena/rdf/model/Model.html + # "native": { + # # structure varies + # } + # } + # ``` + # + # * The `exif` key refers to embedded EXIF data. This also includes IFD0 + # metadata from source TIFFs, whether or not an EXIF IFD is present. + # * The `iptc` key refers to embedded IPTC IIM data. + # * The `xmp_string` key refers to raw embedded XMP data, which may or may + # not contain EXIF and/or IPTC information. + # * The `xmp_model` key contains a Jena Model object pre-loaded with the + # contents of `xmp_string`. + # * The `native` key refers to format-specific metadata. + # + # Any combination of the above keys may be present or missing depending on + # what is available in a particular source image. + # + # Only XMP can be embedded in derivative images. See the user manual for + # examples of working with the XMP model programmatically. + # + # @return [String,Model,nil] String or Jena model containing XMP data to + # embed in the derivative image, or nil to not + # embed anything. + # + def metadata(options = {}) + end + +end diff --git a/cantaloupe/tests/ServiceStartsWithDefaults/build.gradle.kts b/cantaloupe/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..5c987e66 --- /dev/null +++ b/cantaloupe/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("cantaloupe", 0, 143) +} diff --git a/cantaloupe/tests/ServiceStartsWithDefaults/docker-compose.yml b/cantaloupe/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..dcbe11fa --- /dev/null +++ b/cantaloupe/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: cantaloupe-servicestartswithdefaults +services: + cantaloupe: + <<: *common + image: ${CANTALOUPE:-islandora/cantaloupe:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/cantaloupe/tests/ServiceStartsWithDefaults/test.sh b/cantaloupe/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..7f062504 --- /dev/null +++ b/cantaloupe/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,10 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +wait_20x "http://localhost:8182" + +# Service must start for us to get to this point. +exit 0 diff --git a/code-server/Dockerfile b/code-server/Dockerfile new file mode 100644 index 00000000..a5bb490e --- /dev/null +++ b/code-server/Dockerfile @@ -0,0 +1,102 @@ +# syntax=docker/dockerfile:1.5.1 +FROM drupal + +ARG TARGETARCH + +ARG GLIBC_VERSION="2.35-r1" +ARG GLIBC_FILE="glibc-${GLIBC_VERSION}.apk" +ARG GLIBC_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/${GLIBC_FILE}" +ARG GLIBC_SHA256="276f43ce9b2d5878422bca94ca94e882a7eb263abe171d233ac037201ffcaf06" + +EXPOSE 8443 \ + 9003 + +RUN --mount=type=bind,source=rootfs/var/lib/nginx/.composer,target=/composer \ + --mount=type=cache,id=code-server-composer-${TARGETARCH},sharing=locked,target=/var/lib/nginx/.composer/cache \ + mkdir -p /var/lib/nginx/.composer && \ + cp -r /composer/* /var/lib/nginx/.composer && \ + ls -lah /var/lib/nginx/.composer && \ + composer install -n -d /var/lib/nginx/.composer && \ + cleanup.sh + +# Include commonly used tools and xdebug. +# PHPStorm remote requries Glibc. +RUN --mount=type=cache,id=code-server-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ + alpine-sdk \ + docker-cli \ + htop \ + nodejs \ + openssh \ + parallel \ + php81-pecl-xdebug \ + python3 \ + spdlog \ + sudo \ + unison \ + yarn \ + && \ + wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \ + download.sh \ + --url "${GLIBC_URL}" \ + --sha256 "${GLIBC_SHA256}" \ + && \ + apk add "${DOWNLOAD_CACHE_DIRECTORY}/${GLIBC_FILE}" && \ + mkdir /lib64 && \ + ln -s /lib/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2 && \ + cleanup.sh + +RUN --mount=type=cache,id=code-server-npm-${TARGETARCH},sharing=locked,target=/usr/local/share/.cache/yarn \ + yarn global add node-gyp@9.3.1 && \ + FORCE_NODE_VERSION=18 yarn global add --ignore-engines --unsafe-perm \ + @microsoft/1ds-core-js@3.2.9 \ + code-server@4.11.0 \ + minimist@1.2.8 \ + node-gyp@9.3.1 \ + spdlog@0.13.7 \ + yauzl@2.10.0 \ + yazl@2.5.1 \ + && \ + cleanup.sh + +# Drush requires HOME to be set as such. +ENV \ + HOME="/var/lib/nginx" \ + PATH=$PATH:/var/lib/nginx/.composer/vendor/bin:/var/www/drupal/vendor/bin + +# Code server / xdebug settings. +ENV \ + CODE_SERVER_AUTHENTICATION=password \ + CODE_SERVER_PASSWORD=password \ + XDEBUG_FLAGS="-d xdebug.mode=develop,debug" + +COPY --link rootfs / + +# Install Editor plugins from bind mounted folder (Not available on online marketplace). +RUN --mount=type=bind,source=/extensions,target=/extensions \ + declare -a PIDS=() EXTENSIONS=(/extensions/*.vsix); \ + EXTENSIONS+=(\ + bmewburn.vscode-intelephense-client \ + felixfbecker.php-debug \ + streetsidesoftware.code-spell-checker \ + mblode.twig-language-2 \ + ) && \ + mkdir -p /opt/code-server/data /opt/code-server/extensions; \ + for extension in "${EXTENSIONS[@]}"; \ + do \ + code-server \ + --config /opt/code-server/config.yaml \ + --user-data-dir /opt/code-server/data \ + --extensions-dir /opt/code-server/extensions \ + --install-extension="${extension}"; \ + done; \ + chown -R nginx:nginx /opt/code-server && \ + cleanup.sh + +# Set a default shell so it can be used via code-server. +# Additionally https://github.com/sudo-project/sudo/issues/42 +RUN sed -i "/nginx:x:100:101:nginx:\/var\/lib\/nginx:\/sbin\/nologin/cnginx:x:100:101:nginx:/var/lib/nginx:/bin/bash" /etc/passwd && \ + mkdir -p /var/lib/nginx/.local && \ + chown -R nginx:nginx /var/lib/nginx && \ + chmod a=r,u+w /etc/sudo.conf && \ + cleanup.sh diff --git a/code-server/README.md b/code-server/README.md new file mode 100644 index 00000000..0dff3373 --- /dev/null +++ b/code-server/README.md @@ -0,0 +1,75 @@ +# Coder + +Docker image for [code-server] 4.8.3. + +Please refer to the [code-server Documentation] for more in-depth information. + +Allows for shared development environment hosted in the browser. + +Adds some debugging utilities and changes `nginx` and `php-fpm` configuration +such that two `php` processes run, one with `xdebug` and one without. The +`xdebug` process will be used if `XDEBUG_SESSION` cookie is present in the +request otherwise it will go to the much faster `non-xdebug` process. + +## Requirements + +For a good experience, it is recommended at least: + +- 1 GB of RAM +- 2 cores + +## Dependencies + +Requires `islandora/drupal` docker image to build. Please refer to the +[Drupal Image README](../drupal/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Ports + +| Port | Description | +| :--- | :---------- | +| 80 | Nginx | +| 8443 | Code server | +| 9003 | XDebug | + +## Volumes + +| Path | Description | +| :-------------------- | :---------------- | +| /opt/code-server/data | code-server cache | + +It is expected that this image will be used in conjunction with the +[drupal image]. Such that the [code-server] container is responsible for serving +the `Drupal` site as well as hosting `xdebug`, and [code-server]. + +To achieve the the Drupal should create a volume for the Drupal root and any of +any of its public / private file volumes. These volumes can then be mounted at +the same locations within the [code-server] container with the `nocopy` flag +set. Also make sure your create the `Drupal` container before the [code-server] +container so the volumes are correctly populated with content from the `Drupal` +image. + +## Settings + +### Code Server + +| Environment Variable | Default | Description | +| :------------------------- | :------- | :------------------------------------------------------------- | +| CODE_SERVER_AUTHENTICATION | password | Must be either 'none' or 'password' | +| CODE_SERVER_PASSWORD | password | Only used if `CODE_SERVER_AUTHENTICATION` is set to 'password' | + +Code server provides shell access to the server on which it is running, for that +reason **never** use it in a situation where it is accessible publicly from the +internet without setting a strong password. Or alternatively do not use a +password and instead use port forwarding so that it is inaccessible publicly. + +### XDebug + +| Environment Variable | Default | Description | +| :------------------- | :--------------------------- | :------------------------------------------------------------------------- | +| XDEBUG_FLAGS | -d xdebug.mode=develop,debug | See [XDebug Documentation] for settings, and prefix each setting with `-d` | + +[drupal image]: ../drupal/README.md +[code-server]: https://github.com/cdr/code-server +[code-server Documentation]: https://github.com/cdr/code-server +[XDebug Documentation]: https://xdebug.org/docs/all_settings diff --git a/code-server/extensions/README.md b/code-server/extensions/README.md new file mode 100644 index 00000000..70b58cd1 --- /dev/null +++ b/code-server/extensions/README.md @@ -0,0 +1,11 @@ +# Extensions + +[Code Server](https://github.com/cdr/code-server) has its own marketplace for +extensions separate from Microsoft's due to Terms of Service. Sometimes +extensions we want to use are only available in Microsoft's marketplace in which +case we can download them and place them in this folder to get them installed. +This does not violate the TOS oddly enough though but installing directly +through Code Server does. + +- +- diff --git a/code-server/extensions/ValeryanM.vscode-phpsab-0.0.16.vsix b/code-server/extensions/ValeryanM.vscode-phpsab-0.0.16.vsix new file mode 100644 index 00000000..1f185799 Binary files /dev/null and b/code-server/extensions/ValeryanM.vscode-phpsab-0.0.16.vsix differ diff --git a/code-server/extensions/augustocdias.tasks-shell-input-1.8.2.vsix b/code-server/extensions/augustocdias.tasks-shell-input-1.8.2.vsix new file mode 100644 index 00000000..12b2e4b1 Binary files /dev/null and b/code-server/extensions/augustocdias.tasks-shell-input-1.8.2.vsix differ diff --git a/code-server/rootfs/etc/confd/conf.d/drupal.fpm.conf.toml b/code-server/rootfs/etc/confd/conf.d/drupal.fpm.conf.toml new file mode 100644 index 00000000..f83a1508 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/drupal.fpm.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "drupal.fpm.conf.tmpl" +dest = "/etc/nginx/shared/drupal.fpm.conf" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/conf.d/launch.json.toml b/code-server/rootfs/etc/confd/conf.d/launch.json.toml new file mode 100644 index 00000000..1427db78 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/launch.json.toml @@ -0,0 +1,7 @@ +[template] +src = "launch.json.tmpl" +dest = "/var/www/drupal/.vscode/launch.json" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/conf.d/phpcs.xml.toml b/code-server/rootfs/etc/confd/conf.d/phpcs.xml.toml new file mode 100644 index 00000000..1531d817 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/phpcs.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "phpcs.xml.tmpl" +dest = "/var/www/drupal/phpcs.xml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/conf.d/services.yml.toml b/code-server/rootfs/etc/confd/conf.d/services.yml.toml new file mode 100644 index 00000000..f337d4e4 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/services.yml.toml @@ -0,0 +1,7 @@ +[template] +src = "services.yml.tmpl" +dest = "/var/www/drupal/web/sites/default/services.yml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/conf.d/settings.json.toml b/code-server/rootfs/etc/confd/conf.d/settings.json.toml new file mode 100644 index 00000000..cb1878a2 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/settings.json.toml @@ -0,0 +1,7 @@ +[template] +src = "settings.json.tmpl" +dest = "/var/www/drupal/.vscode/settings.json" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/conf.d/settings.local.php.toml b/code-server/rootfs/etc/confd/conf.d/settings.local.php.toml new file mode 100644 index 00000000..57c85823 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/settings.local.php.toml @@ -0,0 +1,7 @@ +[template] +src = "settings.local.php.tmpl" +dest = "/var/www/drupal/web/sites/default/settings.local.php" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/conf.d/tasks.json.toml b/code-server/rootfs/etc/confd/conf.d/tasks.json.toml new file mode 100644 index 00000000..bb451e17 --- /dev/null +++ b/code-server/rootfs/etc/confd/conf.d/tasks.json.toml @@ -0,0 +1,7 @@ +[template] +src = "tasks.json.tmpl" +dest = "/var/www/drupal/.vscode/tasks.json" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/code-server/rootfs/etc/confd/templates/drupal.fpm.conf.tmpl b/code-server/rootfs/etc/confd/templates/drupal.fpm.conf.tmpl new file mode 100644 index 00000000..fa451a57 --- /dev/null +++ b/code-server/rootfs/etc/confd/templates/drupal.fpm.conf.tmpl @@ -0,0 +1,41 @@ +# Allow for toggling between xdebug / production configured fpm. +set $fpm php-fpm81; +if ($cookie_XDEBUG_SESSION) { + set $fpm xdebug; +} + +# In Drupal 8, we must also match new paths where the '.php' appears in +# the middle, such as update.php/selection. The rule we use is strict, +# and only allows this pattern with the update.php front controller. +# This allows legacy path aliases in the form of +# blog/index.php/legacy-path to continue to route to Drupal nodes. If +# you do not have any paths like that, then you might prefer to use a +# laxer rule, such as: +# location ~ \.php(/|$) { +# The laxer rule will continue to work if Drupal uses this new URL +# pattern with front controllers other than update.php in a future +# release. +location ~ '\.php$|^/update.php' { + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + # Ensure the php file exists. Mitigates CVE-2019-11043 + try_files $fastcgi_script_name =404; + # Security note: If you're running a version of PHP older than the + # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. + # See http://serverfault.com/q/627903/94922 for details. + include fastcgi_params; + # Block httpoxy attacks. See https://httpoxy.org/. + fastcgi_param HTTP_PROXY ""; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + {{ if eq (getenv "DRUPAL_ENABLE_HTTPS") "true" }} + fastcgi_param HTTPS on; + fastcgi_param HTTP_SCHEME https; + {{ end }} + fastcgi_intercept_errors on; + # Large Islandora repositories global searches end up with HUGE header sizes + fastcgi_buffers 16 800k; + fastcgi_buffer_size 1600k; + # PHP 8 socket location. + fastcgi_pass unix:/var/run/$fpm/php-fpm81.sock; +} diff --git a/code-server/rootfs/etc/confd/templates/launch.json.tmpl b/code-server/rootfs/etc/confd/templates/launch.json.tmpl new file mode 100644 index 00000000..aa6a0787 --- /dev/null +++ b/code-server/rootfs/etc/confd/templates/launch.json.tmpl @@ -0,0 +1,26 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for XDebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/var/www/drupal": "/var/www/drupal", + }, + "xdebugSettings": {"max_data": 128, "max_children": 1024} + }, + { + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 9003 + } + ] +} diff --git a/code-server/rootfs/etc/confd/templates/phpcs.xml.tmpl b/code-server/rootfs/etc/confd/templates/phpcs.xml.tmpl new file mode 100644 index 00000000..fcfadf16 --- /dev/null +++ b/code-server/rootfs/etc/confd/templates/phpcs.xml.tmpl @@ -0,0 +1,26 @@ + + + CodeSniffer configuration + + + + + web/modules/custom + web/themes/custom + + vendor + web/core + web/includes + web/misc + web/libraries + + *.gif + *.less + *.png + + *.min.css + *.min.js + + + + diff --git a/code-server/rootfs/etc/confd/templates/services.yml.tmpl b/code-server/rootfs/etc/confd/templates/services.yml.tmpl new file mode 100644 index 00000000..80d2070a --- /dev/null +++ b/code-server/rootfs/etc/confd/templates/services.yml.tmpl @@ -0,0 +1,4 @@ +parameters: + twig.config: + auto_reload: true + debug: true diff --git a/code-server/rootfs/etc/confd/templates/settings.json.tmpl b/code-server/rootfs/etc/confd/templates/settings.json.tmpl new file mode 100644 index 00000000..c17b8868 --- /dev/null +++ b/code-server/rootfs/etc/confd/templates/settings.json.tmpl @@ -0,0 +1,127 @@ +{ + // The number of spaces a tab is equal to. This setting is overridden + // based on the file contents when `editor.detectIndentation` is true. + "editor.tabSize": 2, + // Insert spaces when pressing Tab. This setting is overriden + // based on the file contents when `editor.detectIndentation` is true. + "editor.insertSpaces": true, + // When opening a file, `editor.tabSize` and `editor.insertSpaces` + // will be detected based on the file contents. Set to false to keep + // the values you've explicitly set, above. + "editor.detectIndentation": false, + // Exclude files from watch + "files.watcherExclude": { + "**/.git": true, + "**/node_modules": true, + "**/vendor": true, + "/var/www/drupal/config": true, + "/var/www/drupal/web/core": true, + "/var/www/drupal/web/files": true, + "/var/www/drupal/web/libraries": true, + "/var/www/drupal/web/modules/contrib": true, + "/var/www/drupal/web/themes/contrib": true + }, + "cSpell.words": [ + "abuild", + "accordian", + "allprojects", + "archden", + "awslogs", + "awsvpc", + "bmuschko", + "buildscript", + "cachetags", + "classpath", + "CONFIGDIR", + "deepmerge", + "destid", + "destructured", + "Devel", + "dhparam", + "drush", + "edtf", + "fastcheck", + "Fieldable", + "filehash", + "filemime", + "filesize", + "frontpage", + "fullchain", + "fulltext", + "geolocation", + "gradlew", + "hashicorp", + "hostnames", + "iiif", + "imagemagick", + "islandora", + "jsonencode", + "langcode", + "leaderboard", + "letsencrypt", + "loadbalancer", + "lsdir", + "middlewares", + "mixins", + "mkdir", + "MULTIVALUE", + "musl", + "oclc", + "oembed", + "openseadragon", + "openwire", + "phpcs", + "postgresql", + "Pregistry", + "Prepository", + "printf", + "privkey", + "readmore", + "recurse", + "Renderable", + "replacen", + "Seadragon", + "Serializable", + "setintersection", + "setsubstract", + "setsubtract", + "shortcodes", + "simpletest", + "slidedown", + "sourceid", + "Submodule", + "submodules", + "subprojects", + "tabledrag", + "textfield", + "tomap", + "tonumber", + "toset", + "uikit", + "xargs", + "Xdebug", + "xlarge", + "zipmap" + ], + "files.associations": { + "*.inc": "php", + "*.install": "php", + "*.module": "php", + "*.profile": "php", + "*.theme": "php", + "*.env": "shellscript" + }, + "php.suggest.basic": true, + "php.validate.enable": false, + "phpsab.executablePathCS": "/var/lib/nginx/.composer/vendor/bin/phpcs", + "phpsab.executablePathCBF": "/var/lib/nginx/.composer/vendor/bin/phpcbf", + "phpsab.standard": "/var/www/drupal/phpcs.xml", + "phpsab.autoRulesetSearch": false, + "phpsab.snifferShowSources": true, + "phpsab.debug": true, + "[php]": { + "editor.defaultFormatter": "valeryanm.vscode-phpsab" + }, + "intelephense.environment.phpVersion": "7.3.0", + "intelephense.environment.documentRoot": "/var/www/drupal/web" +} diff --git a/code-server/rootfs/etc/confd/templates/settings.local.php.tmpl b/code-server/rootfs/etc/confd/templates/settings.local.php.tmpl new file mode 100644 index 00000000..73671ab1 --- /dev/null +++ b/code-server/rootfs/etc/confd/templates/settings.local.php.tmpl @@ -0,0 +1,155 @@ +=5.3", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", + "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + }, + "time": "2022-02-04T12:51:07+00:00" + }, + { + "name": "drupal/coder", + "version": "8.3.16", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/coder.git", + "reference": "d6f6112e5e84ff4f6baaada223c93dadbd6d3887" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1", + "ext-mbstring": "*", + "php": ">=7.1", + "sirbrillig/phpcs-variable-analysis": "^2.11.7", + "slevomat/coding-standard": "^7.0 || ^8.0", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/yaml": ">=3.4.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.7.12", + "phpunit/phpunit": "^7.0 || ^8.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Drupal\\": "coder_sniffer/Drupal/", + "DrupalPractice\\": "coder_sniffer/DrupalPractice/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "Coder is a library to review Drupal code.", + "homepage": "https://www.drupal.org/project/coder", + "keywords": [ + "code review", + "phpcs", + "standards" + ], + "support": { + "issues": "https://www.drupal.org/project/issues/coder", + "source": "https://www.drupal.org/project/coder" + }, + "time": "2022-08-20T17:31:46+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.15.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "61800f71a5526081d1b5633766aa88341f1ade76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/61800f71a5526081d1b5633766aa88341f1ade76", + "reference": "61800f71a5526081d1b5633766aa88341f1ade76", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.15.3" + }, + "time": "2022-12-20T20:56:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/phpcpd", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-12-07T05:39:23+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "sirbrillig/phpcs-variable-analysis", + "version": "v2.11.10", + "source": { + "type": "git", + "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", + "reference": "0f25a3766f26df91d6bdda0c8931303fc85499d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/0f25a3766f26df91d6bdda0c8931303fc85499d7", + "reference": "0f25a3766f26df91d6bdda0c8931303fc85499d7", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "squizlabs/php_codesniffer": "^3.5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpcsstandards/phpcsdevcs": "^1.1", + "phpstan/phpstan": "^1.7", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0", + "sirbrillig/phpcs-import-detection": "^1.1", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0@beta" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "VariableAnalysis\\": "VariableAnalysis/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Sam Graham", + "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" + } + ], + "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], + "support": { + "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", + "source": "https://github.com/sirbrillig/phpcs-variable-analysis", + "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" + }, + "time": "2023-01-05T18:45:16+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.8.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "59e25146a4ef0a7b194c5bc55b32dd414345db89" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/59e25146a4ef0a7b194c5bc55b32dd414345db89", + "reference": "59e25146a4ef0a7b194c5bc55b32dd414345db89", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": ">=1.15.2 <1.16.0", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.4.10|1.9.6", + "phpstan/phpstan-deprecation-rules": "1.1.1", + "phpstan/phpstan-phpunit": "1.0.0|1.3.3", + "phpstan/phpstan-strict-rules": "1.4.4", + "phpunit/phpunit": "7.5.20|8.5.21|9.5.27" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.8.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2023-01-09T10:46:13+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2022-06-18T07:21:10+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/yaml", + "version": "v6.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3", + "reference": "6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<5.4" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v6.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-12-14T16:11:27+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/code-server/tests/ServiceStartsWithDefaults/build.gradle.kts b/code-server/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..3a8f7341 --- /dev/null +++ b/code-server/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("code-server", 0, 143) +} diff --git a/code-server/tests/ServiceStartsWithDefaults/docker-compose.yml b/code-server/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..664d87e1 --- /dev/null +++ b/code-server/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: code-server-servicestartswithdefaults +services: + code-server: + <<: *common + image: ${CODE_SERVER:-islandora/code-server:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/code-server/tests/ServiceStartsWithDefaults/test.sh b/code-server/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..481716d0 --- /dev/null +++ b/code-server/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,7 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +wait_20x "http://localhost:8443/" + +# Service must start for us to get to this point. +exit 0 diff --git a/crayfish/.dockerignore b/crayfish/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/crayfish/.dockerignore +++ b/crayfish/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/crayfish/Dockerfile b/crayfish/Dockerfile index 1e69bfe7..3493e098 100644 --- a/crayfish/Dockerfile +++ b/crayfish/Dockerfile @@ -1,24 +1,21 @@ -# syntax=docker/dockerfile:experimental -FROM local/nginx:latest +# syntax=docker/dockerfile:1.5.1 +FROM nginx -ARG COMMIT=1.1.1 +# When updating this commit also update the lock files in rootfs/var/www/crayfish. +ARG TARGETARCH +ARG COMMIT=d4bc375c6dd9c6df6bb4fa088629a2f8b7cf5cce +ARG FILE=${COMMIT}.tar.gz +ARG URL=https://github.com/Islandora/Crayfish/archive/${FILE} +ARG SHA256=3b4c144a98b4ed4d1fd9a6395a4e3484ecbb89cac144142d3fc187bc0e5c130a -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - git-clone-cached.sh \ - --url https://github.com/Islandora/Crayfish.git \ - --cache-dir "${DOWNLOAD_CACHE_DIRECTORY}" \ - --commit "${COMMIT}" \ - --worktree /var/www/crayfish && \ - mkdir /var/log/islandora && \ - mkdir -p /opt/keys/jwt && \ - chown nginx:nginx /var/log/islandora && \ - chown nginx:nginx /opt/keys/jwt && \ - chown -R nginx:nginx /var/www && \ +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=crayfish-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${URL}" \ + --sha256 "${SHA256}" \ + --strip \ + --dest "/var/www/crayfish" \ + && \ cleanup.sh -COPY /rootfs / - -STOPSIGNAL SIGWINCH - -EXPOSE 8000 +COPY --link rootfs / diff --git a/crayfish/README.md b/crayfish/README.md index cc51cf6e..4b423097 100644 --- a/crayfish/README.md +++ b/crayfish/README.md @@ -1,9 +1,9 @@ # Crayfish -Docker image for [Crayfish] version 1.1.1. +Docker image for [Crayfish] (**unreleased version**). Acts as base Docker image for Crayfish based micro-services. It is not meant to -be run on its own. +be run on its own it is only used to cache the download. ## Dependencies @@ -19,13 +19,68 @@ additional settings, volumes, ports, etc. ## Settings -> N.B. For all of the settings below images that descend from -> ``islandora/crayfish`` will apply prefix to every setting. So for example -> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for -> different settings on a per-service basis. +### JWT Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :--------------- | :-------- | :---------- | -| JWT_ADMIN_TOKEN | /jwt/admin/token | islandora | JWT Token | +[Crayfish] makes use of JWT for authentication. Please see the documentation in +the [base image] for more information. +## Updating + +You can change the commit used for crayfish by modifying the build argument +`COMMIT` and `SHA256` in the `Dockerfile` shown as `XXXXXXXXXXXX` in the +following snippet: + +```Dockerfile +ARG COMMIT=XXXXXXXXXXXX +#... +ARG SHA256=XXXXXXXXXXXX +``` + +You can generate the `SHA256` with the following commands: + +```bash +COMMIT=$(cat crayfish/Dockerfile | grep -o 'COMMIT=.*' | cut -f2 -d=) +FILE=$(cat crayfish/Dockerfile | grep -o 'FILE=.*' | cut -f2 -d=) +URL=$(cat crayfish/Dockerfile | grep -o 'URL=.*' | cut -f2 -d=) +FILE=$(eval "echo $FILE") +URL=$(eval "echo $URL") +wget --quiet "${URL}" +shasum -a 256 "${FILE}" | cut -f1 -d' ' +rm "${FILE}" +``` + +When changing the `COMMIT` and `SHA256` be sure to also update the composer lock files, this +can be done with the following commands: + +```bash +make bake TARGET=crayfish + +docker run --rm -ti \ + -v $(pwd)/crayfish/rootfs/var/www/crayfish/Recast/composer.lock:/var/www/crayfish/Recast/composer.lock \ + --entrypoint ash islandora.dev/crayfish:latest -c \ + "cd /var/www/crayfish/Recast && composer update" + +docker run --rm -ti \ + -v $(pwd)/crayfish/rootfs/var/www/crayfish/Homarus/composer.lock:/var/www/crayfish/Homarus/composer.lock \ + --entrypoint ash islandora.dev/crayfish:latest -c \ + "cd /var/www/crayfish/Homarus && composer update" + +docker run --rm -ti \ + -v $(pwd)/crayfish/rootfs/var/www/crayfish/Hypercube/composer.lock:/var/www/crayfish/Hypercube/composer.lock \ + --entrypoint ash islandora.dev/crayfish:latest -c \ + "cd /var/www/crayfish/Hypercube && composer update" + +docker run --rm -ti \ + -v $(pwd)/crayfish/rootfs/var/www/crayfish/Houdini/composer.lock:/var/www/crayfish/Houdini/composer.lock \ + --entrypoint ash islandora.dev/crayfish:latest -c \ + "cd /var/www/crayfish/Houdini && composer update" + +docker run --rm -ti \ + -v $(pwd)/crayfish/rootfs/var/www/crayfish/Milliner/composer.lock:/var/www/crayfish/Milliner/composer.lock \ + --entrypoint ash islandora.dev/crayfish:latest -c \ + "cd /var/www/crayfish/Milliner && composer update" +``` + +[base image]: ../base/README.md +[nginx image]: ../nginx/README.md [Crayfish]: https://github.com/Islandora/Crayfish/tree/main diff --git a/crayfish/rootfs/etc/confd/conf.d/default.conf.toml b/crayfish/rootfs/etc/confd/conf.d/default.conf.toml deleted file mode 100644 index 1df8dbe5..00000000 --- a/crayfish/rootfs/etc/confd/conf.d/default.conf.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "default.conf.tmpl" -dest = "/etc/nginx/conf.d/default.conf" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/" ] diff --git a/crayfish/rootfs/etc/confd/conf.d/public.key.toml b/crayfish/rootfs/etc/confd/conf.d/public.key.toml deleted file mode 100644 index e7765b34..00000000 --- a/crayfish/rootfs/etc/confd/conf.d/public.key.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "public.key.tmpl" -dest = "/opt/keys/jwt/public.key" -uid = 100 -gid = 101 -mode = "0600" -keys = [ "/jwt" ] diff --git a/crayfish/rootfs/etc/confd/conf.d/syn-settings.xml.toml b/crayfish/rootfs/etc/confd/conf.d/syn-settings.xml.toml deleted file mode 100644 index bf5d102e..00000000 --- a/crayfish/rootfs/etc/confd/conf.d/syn-settings.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "syn-settings.xml.tmpl" -dest = "/var/www/crayfish/syn-settings.xml" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/jwt" ] diff --git a/crayfish/rootfs/etc/confd/templates/syn-settings.xml.tmpl b/crayfish/rootfs/etc/confd/templates/syn-settings.xml.tmpl deleted file mode 100644 index 004fed2e..00000000 --- a/crayfish/rootfs/etc/confd/templates/syn-settings.xml.tmpl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - {{ getv "/jwt/admin/token" "islandora" }} - - diff --git a/crayfish/rootfs/etc/confd/templates/default.conf.tmpl b/crayfish/rootfs/etc/nginx/http.d/default.conf similarity index 79% rename from crayfish/rootfs/etc/confd/templates/default.conf.tmpl rename to crayfish/rootfs/etc/nginx/http.d/default.conf index b9df4e91..8d2884f5 100644 --- a/crayfish/rootfs/etc/confd/templates/default.conf.tmpl +++ b/crayfish/rootfs/etc/nginx/http.d/default.conf @@ -6,10 +6,10 @@ server { location / { # try to serve file directly, fallback to index.php try_files $uri /index.php$is_args$args; - } - + } + location ~ ^/index\.php(/|$) { - fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; + fastcgi_pass unix:/var/run/php-fpm81/php-fpm81.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; @@ -27,3 +27,6 @@ server { return 404; } } +# Required for Nginx service to validate that fpm is working. +# @see nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check +include /etc/nginx/shared/fpm.server.conf; diff --git a/crayfish/rootfs/var/www/crayfish/Homarus/composer.lock b/crayfish/rootfs/var/www/crayfish/Homarus/composer.lock new file mode 100644 index 00000000..37c0a730 --- /dev/null +++ b/crayfish/rootfs/var/www/crayfish/Homarus/composer.lock @@ -0,0 +1,6921 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "8880bc3443c28a32f82a27b39ea5a3f6", + "packages": [ + { + "name": "easyrdf/easyrdf", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/easyrdf/easyrdf.git", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-xmlreader": "*", + "lib-libxml": "*", + "php": ">=7.1.0" + }, + "require-dev": { + "code-lts/doctum": "^5", + "ml/json-ld": "~1.0", + "phpunit/phpunit": "^7", + "semsol/arc2": "^2.4", + "squizlabs/php_codesniffer": "3.*", + "zendframework/zend-http": "~2.3" + }, + "suggest": { + "ml/json-ld": "~1.0", + "semsol/arc2": "~2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "EasyRdf\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nicholas Humfrey", + "email": "njh@aelius.com", + "homepage": "http://www.aelius.com/njh/", + "role": "Developer" + }, + { + "name": "Alexey Zakhlestin", + "email": "indeyets@gmail.com", + "homepage": "http://indeyets.ru/", + "role": "Developer" + } + ], + "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.", + "homepage": "http://www.easyrdf.org/", + "keywords": [ + "Linked Data", + "RDF", + "Semantic Web", + "Turtle", + "rdfa", + "sparql" + ], + "support": { + "forum": "http://groups.google.com/group/easyrdf/", + "issues": "http://github.com/easyrdf/easyrdf/issues", + "source": "https://github.com/easyrdf/easyrdf/tree/1.1.1" + }, + "time": "2020-12-02T08:47:31+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-20T21:43:03+00:00" + }, + { + "name": "islandora/chullo", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/chullo.git", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/chullo/zipball/a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "shasum": "" + }, + "require": { + "easyrdf/easyrdf": "^0.9 || ^1", + "guzzlehttp/guzzle": "^6.1.0", + "ml/json-ld": "^1.0.4", + "php": ">=7.3" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^9.0", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Islandora\\Chullo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + }, + { + "name": "Nick Ruest", + "email": "ruestn@gmail.com", + "role": "Maintainer" + } + ], + "description": "A PHP client for interacting with a Fedora 4 server.", + "homepage": "https://github.com/Islandora/chullo", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/chullo/tree/1.3.0" + }, + "time": "2021-12-16T22:31:48+00:00" + }, + { + "name": "islandora/crayfish-commons", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/Crayfish-Commons.git", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/Crayfish-Commons/zipball/e7b8cbd5951286897507f6cfd3e6356201d24f48", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48", + "shasum": "" + }, + "require": { + "islandora/chullo": "^1.0", + "namshi/jose": "^7.2", + "psr/log": "^1.0.1", + "symfony/config": "4.4.*", + "symfony/dependency-injection": "4.4.*", + "symfony/event-dispatcher": "4.4.*", + "symfony/http-foundation": "4.4.*", + "symfony/monolog-bundle": "^3.4", + "symfony/security-bundle": "4.4.*", + "symfony/yaml": "4.4.*" + }, + "conflict": { + "symfony/symfony": "*" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "4.4.*" + }, + "type": "symfony-bundle", + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.4.*" + } + }, + "autoload": { + "psr-4": { + "Islandora\\Crayfish\\Commons\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + } + ], + "description": "Shared code amongst Islandora Crayfish microservices", + "homepage": "https://github.com/Islandora/Crayfish-Commons", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/Crayfish-Commons/tree/3.0.0" + }, + "time": "2022-05-05T15:46:41+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "time": "2022-09-29T08:45:17+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "namshi/jose", + "version": "7.2.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.5", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpseclib/phpseclib": "^2.0", + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "suggest": { + "ext-openssl": "Allows to use OpenSSL as crypto engine.", + "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "Namshi\\JOSE\\": "src/Namshi/JOSE/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "support": { + "issues": "https://github.com/namshi/jose/issues", + "source": "https://github.com/namshi/jose/tree/master" + }, + "time": "2016-12-05T07:27:31+00:00" + }, + { + "name": "psr/cache", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/2.0.0" + }, + "time": "2021-02-03T23:23:37+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-17T20:21:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4.26|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-16T16:18:09+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-25T10:21:52+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:35:46+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-12-20T07:19:24+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T16:17:57+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/inflector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/inflector.git", + "reference": "66185be61805b1e44a5c4000929e700228d426cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/inflector/zipball/66185be61805b1e44a5c4000929e700228d426cc", + "reference": "66185be61805b1e44a5c4000929e700228d426cc", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts words between their singular and plural forms (English only)", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "support": { + "source": "https://github.com/symfony/inflector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "EnglishInflector from the String component", + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/ad09c9980b912e757c4ecd8363cebf3039d1d471", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-16T12:12:11+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/property-access", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/d49682f6f0764df725c95128213a38f7e0a9f358", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/inflector": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/cache": "^3.4|^4.0|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/076fd2088ada33d760758d98ff07ddedbf567946", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^4.4", + "symfony/security-csrf": "^4.2|^5.0", + "symfony/security-guard": "^4.2|^5.0", + "symfony/security-http": "^4.4.50" + }, + "conflict": { + "symfony/browser-kit": "<4.2", + "symfony/console": "<3.4", + "symfony/framework-bundle": "<4.4", + "symfony/ldap": "<4.4", + "symfony/twig-bundle": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/twig-bridge": "^3.4|^4.0|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/security-core", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/423ccb332784b236dfe6c5f396d0ac49db57c914", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1|^2", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/ldap": "<4.4", + "symfony/security-guard": "<4.3" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/ldap": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/validator": "^3.4.31|^4.3.4|^5.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-22T05:50:33+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "45c956ef58135091f53732646a0acd28034f02c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/45c956ef58135091f53732646a0acd28034f02c0", + "reference": "45c956ef58135091f53732646a0acd28034f02c0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^3.4|^4.0|^5.0" + }, + "conflict": { + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/http-foundation": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/security-guard", + "version": "v4.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-guard.git", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/f199eb1b19db11ce254b891580728c45a7ccacfd", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/security-core": "^3.4.22|^4.2.3|^5.0", + "symfony/security-http": "^4.4.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Guard\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Guard", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-guard/tree/v4.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-23T06:06:49+00:00" + }, + { + "name": "symfony/security-http", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4.8" + }, + "conflict": { + "symfony/event-dispatcher": ">=5", + "symfony/security-csrf": "<3.4.11|~4.0,<4.0.11" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/security-csrf": "^3.4.11|^4.0.11|^5.0" + }, + "suggest": { + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-27T11:44:32+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/inflector", + "version": "2.0.6", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", + "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.6" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2022-10-20T09:10:12+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + }, + "time": "2022-10-14T12:47:21+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.17.0" + }, + "time": "2023-02-02T15:41:36+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.0.1" + }, + "time": "2020-07-09T08:33:42+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-01-26T08:26:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-04T13:37:15+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/phpcpd", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-12-07T05:39:23+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2022-06-18T07:21:10+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-25T12:56:14+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T17:10:16+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b8daf6c56801e6d664224261cb100b73edc78a5", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-03T12:57:57+00:00" + }, + { + "name": "symfony/maker-bundle", + "version": "v1.39.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/maker-bundle.git", + "reference": "30c8ac13511f6df7bc9ac088f31d7a48ce6433c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/30c8ac13511f6df7bc9ac088f31d7a48ce6433c6", + "reference": "30c8ac13511f6df7bc9ac088f31d7a48ce6433c6", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.2|^2.0", + "nikic/php-parser": "^4.11", + "php": ">=7.1.3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/deprecation-contracts": "^2.2|^3", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/framework-bundle": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0" + }, + "require-dev": { + "composer/semver": "^3.0", + "doctrine/doctrine-bundle": "^1.12.3|^2.0", + "doctrine/orm": "^2.3", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4|^5.0|^6.0", + "symfony/polyfill-php80": "^1.16.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/security-core": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0", + "twig/twig": "^2.0|^3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-main": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MakerBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.", + "homepage": "https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html", + "keywords": [ + "code generator", + "generator", + "scaffold", + "scaffolding" + ], + "support": { + "issues": "https://github.com/symfony/maker-bundle/issues", + "source": "https://github.com/symfony/maker-bundle/tree/v1.39.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-13T18:14:36+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b3378a7d305666a69e08457b65af8bca179fbbbb", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0" + }, + "suggest": { + "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/phpunit-bridge/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-08T14:39:54+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/crayfish/rootfs/var/www/crayfish/Houdini/composer.lock b/crayfish/rootfs/var/www/crayfish/Houdini/composer.lock new file mode 100644 index 00000000..b30922a3 --- /dev/null +++ b/crayfish/rootfs/var/www/crayfish/Houdini/composer.lock @@ -0,0 +1,6652 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "6a8b2c6137d62616d92358a36b58fd5a", + "packages": [ + { + "name": "easyrdf/easyrdf", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/easyrdf/easyrdf.git", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-xmlreader": "*", + "lib-libxml": "*", + "php": ">=7.1.0" + }, + "require-dev": { + "code-lts/doctum": "^5", + "ml/json-ld": "~1.0", + "phpunit/phpunit": "^7", + "semsol/arc2": "^2.4", + "squizlabs/php_codesniffer": "3.*", + "zendframework/zend-http": "~2.3" + }, + "suggest": { + "ml/json-ld": "~1.0", + "semsol/arc2": "~2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "EasyRdf\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nicholas Humfrey", + "email": "njh@aelius.com", + "homepage": "http://www.aelius.com/njh/", + "role": "Developer" + }, + { + "name": "Alexey Zakhlestin", + "email": "indeyets@gmail.com", + "homepage": "http://indeyets.ru/", + "role": "Developer" + } + ], + "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.", + "homepage": "http://www.easyrdf.org/", + "keywords": [ + "Linked Data", + "RDF", + "Semantic Web", + "Turtle", + "rdfa", + "sparql" + ], + "support": { + "forum": "http://groups.google.com/group/easyrdf/", + "issues": "http://github.com/easyrdf/easyrdf/issues", + "source": "https://github.com/easyrdf/easyrdf/tree/1.1.1" + }, + "time": "2020-12-02T08:47:31+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-20T21:43:03+00:00" + }, + { + "name": "islandora/chullo", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/chullo.git", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/chullo/zipball/a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "shasum": "" + }, + "require": { + "easyrdf/easyrdf": "^0.9 || ^1", + "guzzlehttp/guzzle": "^6.1.0", + "ml/json-ld": "^1.0.4", + "php": ">=7.3" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^9.0", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Islandora\\Chullo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + }, + { + "name": "Nick Ruest", + "email": "ruestn@gmail.com", + "role": "Maintainer" + } + ], + "description": "A PHP client for interacting with a Fedora 4 server.", + "homepage": "https://github.com/Islandora/chullo", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/chullo/tree/1.3.0" + }, + "time": "2021-12-16T22:31:48+00:00" + }, + { + "name": "islandora/crayfish-commons", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/Crayfish-Commons.git", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/Crayfish-Commons/zipball/e7b8cbd5951286897507f6cfd3e6356201d24f48", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48", + "shasum": "" + }, + "require": { + "islandora/chullo": "^1.0", + "namshi/jose": "^7.2", + "psr/log": "^1.0.1", + "symfony/config": "4.4.*", + "symfony/dependency-injection": "4.4.*", + "symfony/event-dispatcher": "4.4.*", + "symfony/http-foundation": "4.4.*", + "symfony/monolog-bundle": "^3.4", + "symfony/security-bundle": "4.4.*", + "symfony/yaml": "4.4.*" + }, + "conflict": { + "symfony/symfony": "*" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "4.4.*" + }, + "type": "symfony-bundle", + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.4.*" + } + }, + "autoload": { + "psr-4": { + "Islandora\\Crayfish\\Commons\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + } + ], + "description": "Shared code amongst Islandora Crayfish microservices", + "homepage": "https://github.com/Islandora/Crayfish-Commons", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/Crayfish-Commons/tree/3.0.0" + }, + "time": "2022-05-05T15:46:41+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "time": "2022-09-29T08:45:17+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "namshi/jose", + "version": "7.2.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.5", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpseclib/phpseclib": "^2.0", + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "suggest": { + "ext-openssl": "Allows to use OpenSSL as crypto engine.", + "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "Namshi\\JOSE\\": "src/Namshi/JOSE/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "support": { + "issues": "https://github.com/namshi/jose/issues", + "source": "https://github.com/namshi/jose/tree/master" + }, + "time": "2016-12-05T07:27:31+00:00" + }, + { + "name": "psr/cache", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/2.0.0" + }, + "time": "2021-02-03T23:23:37+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-17T20:21:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4.26|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-16T16:18:09+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-25T10:21:52+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:35:46+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-12-20T07:19:24+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T16:17:57+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/inflector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/inflector.git", + "reference": "66185be61805b1e44a5c4000929e700228d426cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/inflector/zipball/66185be61805b1e44a5c4000929e700228d426cc", + "reference": "66185be61805b1e44a5c4000929e700228d426cc", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts words between their singular and plural forms (English only)", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "support": { + "source": "https://github.com/symfony/inflector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "EnglishInflector from the String component", + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/ad09c9980b912e757c4ecd8363cebf3039d1d471", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-16T12:12:11+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/property-access", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/d49682f6f0764df725c95128213a38f7e0a9f358", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/inflector": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/cache": "^3.4|^4.0|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/076fd2088ada33d760758d98ff07ddedbf567946", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^4.4", + "symfony/security-csrf": "^4.2|^5.0", + "symfony/security-guard": "^4.2|^5.0", + "symfony/security-http": "^4.4.50" + }, + "conflict": { + "symfony/browser-kit": "<4.2", + "symfony/console": "<3.4", + "symfony/framework-bundle": "<4.4", + "symfony/ldap": "<4.4", + "symfony/twig-bundle": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/twig-bridge": "^3.4|^4.0|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/security-core", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/423ccb332784b236dfe6c5f396d0ac49db57c914", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1|^2", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/ldap": "<4.4", + "symfony/security-guard": "<4.3" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/ldap": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/validator": "^3.4.31|^4.3.4|^5.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-22T05:50:33+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "45c956ef58135091f53732646a0acd28034f02c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/45c956ef58135091f53732646a0acd28034f02c0", + "reference": "45c956ef58135091f53732646a0acd28034f02c0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^3.4|^4.0|^5.0" + }, + "conflict": { + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/http-foundation": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/security-guard", + "version": "v4.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-guard.git", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/f199eb1b19db11ce254b891580728c45a7ccacfd", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/security-core": "^3.4.22|^4.2.3|^5.0", + "symfony/security-http": "^4.4.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Guard\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Guard", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-guard/tree/v4.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-23T06:06:49+00:00" + }, + { + "name": "symfony/security-http", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4.8" + }, + "conflict": { + "symfony/event-dispatcher": ">=5", + "symfony/security-csrf": "<3.4.11|~4.0,<4.0.11" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/security-csrf": "^3.4.11|^4.0.11|^5.0" + }, + "suggest": { + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-27T11:44:32+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + }, + "time": "2022-10-14T12:47:21+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.17.0" + }, + "time": "2023-02-02T15:41:36+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.0.1" + }, + "time": "2020-07-09T08:33:42+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-01-26T08:26:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-04T13:37:15+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/phpcpd", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-12-07T05:39:23+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2022-06-18T07:21:10+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-25T12:56:14+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b8daf6c56801e6d664224261cb100b73edc78a5", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-03T12:57:57+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b3378a7d305666a69e08457b65af8bca179fbbbb", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0" + }, + "suggest": { + "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/phpunit-bridge/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-08T14:39:54+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/crayfish/rootfs/var/www/crayfish/Hypercube/composer.lock b/crayfish/rootfs/var/www/crayfish/Hypercube/composer.lock new file mode 100644 index 00000000..e463bced --- /dev/null +++ b/crayfish/rootfs/var/www/crayfish/Hypercube/composer.lock @@ -0,0 +1,6652 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "2392881d8e6c8830dcd71328af9573bd", + "packages": [ + { + "name": "easyrdf/easyrdf", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/easyrdf/easyrdf.git", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-xmlreader": "*", + "lib-libxml": "*", + "php": ">=7.1.0" + }, + "require-dev": { + "code-lts/doctum": "^5", + "ml/json-ld": "~1.0", + "phpunit/phpunit": "^7", + "semsol/arc2": "^2.4", + "squizlabs/php_codesniffer": "3.*", + "zendframework/zend-http": "~2.3" + }, + "suggest": { + "ml/json-ld": "~1.0", + "semsol/arc2": "~2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "EasyRdf\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nicholas Humfrey", + "email": "njh@aelius.com", + "homepage": "http://www.aelius.com/njh/", + "role": "Developer" + }, + { + "name": "Alexey Zakhlestin", + "email": "indeyets@gmail.com", + "homepage": "http://indeyets.ru/", + "role": "Developer" + } + ], + "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.", + "homepage": "http://www.easyrdf.org/", + "keywords": [ + "Linked Data", + "RDF", + "Semantic Web", + "Turtle", + "rdfa", + "sparql" + ], + "support": { + "forum": "http://groups.google.com/group/easyrdf/", + "issues": "http://github.com/easyrdf/easyrdf/issues", + "source": "https://github.com/easyrdf/easyrdf/tree/1.1.1" + }, + "time": "2020-12-02T08:47:31+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-20T21:43:03+00:00" + }, + { + "name": "islandora/chullo", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/chullo.git", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/chullo/zipball/a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "shasum": "" + }, + "require": { + "easyrdf/easyrdf": "^0.9 || ^1", + "guzzlehttp/guzzle": "^6.1.0", + "ml/json-ld": "^1.0.4", + "php": ">=7.3" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^9.0", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Islandora\\Chullo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + }, + { + "name": "Nick Ruest", + "email": "ruestn@gmail.com", + "role": "Maintainer" + } + ], + "description": "A PHP client for interacting with a Fedora 4 server.", + "homepage": "https://github.com/Islandora/chullo", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/chullo/tree/1.3.0" + }, + "time": "2021-12-16T22:31:48+00:00" + }, + { + "name": "islandora/crayfish-commons", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/Crayfish-Commons.git", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/Crayfish-Commons/zipball/e7b8cbd5951286897507f6cfd3e6356201d24f48", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48", + "shasum": "" + }, + "require": { + "islandora/chullo": "^1.0", + "namshi/jose": "^7.2", + "psr/log": "^1.0.1", + "symfony/config": "4.4.*", + "symfony/dependency-injection": "4.4.*", + "symfony/event-dispatcher": "4.4.*", + "symfony/http-foundation": "4.4.*", + "symfony/monolog-bundle": "^3.4", + "symfony/security-bundle": "4.4.*", + "symfony/yaml": "4.4.*" + }, + "conflict": { + "symfony/symfony": "*" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "4.4.*" + }, + "type": "symfony-bundle", + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.4.*" + } + }, + "autoload": { + "psr-4": { + "Islandora\\Crayfish\\Commons\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + } + ], + "description": "Shared code amongst Islandora Crayfish microservices", + "homepage": "https://github.com/Islandora/Crayfish-Commons", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/Crayfish-Commons/tree/3.0.0" + }, + "time": "2022-05-05T15:46:41+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "time": "2022-09-29T08:45:17+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "namshi/jose", + "version": "7.2.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.5", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpseclib/phpseclib": "^2.0", + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "suggest": { + "ext-openssl": "Allows to use OpenSSL as crypto engine.", + "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "Namshi\\JOSE\\": "src/Namshi/JOSE/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "support": { + "issues": "https://github.com/namshi/jose/issues", + "source": "https://github.com/namshi/jose/tree/master" + }, + "time": "2016-12-05T07:27:31+00:00" + }, + { + "name": "psr/cache", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/2.0.0" + }, + "time": "2021-02-03T23:23:37+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-17T20:21:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4.26|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-16T16:18:09+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-25T10:21:52+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:35:46+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-12-20T07:19:24+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T16:17:57+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/inflector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/inflector.git", + "reference": "66185be61805b1e44a5c4000929e700228d426cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/inflector/zipball/66185be61805b1e44a5c4000929e700228d426cc", + "reference": "66185be61805b1e44a5c4000929e700228d426cc", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts words between their singular and plural forms (English only)", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "support": { + "source": "https://github.com/symfony/inflector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "EnglishInflector from the String component", + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/ad09c9980b912e757c4ecd8363cebf3039d1d471", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-16T12:12:11+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/property-access", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/d49682f6f0764df725c95128213a38f7e0a9f358", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/inflector": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/cache": "^3.4|^4.0|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/076fd2088ada33d760758d98ff07ddedbf567946", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^4.4", + "symfony/security-csrf": "^4.2|^5.0", + "symfony/security-guard": "^4.2|^5.0", + "symfony/security-http": "^4.4.50" + }, + "conflict": { + "symfony/browser-kit": "<4.2", + "symfony/console": "<3.4", + "symfony/framework-bundle": "<4.4", + "symfony/ldap": "<4.4", + "symfony/twig-bundle": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/twig-bridge": "^3.4|^4.0|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/security-core", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/423ccb332784b236dfe6c5f396d0ac49db57c914", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1|^2", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/ldap": "<4.4", + "symfony/security-guard": "<4.3" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/ldap": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/validator": "^3.4.31|^4.3.4|^5.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-22T05:50:33+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "45c956ef58135091f53732646a0acd28034f02c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/45c956ef58135091f53732646a0acd28034f02c0", + "reference": "45c956ef58135091f53732646a0acd28034f02c0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^3.4|^4.0|^5.0" + }, + "conflict": { + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/http-foundation": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/security-guard", + "version": "v4.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-guard.git", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/f199eb1b19db11ce254b891580728c45a7ccacfd", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/security-core": "^3.4.22|^4.2.3|^5.0", + "symfony/security-http": "^4.4.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Guard\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Guard", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-guard/tree/v4.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-23T06:06:49+00:00" + }, + { + "name": "symfony/security-http", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4.8" + }, + "conflict": { + "symfony/event-dispatcher": ">=5", + "symfony/security-csrf": "<3.4.11|~4.0,<4.0.11" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/security-csrf": "^3.4.11|^4.0.11|^5.0" + }, + "suggest": { + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-27T11:44:32+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + }, + "time": "2022-10-14T12:47:21+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.17.0" + }, + "time": "2023-02-02T15:41:36+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.0.1" + }, + "time": "2020-07-09T08:33:42+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-01-26T08:26:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-04T13:37:15+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/phpcpd", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-12-07T05:39:23+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2022-06-18T07:21:10+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-25T12:56:14+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b8daf6c56801e6d664224261cb100b73edc78a5", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-03T12:57:57+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b3378a7d305666a69e08457b65af8bca179fbbbb", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0" + }, + "suggest": { + "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/phpunit-bridge/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-08T14:39:54+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/crayfish/rootfs/var/www/crayfish/Milliner/composer.lock b/crayfish/rootfs/var/www/crayfish/Milliner/composer.lock new file mode 100644 index 00000000..26677980 --- /dev/null +++ b/crayfish/rootfs/var/www/crayfish/Milliner/composer.lock @@ -0,0 +1,6652 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "9acdb3178f4ce1aa3155bda7530d771d", + "packages": [ + { + "name": "easyrdf/easyrdf", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/easyrdf/easyrdf.git", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-xmlreader": "*", + "lib-libxml": "*", + "php": ">=7.1.0" + }, + "require-dev": { + "code-lts/doctum": "^5", + "ml/json-ld": "~1.0", + "phpunit/phpunit": "^7", + "semsol/arc2": "^2.4", + "squizlabs/php_codesniffer": "3.*", + "zendframework/zend-http": "~2.3" + }, + "suggest": { + "ml/json-ld": "~1.0", + "semsol/arc2": "~2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "EasyRdf\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nicholas Humfrey", + "email": "njh@aelius.com", + "homepage": "http://www.aelius.com/njh/", + "role": "Developer" + }, + { + "name": "Alexey Zakhlestin", + "email": "indeyets@gmail.com", + "homepage": "http://indeyets.ru/", + "role": "Developer" + } + ], + "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.", + "homepage": "http://www.easyrdf.org/", + "keywords": [ + "Linked Data", + "RDF", + "Semantic Web", + "Turtle", + "rdfa", + "sparql" + ], + "support": { + "forum": "http://groups.google.com/group/easyrdf/", + "issues": "http://github.com/easyrdf/easyrdf/issues", + "source": "https://github.com/easyrdf/easyrdf/tree/1.1.1" + }, + "time": "2020-12-02T08:47:31+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-20T21:43:03+00:00" + }, + { + "name": "islandora/chullo", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/chullo.git", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/chullo/zipball/a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "shasum": "" + }, + "require": { + "easyrdf/easyrdf": "^0.9 || ^1", + "guzzlehttp/guzzle": "^6.1.0", + "ml/json-ld": "^1.0.4", + "php": ">=7.3" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^9.0", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Islandora\\Chullo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + }, + { + "name": "Nick Ruest", + "email": "ruestn@gmail.com", + "role": "Maintainer" + } + ], + "description": "A PHP client for interacting with a Fedora 4 server.", + "homepage": "https://github.com/Islandora/chullo", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/chullo/tree/1.3.0" + }, + "time": "2021-12-16T22:31:48+00:00" + }, + { + "name": "islandora/crayfish-commons", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/Crayfish-Commons.git", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/Crayfish-Commons/zipball/e7b8cbd5951286897507f6cfd3e6356201d24f48", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48", + "shasum": "" + }, + "require": { + "islandora/chullo": "^1.0", + "namshi/jose": "^7.2", + "psr/log": "^1.0.1", + "symfony/config": "4.4.*", + "symfony/dependency-injection": "4.4.*", + "symfony/event-dispatcher": "4.4.*", + "symfony/http-foundation": "4.4.*", + "symfony/monolog-bundle": "^3.4", + "symfony/security-bundle": "4.4.*", + "symfony/yaml": "4.4.*" + }, + "conflict": { + "symfony/symfony": "*" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "4.4.*" + }, + "type": "symfony-bundle", + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.4.*" + } + }, + "autoload": { + "psr-4": { + "Islandora\\Crayfish\\Commons\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + } + ], + "description": "Shared code amongst Islandora Crayfish microservices", + "homepage": "https://github.com/Islandora/Crayfish-Commons", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/Crayfish-Commons/tree/3.0.0" + }, + "time": "2022-05-05T15:46:41+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "time": "2022-09-29T08:45:17+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "namshi/jose", + "version": "7.2.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.5", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpseclib/phpseclib": "^2.0", + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "suggest": { + "ext-openssl": "Allows to use OpenSSL as crypto engine.", + "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "Namshi\\JOSE\\": "src/Namshi/JOSE/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "support": { + "issues": "https://github.com/namshi/jose/issues", + "source": "https://github.com/namshi/jose/tree/master" + }, + "time": "2016-12-05T07:27:31+00:00" + }, + { + "name": "psr/cache", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/2.0.0" + }, + "time": "2021-02-03T23:23:37+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-17T20:21:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4.26|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-16T16:18:09+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-25T10:21:52+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:35:46+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-12-20T07:19:24+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T16:17:57+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/inflector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/inflector.git", + "reference": "66185be61805b1e44a5c4000929e700228d426cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/inflector/zipball/66185be61805b1e44a5c4000929e700228d426cc", + "reference": "66185be61805b1e44a5c4000929e700228d426cc", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts words between their singular and plural forms (English only)", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "support": { + "source": "https://github.com/symfony/inflector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "EnglishInflector from the String component", + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/ad09c9980b912e757c4ecd8363cebf3039d1d471", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-16T12:12:11+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/property-access", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/d49682f6f0764df725c95128213a38f7e0a9f358", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/inflector": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/cache": "^3.4|^4.0|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/076fd2088ada33d760758d98ff07ddedbf567946", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^4.4", + "symfony/security-csrf": "^4.2|^5.0", + "symfony/security-guard": "^4.2|^5.0", + "symfony/security-http": "^4.4.50" + }, + "conflict": { + "symfony/browser-kit": "<4.2", + "symfony/console": "<3.4", + "symfony/framework-bundle": "<4.4", + "symfony/ldap": "<4.4", + "symfony/twig-bundle": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/twig-bridge": "^3.4|^4.0|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/security-core", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/423ccb332784b236dfe6c5f396d0ac49db57c914", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1|^2", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/ldap": "<4.4", + "symfony/security-guard": "<4.3" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/ldap": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/validator": "^3.4.31|^4.3.4|^5.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-22T05:50:33+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "45c956ef58135091f53732646a0acd28034f02c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/45c956ef58135091f53732646a0acd28034f02c0", + "reference": "45c956ef58135091f53732646a0acd28034f02c0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^3.4|^4.0|^5.0" + }, + "conflict": { + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/http-foundation": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/security-guard", + "version": "v4.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-guard.git", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/f199eb1b19db11ce254b891580728c45a7ccacfd", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/security-core": "^3.4.22|^4.2.3|^5.0", + "symfony/security-http": "^4.4.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Guard\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Guard", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-guard/tree/v4.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-23T06:06:49+00:00" + }, + { + "name": "symfony/security-http", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4.8" + }, + "conflict": { + "symfony/event-dispatcher": ">=5", + "symfony/security-csrf": "<3.4.11|~4.0,<4.0.11" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/security-csrf": "^3.4.11|^4.0.11|^5.0" + }, + "suggest": { + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-27T11:44:32+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + }, + "time": "2022-10-14T12:47:21+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.17.0" + }, + "time": "2023-02-02T15:41:36+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.0.1" + }, + "time": "2020-07-09T08:33:42+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-01-26T08:26:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-04T13:37:15+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/phpcpd", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-12-07T05:39:23+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2022-06-18T07:21:10+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-25T12:56:14+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b8daf6c56801e6d664224261cb100b73edc78a5", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-03T12:57:57+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b3378a7d305666a69e08457b65af8bca179fbbbb", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0" + }, + "suggest": { + "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/phpunit-bridge/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-08T14:39:54+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/crayfish/rootfs/var/www/crayfish/Recast/composer.lock b/crayfish/rootfs/var/www/crayfish/Recast/composer.lock new file mode 100644 index 00000000..f75be05d --- /dev/null +++ b/crayfish/rootfs/var/www/crayfish/Recast/composer.lock @@ -0,0 +1,6652 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "0354ba9e6ded9e3c35f4147ffc006873", + "packages": [ + { + "name": "easyrdf/easyrdf", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/easyrdf/easyrdf.git", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/easyrdf/easyrdf/zipball/c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "reference": "c7b0a9dbcb211eb7de03ee99ff5b52d17f2a8e64", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-xmlreader": "*", + "lib-libxml": "*", + "php": ">=7.1.0" + }, + "require-dev": { + "code-lts/doctum": "^5", + "ml/json-ld": "~1.0", + "phpunit/phpunit": "^7", + "semsol/arc2": "^2.4", + "squizlabs/php_codesniffer": "3.*", + "zendframework/zend-http": "~2.3" + }, + "suggest": { + "ml/json-ld": "~1.0", + "semsol/arc2": "~2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "EasyRdf\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nicholas Humfrey", + "email": "njh@aelius.com", + "homepage": "http://www.aelius.com/njh/", + "role": "Developer" + }, + { + "name": "Alexey Zakhlestin", + "email": "indeyets@gmail.com", + "homepage": "http://indeyets.ru/", + "role": "Developer" + } + ], + "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.", + "homepage": "http://www.easyrdf.org/", + "keywords": [ + "Linked Data", + "RDF", + "Semantic Web", + "Turtle", + "rdfa", + "sparql" + ], + "support": { + "forum": "http://groups.google.com/group/easyrdf/", + "issues": "http://github.com/easyrdf/easyrdf/issues", + "source": "https://github.com/easyrdf/easyrdf/tree/1.1.1" + }, + "time": "2020-12-02T08:47:31+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-20T21:43:03+00:00" + }, + { + "name": "islandora/chullo", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/chullo.git", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/chullo/zipball/a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "reference": "a7c1e051eab2a5077eaf5db2649201fa775c5a02", + "shasum": "" + }, + "require": { + "easyrdf/easyrdf": "^0.9 || ^1", + "guzzlehttp/guzzle": "^6.1.0", + "ml/json-ld": "^1.0.4", + "php": ">=7.3" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^9.0", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Islandora\\Chullo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + }, + { + "name": "Nick Ruest", + "email": "ruestn@gmail.com", + "role": "Maintainer" + } + ], + "description": "A PHP client for interacting with a Fedora 4 server.", + "homepage": "https://github.com/Islandora/chullo", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/chullo/tree/1.3.0" + }, + "time": "2021-12-16T22:31:48+00:00" + }, + { + "name": "islandora/crayfish-commons", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Islandora/Crayfish-Commons.git", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Islandora/Crayfish-Commons/zipball/e7b8cbd5951286897507f6cfd3e6356201d24f48", + "reference": "e7b8cbd5951286897507f6cfd3e6356201d24f48", + "shasum": "" + }, + "require": { + "islandora/chullo": "^1.0", + "namshi/jose": "^7.2", + "psr/log": "^1.0.1", + "symfony/config": "4.4.*", + "symfony/dependency-injection": "4.4.*", + "symfony/event-dispatcher": "4.4.*", + "symfony/http-foundation": "4.4.*", + "symfony/monolog-bundle": "^3.4", + "symfony/security-bundle": "4.4.*", + "symfony/yaml": "4.4.*" + }, + "conflict": { + "symfony/symfony": "*" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "4.4.*" + }, + "type": "symfony-bundle", + "extra": { + "symfony": { + "allow-contrib": false, + "require": "4.4.*" + } + }, + "autoload": { + "psr-4": { + "Islandora\\Crayfish\\Commons\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + }, + { + "name": "Daniel Lamb", + "email": "dlamb@islandora.ca", + "role": "Maintainer" + } + ], + "description": "Shared code amongst Islandora Crayfish microservices", + "homepage": "https://github.com/Islandora/Crayfish-Commons", + "support": { + "issues": "https://github.com/Islandora/documentation/issues", + "source": "https://github.com/Islandora/Crayfish-Commons/tree/3.0.0" + }, + "time": "2022-05-05T15:46:41+00:00" + }, + { + "name": "ml/iri", + "version": "1.1.4", + "target-dir": "ML/IRI", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/IRI.git", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/IRI/zipball/cbd44fa913e00ea624241b38cefaa99da8d71341", + "reference": "cbd44fa913e00ea624241b38cefaa99da8d71341", + "shasum": "" + }, + "require": { + "lib-pcre": ">=4.0", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "ML\\IRI": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "IRI handling for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "URN", + "iri", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/lanthaler/IRI/issues", + "source": "https://github.com/lanthaler/IRI/tree/master" + }, + "time": "2014-01-21T13:43:39+00:00" + }, + { + "name": "ml/json-ld", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/lanthaler/JsonLD.git", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lanthaler/JsonLD/zipball/537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "reference": "537e68e87a6bce23e57c575cd5dcac1f67ce25d8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ml/iri": "^1.1.1", + "php": ">=5.3.0" + }, + "require-dev": { + "json-ld/tests": "1.0", + "phpunit/phpunit": "^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ML\\JsonLD\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Markus Lanthaler", + "email": "mail@markus-lanthaler.com", + "homepage": "http://www.markus-lanthaler.com", + "role": "Developer" + } + ], + "description": "JSON-LD Processor for PHP", + "homepage": "http://www.markus-lanthaler.com", + "keywords": [ + "JSON-LD", + "jsonld" + ], + "support": { + "issues": "https://github.com/lanthaler/JsonLD/issues", + "source": "https://github.com/lanthaler/JsonLD/tree/1.2.1" + }, + "time": "2022-09-29T08:45:17+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "namshi/jose", + "version": "7.2.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.5", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpseclib/phpseclib": "^2.0", + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "suggest": { + "ext-openssl": "Allows to use OpenSSL as crypto engine.", + "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "Namshi\\JOSE\\": "src/Namshi/JOSE/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "support": { + "issues": "https://github.com/namshi/jose/issues", + "source": "https://github.com/namshi/jose/tree/master" + }, + "time": "2016-12-05T07:27:31+00:00" + }, + { + "name": "psr/cache", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/2.0.0" + }, + "time": "2021-02-03T23:23:37+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-17T20:21:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4.26|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-16T16:18:09+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-25T10:21:52+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:35:46+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-12-20T07:19:24+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T16:17:57+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/inflector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/inflector.git", + "reference": "66185be61805b1e44a5c4000929e700228d426cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/inflector/zipball/66185be61805b1e44a5c4000929e700228d426cc", + "reference": "66185be61805b1e44a5c4000929e700228d426cc", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Inflector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts words between their singular and plural forms (English only)", + "homepage": "https://symfony.com", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string", + "symfony", + "words" + ], + "support": { + "source": "https://github.com/symfony/inflector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "EnglishInflector from the String component", + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/ad09c9980b912e757c4ecd8363cebf3039d1d471", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-16T12:12:11+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/property-access", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/d49682f6f0764df725c95128213a38f7e0a9f358", + "reference": "d49682f6f0764df725c95128213a38f7e0a9f358", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/inflector": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/cache": "^3.4|^4.0|^5.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/076fd2088ada33d760758d98ff07ddedbf567946", + "reference": "076fd2088ada33d760758d98ff07ddedbf567946", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^4.4", + "symfony/security-csrf": "^4.2|^5.0", + "symfony/security-guard": "^4.2|^5.0", + "symfony/security-http": "^4.4.50" + }, + "conflict": { + "symfony/browser-kit": "<4.2", + "symfony/console": "<3.4", + "symfony/framework-bundle": "<4.4", + "symfony/ldap": "<4.4", + "symfony/twig-bundle": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.2|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/translation": "^3.4|^4.0|^5.0", + "symfony/twig-bridge": "^3.4|^4.0|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/security-core", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/423ccb332784b236dfe6c5f396d0ac49db57c914", + "reference": "423ccb332784b236dfe6c5f396d0ac49db57c914", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1|^2", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/ldap": "<4.4", + "symfony/security-guard": "<4.3" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/ldap": "^4.4|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/validator": "^3.4.31|^4.3.4|^5.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-22T05:50:33+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "45c956ef58135091f53732646a0acd28034f02c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/45c956ef58135091f53732646a0acd28034f02c0", + "reference": "45c956ef58135091f53732646a0acd28034f02c0", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16", + "symfony/security-core": "^3.4|^4.0|^5.0" + }, + "conflict": { + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/http-foundation": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/security-guard", + "version": "v4.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-guard.git", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/f199eb1b19db11ce254b891580728c45a7ccacfd", + "reference": "f199eb1b19db11ce254b891580728c45a7ccacfd", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/security-core": "^3.4.22|^4.2.3|^5.0", + "symfony/security-http": "^4.4.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Guard\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Guard", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-guard/tree/v4.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-23T06:06:49+00:00" + }, + { + "name": "symfony/security-http", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "reference": "7fa4a0cac16f02cb534a6e9adcdb17385f94004f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/http-foundation": "^3.4.40|^4.4.7|^5.0.7", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-php80": "^1.16", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4.8" + }, + "conflict": { + "symfony/event-dispatcher": ">=5", + "symfony/security-csrf": "<3.4.11|~4.0,<4.0.11" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/security-csrf": "^3.4.11|^4.0.11|^5.0" + }, + "suggest": { + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T10:39:54+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "reference": "4a7a3a3d55c471d396e6d28011368b7b83cb518b", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-27T11:44:32+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + }, + "time": "2022-10-14T12:47:21+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "reference": "15873c65b207b07765dbc3c95d20fdf4a320cbe2", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2 || ^2.0", + "php": "^7.2 || 8.0.* || 8.1.* || 8.2.*", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0 || ^7.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.17.0" + }, + "time": "2023-02-02T15:41:36+00:00" + }, + { + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy-phpunit/issues", + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.0.1" + }, + "time": "2020-07-09T08:33:42+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-01-26T08:26:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-04T13:37:15+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/phpcpd", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpcpd.git", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" + }, + "bin": [ + "phpcpd" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Copy/Paste Detector (CPD) for PHP code.", + "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-12-07T05:39:23+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2022-06-18T07:21:10+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "reference": "2a1ff40723ef6b29c8229a860a9c8f815ad7dbbb", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-25T12:56:14+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b8daf6c56801e6d664224261cb100b73edc78a5", + "reference": "4b8daf6c56801e6d664224261cb100b73edc78a5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-03T12:57:57+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b3378a7d305666a69e08457b65af8bca179fbbbb", + "reference": "b3378a7d305666a69e08457b65af8bca179fbbbb", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0|9.1.2" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0" + }, + "suggest": { + "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/phpunit-bridge/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-08T14:39:54+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/crayfits/.dockerignore b/crayfits/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/crayfits/.dockerignore +++ b/crayfits/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/crayfits/Dockerfile b/crayfits/Dockerfile index 87ed82be..9bcc4204 100644 --- a/crayfits/Dockerfile +++ b/crayfits/Dockerfile @@ -1,26 +1,42 @@ -# syntax=docker/dockerfile:experimental -FROM local/nginx:latest - -ARG COMMIT=4e0faeb31f84e74e7cecc083b2f096d55e425fbb - -RUN --mount=type=cache,target=/root/.composer/cache \ - --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - git-clone-cached.sh \ - --url https://github.com/roblib/CrayFits.git \ - --cache-dir "${DOWNLOAD_CACHE_DIRECTORY}" \ - --commit "${COMMIT}" \ - --worktree /var/www/crayfits && \ - composer install -d /var/www/crayfits && \ - mkdir /var/log/islandora && \ - chown nginx:nginx /var/log/islandora && \ - chown -R nginx:nginx /var/www && \ - cleanup.sh +# syntax=docker/dockerfile:1.5.1 +FROM nginx + +# When updating this commit also update the lock file in rootfs/var/www/crayfits. +ARG TARGETARCH +ARG COMMIT=89f8229508c3da4f3d4a7002eb72a69c40c03e94 +ARG FILE=${COMMIT}.tar.gz +ARG URL=https://github.com/roblib/CrayFits/archive/${FILE} +ARG SHA256=f6c45699d2dbf28c984777abb7a18bb3e864d27666abb71488e2ffbcc567632a + +EXPOSE 8000 WORKDIR /var/www/crayfits -COPY /rootfs / +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=crayfits-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + --mount=type=cache,id=crayfish-composer-${TARGETARCH},sharing=locked,target=/root/.composer/cache \ + download.sh \ + --url "${URL}" \ + --sha256 "${SHA256}" \ + --strip \ + --dest "/var/www/crayfits" \ + && \ + cleanup.sh -STOPSIGNAL SIGWINCH +# Required at the moment as the log location is hard-coded in crayfits. +RUN mkdir -p /var/log/islandora && \ + touch /var/log/islandora/fits.log && \ + chown -R nginx:nginx /var/log/islandora && \ + cleanup.sh -EXPOSE 8000 +RUN --mount=type=bind,source=rootfs/var/www/crayfits/composer.lock,target=/var/www/crayfits/composer.lock \ + composer install -d /var/www/crayfits && \ + cleanup.sh + +ENV \ + CRAYFITS_LOG_LEVEL=info \ + CRAYFITS_WEBSERVICE_URI=fits:8080/fits/examine + +COPY --link rootfs / + +RUN chown -R nginx:nginx /var/www diff --git a/crayfits/README.md b/crayfits/README.md index aef6b32a..d2bba38a 100644 --- a/crayfits/README.md +++ b/crayfits/README.md @@ -19,14 +19,46 @@ additional settings, volumes, ports, etc. ## Settings -> N.B. For all of the settings below images that descend from -> ``islandora/crayfits`` will apply prefix to every setting. So for example -> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for -> different settings on a per-service basis. - -| Environment Variable | Etcd Key | Default | Description | -| :---------------------- | :----------------------- | :---------------- | :------------------------------------------------------------------------------------------------ | -| CRAYFITS_LOG_LEVEL | /crayfits/log/level | debug | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | -| CRAYFITS_WEBSERVICE_URI | /crayfits/webservice/uri | fits/fits/examine | The URL of the FITS servlet. | +| Environment Variable | Default | Description | +| :---------------------- | :--------------------- | :------------------------------------------------------------------------------------------------ | +| CRAYFITS_LOG_LEVEL | info | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | +| CRAYFITS_WEBSERVICE_URI | fits:8080/fits/examine | The URL of the FITS servlet. | + +## Updating + +You can change the commit used for crayfits by modifying the build argument +`COMMIT` and `SHA256` in the `Dockerfile` shown as `XXXXXXXXXXXX` in the +following snippet: + +```Dockerfile +ARG COMMIT=XXXXXXXXXXXX +#... +ARG SHA256=XXXXXXXXXXXX +``` + +You can generate the `SHA256` with the following commands: + +```bash +COMMIT=$(cat crayfits/Dockerfile | grep -o 'COMMIT=.*' | cut -f2 -d=) +FILE=$(cat crayfits/Dockerfile | grep -o 'FILE=.*' | cut -f2 -d=) +URL=$(cat crayfits/Dockerfile | grep -o 'URL=.*' | cut -f2 -d=) +FILE=$(eval "echo $FILE") +URL=$(eval "echo $URL") +wget --quiet "${URL}" +shasum -a 256 "${FILE}" | cut -f1 -d' ' +rm "${FILE}" +``` + +When changing the `COMMIT` and `SHA256` be sure to also update the composer lock files, this +can be done with the following commands: + +```bash +make bake TARGET=crayfits + +docker run --rm -ti \ + -v $(pwd)/crayfits/rootfs/var/www/crayfits/composer.lock:/var/www/crayfits/composer.lock \ + --entrypoint ash islandora.dev/crayfits:latest -c \ + "cd /var/www/crayfits && composer update" +``` [CrayFits]: https://github.com/roblib/CrayFits diff --git a/crayfits/rootfs/etc/confd/conf.d/.env.local.toml b/crayfits/rootfs/etc/confd/conf.d/.env.local.toml index 6926e23c..4919d18f 100644 --- a/crayfits/rootfs/etc/confd/conf.d/.env.local.toml +++ b/crayfits/rootfs/etc/confd/conf.d/.env.local.toml @@ -4,4 +4,4 @@ dest = "/var/www/crayfits/.env.local" uid = 100 gid = 101 mode = "0644" -keys = [ "/webservice" ] \ No newline at end of file +keys = [ "/" ] diff --git a/crayfits/rootfs/etc/confd/conf.d/default.conf.toml b/crayfits/rootfs/etc/confd/conf.d/default.conf.toml deleted file mode 100644 index 1df8dbe5..00000000 --- a/crayfits/rootfs/etc/confd/conf.d/default.conf.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "default.conf.tmpl" -dest = "/etc/nginx/conf.d/default.conf" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/" ] diff --git a/crayfits/rootfs/etc/confd/conf.d/monolog.yaml.toml b/crayfits/rootfs/etc/confd/conf.d/monolog.yaml.toml index 7bb50dcc..58056e9c 100644 --- a/crayfits/rootfs/etc/confd/conf.d/monolog.yaml.toml +++ b/crayfits/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -4,4 +4,4 @@ dest = "/var/www/crayfits/config/packages/monolog.yaml" uid = 100 gid = 101 mode = "0644" -keys = [ "/log/level" ] +keys = [ "/" ] diff --git a/crayfits/rootfs/etc/confd/confd.toml b/crayfits/rootfs/etc/confd/confd.toml deleted file mode 100644 index 20778f09..00000000 --- a/crayfits/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/crayfits" diff --git a/crayfits/rootfs/etc/confd/templates/.env.local.tmpl b/crayfits/rootfs/etc/confd/templates/.env.local.tmpl index 50554e82..539056c9 100644 --- a/crayfits/rootfs/etc/confd/templates/.env.local.tmpl +++ b/crayfits/rootfs/etc/confd/templates/.env.local.tmpl @@ -1 +1 @@ -FITS_WEBSERVICE_URI={{ getv "/webservice/uri" "fits/fits/examine" }} \ No newline at end of file +FITS_WEBSERVICE_URI={{ getenv "CRAYFITS_WEBSERVICE_URI" }} diff --git a/crayfits/rootfs/etc/confd/templates/monolog.yaml.tmpl b/crayfits/rootfs/etc/confd/templates/monolog.yaml.tmpl index 457096f0..7fc0279c 100644 --- a/crayfits/rootfs/etc/confd/templates/monolog.yaml.tmpl +++ b/crayfits/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -5,4 +5,4 @@ monolog: path: "php://stderr" # Valid log levels are: # debug, info, notice, warning, error, critical, alert, emergency, none - level: {{ getv "/log/level" "debug" }} + level: {{ getenv "CRAYFITS_LOG_LEVEL" }} diff --git a/crayfits/rootfs/etc/confd/templates/default.conf.tmpl b/crayfits/rootfs/etc/nginx/http.d/default.conf similarity index 79% rename from crayfits/rootfs/etc/confd/templates/default.conf.tmpl rename to crayfits/rootfs/etc/nginx/http.d/default.conf index 22106cfc..e960bf6b 100644 --- a/crayfits/rootfs/etc/confd/templates/default.conf.tmpl +++ b/crayfits/rootfs/etc/nginx/http.d/default.conf @@ -6,10 +6,10 @@ server { location / { # try to serve file directly, fallback to index.php try_files $uri /index.php$is_args$args; - } - + } + location ~ ^/index\.php(/|$) { - fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; + fastcgi_pass unix:/var/run/php-fpm81/php-fpm81.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; @@ -27,3 +27,7 @@ server { return 404; } } + +# Required for Nginx service to validate that fpm is working. +# @see nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check +include /etc/nginx/shared/fpm.server.conf; diff --git a/crayfits/rootfs/var/www/crayfits/composer.lock b/crayfits/rootfs/var/www/crayfits/composer.lock new file mode 100644 index 00000000..ead48c48 --- /dev/null +++ b/crayfits/rootfs/var/www/crayfits/composer.lock @@ -0,0 +1,3324 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "13a4202b88ad70d104d34f65a2d79c70", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "b94b2807d85443f9719887892882d0329d1e2598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2022-08-28T14:55:35+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2022-06-20T21:43:03+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.27.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", + "phpunit/phpunit": "~4.5", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "psr/cache", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/2.0.0" + }, + "time": "2021-02-03T23:23:37+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/cache", + "version": "v4.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" + }, + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v4.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-17T20:21:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T17:10:16+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4.26|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-16T16:18:09+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-03-01T10:25:55+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v4.4.37", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "reference": "fcedd6d382b3afc3e1e786aa4e4fc4cf06f564cf", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "require-dev": { + "symfony/process": "^3.4.2|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v4.4.37" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:41:36+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-29T07:35:46+00:00" + }, + { + "name": "symfony/flex", + "version": "v1.19.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "51077ed0f6dc2c94cd0b670167eee3747c31b2c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/51077ed0f6dc2c94cd0b670167eee3747c31b2c1", + "reference": "51077ed0f6dc2c94cd0b670167eee3747c31b2c1", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=7.1" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/dotenv": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v1.19.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-30T17:02:31+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d8cf2558249004a29b8e27b1f6eae52337ff471b", + "reference": "d8cf2558249004a29b8e27b1f6eae52337ff471b", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=7.1.3", + "symfony/cache": "^4.4|^5.0", + "symfony/config": "^4.4.11|~5.0.11|^5.1.3", + "symfony/dependency-injection": "^4.4.38|^5.0.1", + "symfony/error-handler": "^4.4.1|^5.0.1", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/routing": "^4.4.12|^5.1.4" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.0|>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.3.0|1.3.*", + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", + "symfony/console": "<4.4.21", + "symfony/dom-crawler": "<4.3", + "symfony/dotenv": "<4.3.6", + "symfony/form": "<4.3.5", + "symfony/http-client": "<4.4", + "symfony/lock": "<4.4", + "symfony/mailer": "<4.4", + "symfony/messenger": "<4.4", + "symfony/mime": "<4.4", + "symfony/property-info": "<3.4", + "symfony/security-bundle": "<4.4", + "symfony/serializer": "<4.4", + "symfony/stopwatch": "<3.4", + "symfony/translation": "<4.4", + "symfony/twig-bridge": "<4.1.1", + "symfony/twig-bundle": "<4.4", + "symfony/validator": "<4.4", + "symfony/web-profiler-bundle": "<4.4", + "symfony/workflow": "<4.3.6" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "doctrine/cache": "^1.0|^2.0", + "doctrine/persistence": "^1.3|^2|^3", + "paragonie/sodium_compat": "^1.8", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^3.4|^4.0|^5.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/console": "^4.4.42|^5.4.9", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dom-crawler": "^4.4.30|^5.3.7", + "symfony/dotenv": "^4.3.6|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/form": "^4.3.5|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4|^4.0|^5.0", + "symfony/security-core": "^3.4|^4.4|^5.2", + "symfony/security-csrf": "^3.4|^4.0|^5.0", + "symfony/security-http": "^3.4|^4.0|^5.0", + "symfony/serializer": "^4.4|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.4|^5.0", + "symfony/twig-bundle": "^4.4|^5.0", + "symfony/validator": "^4.4|^5.0", + "symfony/web-link": "^4.4|^5.0", + "symfony/workflow": "^4.3.6|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-apcu": "For best performance of the system caches", + "symfony/console": "For using the console commands", + "symfony/form": "For using forms", + "symfony/property-info": "For using the property_info service", + "symfony/serializer": "For using the serializer service", + "symfony/validator": "For using validation", + "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", + "symfony/yaml": "For using the debug:config and lint:yaml commands" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T15:42:31+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-04T16:17:57+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/mime", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v4.4.43", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/ad09c9980b912e757c4ecd8363cebf3039d1d471", + "reference": "ad09c9980b912e757c4ecd8363cebf3039d1d471", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1", + "php": ">=7.1.3", + "symfony/http-kernel": "^4.3", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<3.4", + "symfony/http-foundation": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v4.4.43" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-16T12:12:11+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/routing", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/be74908a6942fdd331554b3cec27ff41b45ccad4", + "reference": "be74908a6942fdd331554b3cec27ff41b45ccad4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-21T19:46:44+00:00" + }, + { + "name": "symfony/yaml", + "version": "v4.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-02T15:47:23+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/crayfits/tests/ServiceStartsWithDefaults/docker-compose.yml b/crayfits/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..2e5f2a60 --- /dev/null +++ b/crayfits/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: crayfits-servicestartswithdefaults +services: + crayfits: + <<: *common + image: ${CRAYFITS:-islandora/crayfits:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/crayfits/tests/ServiceStartsWithDefaults/test.sh b/crayfits/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..d1fc780e --- /dev/null +++ b/crayfits/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,7 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +wait_20x "http://localhost:8000/" + +# Service must start for us to get to this point. +exit 0 diff --git a/demo/.dockerignore b/demo/.dockerignore deleted file mode 100644 index b43bf86b..00000000 --- a/demo/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/demo/Dockerfile b/demo/Dockerfile deleted file mode 100644 index 0fc62ab9..00000000 --- a/demo/Dockerfile +++ /dev/null @@ -1,68 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM local/nginx:latest as composer - -# Islandora based Drupal install. -RUN --mount=type=cache,target=/root/.composer/cache \ - --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - composer create-project islandora/drupal-project:8.8.1 \ - --prefer-dist \ - --no-interaction \ - --stability stable \ - --no-dev \ - --no-install \ - /var/www/drupal \ - && \ - cd /var/www/drupal && \ - composer require --update-no-dev -- \ - drupal/admin_toolbar:^2.0 \ - drupal/console:~1.0 \ - drupal/content_browser:^1.0@alpha \ - drupal/devel:^2.0 \ - drupal/facets:^1.3 \ - drupal/matomo:^1.7 \ - drupal/pdf:1.x-dev \ - drupal/rdfui:^1.0-beta1 \ - drupal/rest_oai_pmh:^1.0 \ - drupal/restui:^1.16 \ - drupal/search_api_solr:^3.8 \ - drupal/transliterate_filenames:^1.3 \ - drush/drush:^9.7.1 \ - islandora-rdm/islandora_fits:dev-master \ - islandora/carapace:dev-8.x-3.x \ - islandora/islandora_defaults:dev-8.x-1.x \ - zaporylie/composer-drupal-optimizations:^1.0 \ - && \ - mkdir -p /var/www/drupal/web/libraries && \ - MASONRY_VERSION="3.3.2" && \ - MASONRY_FILE="v${MASONRY_VERSION}.zip" && \ - MASONRY_URL="https://github.com/desandro/masonry/archive/${MASONRY_FILE}" && \ - MASONRY_SHA256="85dc8b2cdf789693a14022dadc3e573a87d625da5da1cf83e1ef1e5af22af496" && \ - download.sh --url "${MASONRY_URL}" --sha256 "${MASONRY_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - unzip "${DOWNLOAD_CACHE_DIRECTORY}/${MASONRY_FILE}" -d /var/www/drupal/web/libraries && \ - mv /var/www/drupal/web/libraries/masonry-${MASONRY_VERSION} /var/www/drupal/web/libraries/masonry && \ - PDFJS_VERSION="2.0.943" && \ - PDFJS_FILE="pdfjs-${PDFJS_VERSION}-dist.zip" && \ - PDFJS_URL="https://github.com/mozilla/pdf.js/releases/download/v${PDFJS_VERSION}/${PDFJS_FILE}" && \ - PDFJS_SHA256="381683b05f494fe28e11185f98a238b34a663b1b41b5432aa769ca493e5cd087" && \ - download.sh --url "${PDFJS_URL}" --sha256 "${PDFJS_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - mkdir -p /var/www/drupal/web/libraries/pdf.js && \ - unzip "${DOWNLOAD_CACHE_DIRECTORY}/${PDFJS_FILE}" -d /var/www/drupal/web/libraries/pdf.js && \ - OPENSEADRAGON_VERSION="2.4.2" && \ - OPENSEADRAGON_FILE="openseadragon-bin-${OPENSEADRAGON_VERSION}.zip" && \ - OPENSEADRAGON_URL="https://github.com/openseadragon/openseadragon/releases/download/v${OPENSEADRAGON_VERSION}/${OPENSEADRAGON_FILE}" && \ - OPENSEADRAGON_SHA256="8e32d808b80206d5f5aadcfc51ffecf2ecc89e5fb6876c51f409940cf4b1087e" && \ - download.sh --url "${OPENSEADRAGON_URL}" --sha256 "${OPENSEADRAGON_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - mkdir -p /var/www/drupal/web/sites/all/assets/vendor && \ - unzip "${DOWNLOAD_CACHE_DIRECTORY}/${OPENSEADRAGON_FILE}" -d /var/www/drupal/web/sites/all/assets/vendor && \ - mv "/var/www/drupal/web/sites/all/assets/vendor/${OPENSEADRAGON_FILE%.zip}" /var/www/drupal/web/sites/all/assets/vendor/openseadragon && \ - mkdir -p /var/www/drupal/web/sites/default/files/library-definitions && \ - cp /var/www/drupal/web/modules/contrib/openseadragon/openseadragon.json /var/www/drupal/web/sites/default/files/library-definitions && \ - chown -R nginx:nginx /var/www/drupal && \ - cleanup.sh - -FROM local/drupal:latest - -COPY --chown=nginx:nginx --from=composer /var/www/drupal /var/www/drupal - -COPY rootfs / diff --git a/demo/README.md b/demo/README.md deleted file mode 100644 index 5fa8541b..00000000 --- a/demo/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Demo - -Islandora Demo image meant for demoing a functioning system. If you want to -build your own Islandora site site the composer folder for a template on how to -do that. - -## Dependencies - -Requires `islandora/drupal` docker image to build. Please refer to the -[Drupal Image README](../drupal/README.md) for additional information including -additional settings, volumes, ports, etc. diff --git a/demo/rootfs/etc/cont-init.d/04-demo-setup.sh b/demo/rootfs/etc/cont-init.d/04-demo-setup.sh deleted file mode 100755 index da61f29d..00000000 --- a/demo/rootfs/etc/cont-init.d/04-demo-setup.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Does not run in the context of a login shell so we must explicitly include utilities.sh -source /etc/islandora/utilities.sh - -function main { - local modules=( - admin_toolbar - basic_auth - content_browser - controlled_access_terms_defaults - devel - facets - islandora_breadcrumbs - islandora_defaults - islandora_fits - islandora_iiif - islandora_oaipmh - islandora_search - matomo - pdf - rdf - responsive_image - rest - restui - search_api_solr - search_api_solr_defaults - serialization - simpletest - syslog - transliterate_filenames - ) - local features=( - islandora_core_feature - islandora_defaults - islandora_search - ) - - # We do all sites in a stepwise fashion as it turns out to be faster than - # configuring one site completely at a time as they get blocked waiting on - # other services like Fedora to start. - for_all_sites create_database - for_all_sites install_site - for_all_sites update_settings_php - - # Uses the same public/private key for all sub-sites. - # Required if they share the same backend microservices, etc. - for_all_sites configure_jwt_module - - # Enable islandora before all other modules so services that require direct - # communication like ActiveMQ etc have the appropriate settings. - for_all_sites configure_islandora_module - - # The following commands require several services - # to be up and running before they can complete. - for_all_sites wait_for_required_services - - # Create namespace assumed one per site. - for_all_sites create_blazegraph_namespace_with_default_properties - - # Theme must be enabled before importing features. - for_all_sites set_carapace_default_theme - - # All subsites are assumed to use the same modules and features. - for_all_sites enable_modules ${modules[@]} - for_all_sites import_features ${features[@]} - - # Features overrides some settings for services, so we need to explicitly - # set them again. - for_all_sites configure_islandora_module - for_all_sites configure_matomo_module - for_all_sites configure_search_api_solr_module - for_all_sites configure_openseadragon - for_all_sites configure_islandora_default_module - - # Export configuration now that features have been imported. - for_all_sites create_solr_core_with_default_config - - # Run migrations. - for_all_sites import_islandora_migrations - - s6-setuidgid nginx mkdir -p /var/www/drupal/web/simpletest /var/www/drupal/web/sites/simpletest - s6-setuidgid nginx mkdir -p config/sync - - for_all_sites cache_rebuild -} -main diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 00000000..577a32b7 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,1258 @@ +ARCHES = [ + "amd64", + "arm64", +] + +IMAGES = [ + "activemq", + "alpaca", + "base", + "blazegraph", + "cantaloupe", + "code-server", + "crayfish", + "crayfits", + "drupal", + "fcrepo6", + "fits", + "handle", + "homarus", + "houdini", + "hypercube", + "java", + "mariadb", + "matomo", + "milliner", + "nginx", + "postgresql", + "riprap", + "solr", + "test", + "tomcat", +] + +DEPENDENCIES = { + activemq = ["java"] + alpaca = ["java"] + blazegraph = ["tomcat"] + cantaloupe = ["java"] + code-server = ["drupal"] + crayfish = ["nginx"] + crayfits = ["nginx"] + drupal = ["nginx"] + fcrepo6 = ["tomcat"] + fits = ["tomcat"] + handle = ["java"] + homarus = ["crayfish"] + houdini = ["crayfish"] + hypercube = ["crayfish"] + java = ["base"] + mariadb = ["base"] + matomo = ["nginx"] + milliner = ["crayfish"] + nginx = ["base"] + postgresql = ["base"] + riprap = ["nginx"] + solr = ["java"] + test = ["drupal"] + tomcat = ["java"] +} + +############################################################################### +# Variables +############################################################################### +variable "REPOSITORY" { + default = "islandora" +} + +variable "CACHE_FROM_REPOSITORY" { + default = "islandora" +} + +variable "CACHE_TO_REPOSITORY" { + default = "islandora" +} + +variable "TAGS" { + # "latest" is reserved for the most recent release. + # "local" is to distinguish that from builds produced locally. + # Multiple tags can be specified by using a space " " delimited list. + default = "local" +} + +variable "SOURCE_DATE_EPOCH" { + default = "0" +} + +variable "BRANCH" { + # Must be specified for ci builds. + # BRANCH=$(git rev-parse --abbrev-ref HEAD) + default = "" +} + +############################################################################### +# Functions +############################################################################### +function hostArch { + params = [] + result = equal("linux/amd64", BAKE_LOCAL_PLATFORM) ? "amd64" : "arm64" # Only two platforms supported. +} + +function arches { + params = [image, suffix] + result = equal("", suffix) ? [for arch in ARCHES: "${image}-${arch}" ] : [ for arch in ARCHES: "${image}-${arch}-${suffix}" ] +} + +function dependencies { + params = [image, suffix] + result = { for target in DEPENDENCIES[image]: target => notequal("", suffix) ? "target:${target}-${suffix}" : "target:${target}" } +} + +function targets { + params = [suffix] + result = [for target in IMAGES: "${target}-${suffix}" ] +} + +function "tags" { + params = [image, suffix] + result = equal("", suffix) ? [for tag in split(" ", TAGS): "${REPOSITORY}/${image}:${tag}"] : [for tag in split(" ", TAGS): "${REPOSITORY}/${image}:${tag}-${suffix}"] +} + +function "cacheFrom" { + params = [image, arch] + result = equal("", arch) ? [] : ["type=registry,ref=${CACHE_FROM_REPOSITORY}/cache:${image}-main-${arch}", notequal("", BRANCH) ? "type=registry,ref=${CACHE_FROM_REPOSITORY}/cache:${image}-${BRANCH}-${arch}" : ""] +} + +function "cacheTo" { + params = [image, arch] + result = [notequal("", BRANCH) ? "type=registry,oci-mediatypes=true,mode=max,compression=estargz,compression-level=5,ref=${CACHE_TO_REPOSITORY}/cache:${image}-${BRANCH}-${arch}" : ""] +} + +############################################################################### +# Groups +############################################################################### +group "default" { + targets = IMAGES +} + +group "amd64" { + targets = targets("amd64") +} + +group "arm64" { + targets = targets("arm64") +} + +group "ci" { + targets = [ "amd64-ci", "arm64-ci" ] +} + +group "amd64-ci" { + targets = targets("amd64-ci") +} + +group "arm64-ci" { + targets = targets("arm64-ci") +} + +group "activemq-ci" { + targets = arches("activemq", "ci") +} + +group "alpaca-ci" { + targets = arches("alpaca", "ci") +} + +group "base-ci" { + targets = arches("base", "ci") +} + +group "blazegraph-ci" { + targets = arches("blazegraph", "ci") +} + +group "cantaloupe-ci" { + targets = arches("cantaloupe", "ci") +} + +group "code-server-ci" { + targets = arches("code-server", "ci") +} + +group "crayfish-ci" { + targets = arches("crayfish", "ci") +} + +group "crayfits-ci" { + targets = arches("crayfits", "ci") +} + +group "drupal-ci" { + targets = arches("drupal", "ci") +} + +group "fcrepo6-ci" { + targets = arches("fcrepo6", "ci") +} + +group "fits-ci" { + targets = arches("fits", "ci") +} + +group "handle-ci" { + targets = arches("handle", "ci") +} + +group "homarus-ci" { + targets = arches("homarus", "ci") +} + +group "houdini-ci" { + targets = arches("houdini", "ci") +} + +group "hypercube-ci" { + targets = arches("hypercube", "ci") +} + +group "java-ci" { + targets = arches("java", "ci") +} + +group "mariadb-ci" { + targets = arches("mariadb", "ci") +} + +group "matomo-ci" { + targets = arches("matomo", "ci") +} + +group "milliner-ci" { + targets = arches("milliner", "ci") +} + +group "nginx-ci" { + targets = arches("nginx", "ci") +} + +group "postgresql-ci" { + targets = arches("postgresql", "ci") +} + +group "riprap-ci" { + targets = arches("riprap", "ci") +} + +group "solr-ci" { + targets = arches("solr", "ci") +} + +group "test-ci" { + targets = arches("test", "ci") +} + +group "tomcat-ci" { + targets = arches("tomcat", "ci") +} + +############################################################################### +# Common target properties. +############################################################################### +target "common" { + args = { + # Required for reproduciable builds. + # Requires Buildkit 0.11+ + # See: https://reproducible-builds.org/docs/source-date-epoch/ + SOURCE_DATE_EPOCH = "${SOURCE_DATE_EPOCH}", + } +} + +target "amd64-common" { + platforms = ["linux/amd64"] +} + +target "arm64-common" { + platforms = ["linux/arm64"] +} + +############################################################################### +# Image specific target properties. +############################################################################### +target "activemq-common" { + inherits = ["common"] + context = "activemq" +} + +target "alpaca-common" { + inherits = ["common"] + context = "alpaca" +} + +target "base-common" { + inherits = ["common"] + context = "base" + contexts = { + # The digest (sha256 hash) is not platform specific but the digest for the manifest of all platforms. + # It will be the digest printed when you do: docker pull alpine:3.17.1 + # Not the one displayed on DockerHub. + # N.B. This should match the value used in: + # - + # - + alpine = "docker-image://alpine:3.18.3@sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a" + } +} + +target "blazegraph-common" { + inherits = ["common"] + context = "blazegraph" +} + +target "cantaloupe-common" { + inherits = ["common"] + context = "cantaloupe" +} + +target "code-server-common" { + inherits = ["common"] + context = "code-server" +} + +target "crayfish-common" { + inherits = ["common"] + context = "crayfish" +} + +target "crayfits-common" { + inherits = ["common"] + context = "crayfits" +} + +target "drupal-common" { + inherits = ["common"] + context = "drupal" +} + +target "fcrepo6-common" { + inherits = ["common"] + context = "fcrepo6" +} + +target "fits-common" { + inherits = ["common"] + context = "fits" +} + +target "handle-common" { + inherits = ["common"] + context = "handle" +} + +target "homarus-common" { + inherits = ["common"] + context = "homarus" +} + +target "houdini-common" { + inherits = ["common"] + context = "houdini" + contexts = { + # Produced by this repository . + imagemagick = "docker-image://islandora/imagemagick:7.1.1.13@sha256:f95f073798966ca963b1337480bbdadedd958fadb5cee1af7c8c5dc2b9618797" + } +} + +target "hypercube-common" { + inherits = ["common"] + context = "hypercube" + contexts = { + # Produced by this repository . + leptonica = "docker-image://islandora/leptonica:1.83.1@sha256:621b7ff8480b8f9c450259b6610141f5200cf1a0169e2802df74af2f97a3b928" + } +} + +target "java-common" { + inherits = ["common"] + context = "java" +} + +target "mariadb-common" { + inherits = ["common"] + context = "mariadb" +} + +target "matomo-common" { + inherits = ["common"] + context = "matomo" +} + +target "milliner-common" { + inherits = ["common"] + context = "milliner" +} + +target "nginx-common" { + inherits = ["common"] + context = "nginx" +} + +target "postgresql-common" { + inherits = ["common"] + context = "postgresql" +} + +target "riprap-common" { + inherits = ["common"] + context = "riprap" +} + +target "solr-common" { + inherits = ["common"] + context = "solr" +} + +target "test-common" { + inherits = ["common"] + context = "test" +} + +target "tomcat-common" { + inherits = ["common"] + context = "tomcat" +} + +############################################################################### +# Default Image targets for local builds. +############################################################################### +target "activemq" { + inherits = ["activemq-common"] + contexts = dependencies("activemq", "") + cache-from = cacheFrom("activemq", hostArch()) + tags = tags("activemq", "") +} + +target "alpaca" { + inherits = ["alpaca-common"] + contexts = dependencies("alpaca", "") + cache-from = cacheFrom("alpaca", hostArch()) + tags = tags("alpaca", "") +} + +target "base" { + inherits = ["base-common"] + cache-from = cacheFrom("base", hostArch()) + tags = tags("base", "") +} + +target "blazegraph" { + inherits = ["blazegraph-common"] + contexts = dependencies("blazegraph", "") + cache-from = cacheFrom("blazegraph", hostArch()) + tags = tags("blazegraph", "") +} + +target "cantaloupe" { + inherits = ["cantaloupe-common"] + contexts = dependencies("cantaloupe", "") + cache-from = cacheFrom("cantaloupe", hostArch()) + tags = tags("cantaloupe", "") +} + +target "code-server" { + inherits = ["code-server-common"] + contexts = dependencies("code-server", "") + cache-from = cacheFrom("code-server", hostArch()) + tags = tags("code-server", "") +} + +target "crayfish" { + inherits = ["crayfish-common"] + contexts = dependencies("crayfish", "") + cache-from = cacheFrom("crayfish", hostArch()) + tags = tags("crayfish", "") +} + +target "crayfits" { + inherits = ["crayfits-common"] + contexts = dependencies("crayfits", "") + cache-from = cacheFrom("crayfits", hostArch()) + tags = tags("crayfits", "") +} + +target "drupal" { + inherits = ["drupal-common"] + contexts = dependencies("drupal", "") + cache-from = cacheFrom("drupal", hostArch()) + tags = tags("drupal", "") +} + +target "fcrepo6" { + inherits = ["fcrepo6-common"] + contexts = dependencies("fcrepo6", "") + cache-from = cacheFrom("fcrepo6", hostArch()) + tags = tags("fcrepo6", "") +} + +target "fits" { + inherits = ["fits-common"] + contexts = dependencies("fits", "") + cache-from = cacheFrom("fits", hostArch()) + tags = tags("fits", "") +} + +target "handle" { + inherits = ["handle-common"] + contexts = dependencies("handle", "") + cache-from = cacheFrom("handle", hostArch()) + tags = tags("handle", "") +} + +target "homarus" { + inherits = ["homarus-common"] + contexts = dependencies("homarus", "") + cache-from = cacheFrom("homarus", hostArch()) + tags = tags("homarus", "") +} + +target "houdini" { + inherits = ["houdini-common"] + contexts = dependencies("houdini", "") + cache-from = cacheFrom("houdini", hostArch()) + tags = tags("houdini", "") +} + +target "hypercube" { + inherits = ["hypercube-common"] + contexts = dependencies("hypercube", "") + cache-from = cacheFrom("hypercube", hostArch()) + tags = tags("hypercube", "") +} + +target "java" { + inherits = ["java-common"] + contexts = dependencies("java", "") + cache-from = cacheFrom("java", hostArch()) + tags = tags("java", "") +} + +target "mariadb" { + inherits = ["mariadb-common"] + contexts = dependencies("mariadb", "") + cache-from = cacheFrom("mariadb", hostArch()) + tags = tags("mariadb", "") +} + +target "matomo" { + inherits = ["matomo-common"] + contexts = dependencies("matomo", "") + cache-from = cacheFrom("matomo", hostArch()) + tags = tags("matomo", "") +} + +target "milliner" { + inherits = ["milliner-common"] + contexts = dependencies("milliner", "") + cache-from = cacheFrom("milliner", hostArch()) + tags = tags("milliner", "") +} + +target "nginx" { + inherits = ["nginx-common"] + contexts = dependencies("nginx", "") + cache-from = cacheFrom("nginx", hostArch()) + tags = tags("nginx", "") +} + +target "postgresql" { + inherits = ["postgresql-common"] + contexts = dependencies("postgresql", "") + cache-from = cacheFrom("postgresql", hostArch()) + tags = tags("postgresql", "") +} + +target "riprap" { + inherits = ["riprap-common"] + contexts = dependencies("riprap", "") + cache-from = cacheFrom("riprap", hostArch()) + tags = tags("riprap", "") +} + +target "solr" { + inherits = ["solr-common"] + contexts = dependencies("solr", "") + cache-from = cacheFrom("solr", hostArch()) + tags = tags("solr", "") +} + +target "test" { + inherits = ["test-common"] + contexts = dependencies("test", "") + cache-from = cacheFrom("test", hostArch()) + tags = tags("test", "") +} + +target "tomcat" { + inherits = ["tomcat-common"] + contexts = dependencies("tomcat", "") + cache-from = cacheFrom("tomcat", hostArch()) + tags = tags("tomcat", "") +} + +############################################################################### +# linux/amd64 targets. +############################################################################### +target "activemq-amd64" { + inherits = ["activemq-common", "amd64-common"] + contexts = dependencies("activemq", "amd64") + cache-from = cacheFrom("activemq", "amd64") + tags = tags("activemq", "amd64") +} + +target "alpaca-amd64" { + inherits = ["alpaca-common", "amd64-common"] + contexts = dependencies("alpaca", "amd64") + cache-from = cacheFrom("alpaca", "amd64") + tags = tags("alpaca", "amd64") +} + +target "base-amd64" { + inherits = ["base-common", "amd64-common"] + cache-from = cacheFrom("base", "amd64") + tags = tags("base", "amd64") +} + +target "blazegraph-amd64" { + inherits = ["blazegraph-common", "amd64-common"] + contexts = dependencies("blazegraph", "amd64") + cache-from = cacheFrom("blazegraph", "amd64") + tags = tags("blazegraph", "amd64") +} + +target "cantaloupe-amd64" { + inherits = ["cantaloupe-common", "amd64-common"] + contexts = dependencies("cantaloupe", "amd64") + cache-from = cacheFrom("cantaloupe", "amd64") + tags = tags("cantaloupe", "amd64") +} + +target "code-server-amd64" { + inherits = ["code-server-common", "amd64-common"] + contexts = dependencies("code-server", "amd64") + cache-from = cacheFrom("code-server", "amd64") + tags = tags("code-server", "amd64") +} + +target "crayfish-amd64" { + inherits = ["crayfish-common", "amd64-common"] + contexts = dependencies("crayfish", "amd64") + cache-from = cacheFrom("crayfish", "amd64") + tags = tags("crayfish", "amd64") +} + +target "crayfits-amd64" { + inherits = ["crayfits-common", "amd64-common"] + contexts = dependencies("crayfits", "amd64") + cache-from = cacheFrom("crayfits", "amd64") + tags = tags("crayfits", "amd64") +} + +target "drupal-amd64" { + inherits = ["drupal-common", "amd64-common"] + contexts = dependencies("drupal", "amd64") + cache-from = cacheFrom("drupal", "amd64") + tags = tags("drupal", "amd64") +} + +target "fcrepo6-amd64" { + inherits = ["fcrepo6-common", "amd64-common"] + contexts = dependencies("fcrepo6", "amd64") + cache-from = cacheFrom("fcrepo6", "amd64") + tags = tags("fcrepo6", "amd64") +} + +target "fits-amd64" { + inherits = ["fits-common", "amd64-common"] + contexts = dependencies("fits", "amd64") + cache-from = cacheFrom("fits", "amd64") + tags = tags("fits", "amd64") +} + +target "handle-amd64" { + inherits = ["handle-common", "amd64-common"] + contexts = dependencies("handle", "amd64") + cache-from = cacheFrom("handle", "amd64") + tags = tags("handle", "amd64") +} + +target "homarus-amd64" { + inherits = ["homarus-common", "amd64-common"] + contexts = dependencies("homarus", "amd64") + cache-from = cacheFrom("homarus", "amd64") + tags = tags("homarus", "amd64") +} + +target "houdini-amd64" { + inherits = ["houdini-common", "amd64-common"] + contexts = dependencies("houdini", "amd64") + cache-from = cacheFrom("houdini", "amd64") + tags = tags("houdini", "amd64") +} + +target "hypercube-amd64" { + inherits = ["hypercube-common", "amd64-common"] + contexts = dependencies("hypercube", "amd64") + cache-from = cacheFrom("hypercube", "amd64") + tags = tags("hypercube", "amd64") +} + +target "java-amd64" { + inherits = ["java-common", "amd64-common"] + contexts = dependencies("java", "amd64") + cache-from = cacheFrom("java", "amd64") + tags = tags("java", "amd64") +} + +target "mariadb-amd64" { + inherits = ["mariadb-common", "amd64-common"] + contexts = dependencies("mariadb", "amd64") + cache-from = cacheFrom("mariadb", "amd64") + tags = tags("mariadb", "amd64") +} + +target "matomo-amd64" { + inherits = ["matomo-common", "amd64-common"] + contexts = dependencies("matomo", "amd64") + cache-from = cacheFrom("matomo", "amd64") + tags = tags("matomo", "amd64") +} + +target "milliner-amd64" { + inherits = ["milliner-common", "amd64-common"] + contexts = dependencies("milliner", "amd64") + cache-from = cacheFrom("milliner", "amd64") + tags = tags("milliner", "amd64") +} + +target "nginx-amd64" { + inherits = ["nginx-common", "amd64-common"] + contexts = dependencies("nginx", "amd64") + cache-from = cacheFrom("nginx", "amd64") + tags = tags("nginx", "amd64") +} + +target "postgresql-amd64" { + inherits = ["postgresql-common", "amd64-common"] + contexts = dependencies("postgresql", "amd64") + cache-from = cacheFrom("postgresql", "amd64") + tags = tags("postgresql", "amd64") +} + +target "riprap-amd64" { + inherits = ["riprap-common", "amd64-common"] + contexts = dependencies("riprap", "amd64") + cache-from = cacheFrom("riprap", "amd64") + tags = tags("riprap", "amd64") +} + +target "solr-amd64" { + inherits = ["solr-common", "amd64-common"] + contexts = dependencies("solr", "amd64") + cache-from = cacheFrom("solr", "amd64") + tags = tags("solr", "amd64") +} + +target "test-amd64" { + inherits = ["test-common", "amd64-common"] + contexts = dependencies("test", "amd64") + cache-from = cacheFrom("test", "amd64") + tags = tags("test", "amd64") +} + +target "tomcat-amd64" { + inherits = ["tomcat-common", "amd64-common"] + contexts = dependencies("tomcat", "amd64") + cache-from = cacheFrom("tomcat", "amd64") + tags = tags("tomcat", "amd64") +} + +############################################################################### +# linux/arm64 targets. +############################################################################### +target "activemq-arm64" { + inherits = ["activemq-common", "arm64-common"] + contexts = dependencies("activemq", "arm64") + cache-from = cacheFrom("activemq", "arm64") + tags = tags("activemq", "arm64") +} + +target "alpaca-arm64" { + inherits = ["alpaca-common", "arm64-common"] + contexts = dependencies("alpaca", "arm64") + cache-from = cacheFrom("alpaca", "arm64") + tags = tags("alpaca", "arm64") +} + +target "base-arm64" { + inherits = ["base-common", "arm64-common"] + cache-from = cacheFrom("base", "arm64") + tags = tags("base", "arm64") +} + +target "blazegraph-arm64" { + inherits = ["blazegraph-common", "arm64-common"] + contexts = dependencies("blazegraph", "arm64") + cache-from = cacheFrom("blazegraph", "arm64") + tags = tags("blazegraph", "arm64") +} + +target "cantaloupe-arm64" { + inherits = ["cantaloupe-common", "arm64-common"] + contexts = dependencies("cantaloupe", "arm64") + cache-from = cacheFrom("cantaloupe", "arm64") + tags = tags("cantaloupe", "arm64") +} + +target "code-server-arm64" { + inherits = ["code-server-common", "arm64-common"] + contexts = dependencies("code-server", "arm64") + cache-from = cacheFrom("code-server", "arm64") + tags = tags("code-server", "arm64") +} + +target "crayfish-arm64" { + inherits = ["crayfish-common", "arm64-common"] + contexts = dependencies("crayfish", "arm64") + cache-from = cacheFrom("crayfish", "arm64") + tags = tags("crayfish", "arm64") +} + +target "crayfits-arm64" { + inherits = ["crayfits-common", "arm64-common"] + contexts = dependencies("crayfits", "arm64") + cache-from = cacheFrom("crayfits", "arm64") + tags = tags("crayfits", "arm64") +} + +target "drupal-arm64" { + inherits = ["drupal-common", "arm64-common"] + contexts = dependencies("drupal", "arm64") + cache-from = cacheFrom("drupal", "arm64") + tags = tags("drupal", "arm64") +} + +target "fcrepo6-arm64" { + inherits = ["fcrepo6-common", "arm64-common"] + contexts = dependencies("fcrepo6", "arm64") + cache-from = cacheFrom("fcrepo6", "arm64") + tags = tags("fcrepo6", "arm64") +} + +target "fits-arm64" { + inherits = ["fits-common", "arm64-common"] + contexts = dependencies("fits", "arm64") + cache-from = cacheFrom("fits", "arm64") + tags = tags("fits", "arm64") +} + +target "handle-arm64" { + inherits = ["handle-common", "arm64-common"] + contexts = dependencies("handle", "arm64") + cache-from = cacheFrom("handle", "arm64") + tags = tags("handle", "arm64") +} + +target "homarus-arm64" { + inherits = ["homarus-common", "arm64-common"] + contexts = dependencies("homarus", "arm64") + cache-from = cacheFrom("homarus", "arm64") + tags = tags("homarus", "arm64") +} + +target "houdini-arm64" { + inherits = ["houdini-common", "arm64-common"] + contexts = dependencies("houdini", "arm64") + cache-from = cacheFrom("houdini", "arm64") + tags = tags("houdini", "arm64") +} + +target "hypercube-arm64" { + inherits = ["hypercube-common", "arm64-common"] + contexts = dependencies("hypercube", "arm64") + cache-from = cacheFrom("hypercube", "arm64") + tags = tags("hypercube", "arm64") +} + +target "java-arm64" { + inherits = ["java-common", "arm64-common"] + contexts = dependencies("java", "arm64") + cache-from = cacheFrom("java", "arm64") + tags = tags("java", "arm64") +} + +target "mariadb-arm64" { + inherits = ["mariadb-common", "arm64-common"] + contexts = dependencies("mariadb", "arm64") + cache-from = cacheFrom("mariadb", "arm64") + tags = tags("mariadb", "arm64") +} + +target "matomo-arm64" { + inherits = ["matomo-common", "arm64-common"] + contexts = dependencies("matomo", "arm64") + cache-from = cacheFrom("matomo", "arm64") + tags = tags("matomo", "arm64") +} + +target "milliner-arm64" { + inherits = ["milliner-common", "arm64-common"] + contexts = dependencies("milliner", "arm64") + cache-from = cacheFrom("milliner", "arm64") + tags = tags("milliner", "arm64") +} + +target "nginx-arm64" { + inherits = ["nginx-common", "arm64-common"] + contexts = dependencies("nginx", "arm64") + cache-from = cacheFrom("nginx", "arm64") + tags = tags("nginx", "arm64") +} + +target "postgresql-arm64" { + inherits = ["postgresql-common", "arm64-common"] + contexts = dependencies("postgresql", "arm64") + cache-from = cacheFrom("postgresql", "arm64") + tags = tags("postgresql", "arm64") +} + +target "riprap-arm64" { + inherits = ["riprap-common", "arm64-common"] + contexts = dependencies("riprap", "arm64") + cache-from = cacheFrom("riprap", "arm64") + tags = tags("riprap", "arm64") +} + +target "solr-arm64" { + inherits = ["solr-common", "arm64-common"] + contexts = dependencies("solr", "arm64") + cache-from = cacheFrom("solr", "arm64") + tags = tags("solr", "arm64") +} + +target "test-arm64" { + inherits = ["test-common", "arm64-common"] + contexts = dependencies("test", "arm64") + cache-from = cacheFrom("test", "arm64") + tags = tags("test", "arm64") +} + +target "tomcat-arm64" { + inherits = ["tomcat-common", "arm64-common"] + contexts = dependencies("tomcat", "arm64") + cache-from = cacheFrom("tomcat", "arm64") + tags = tags("tomcat", "arm64") +} + +############################################################################### +# CI linux/amd64 targets. +############################################################################### +target "activemq-amd64-ci" { + inherits = ["activemq-amd64"] + contexts = dependencies("activemq", "amd64-ci") + cache-to = cacheTo("activemq", "amd64") +} + +target "alpaca-amd64-ci" { + inherits = ["alpaca-amd64"] + contexts = dependencies("alpaca", "amd64-ci") + cache-to = cacheTo("alpaca", "amd64") +} + +target "base-amd64-ci" { + inherits = ["base-amd64"] + cache-to = cacheTo("base", "amd64") +} + +target "blazegraph-amd64-ci" { + inherits = ["blazegraph-amd64"] + contexts = dependencies("blazegraph", "amd64-ci") + cache-to = cacheTo("blazegraph", "amd64") +} + +target "cantaloupe-amd64-ci" { + inherits = ["cantaloupe-amd64"] + contexts = dependencies("cantaloupe", "amd64-ci") + cache-to = cacheTo("cantaloupe", "amd64") +} + +target "code-server-amd64-ci" { + inherits = ["code-server-amd64"] + contexts = dependencies("code-server", "amd64-ci") + cache-to = cacheTo("code-server", "amd64") +} + +target "crayfish-amd64-ci" { + inherits = ["crayfish-amd64"] + contexts = dependencies("crayfish", "amd64-ci") + cache-to = cacheTo("crayfish", "amd64") +} + +target "crayfits-amd64-ci" { + inherits = ["crayfits-amd64"] + contexts = dependencies("crayfits", "amd64-ci") + cache-to = cacheTo("crayfits", "amd64") +} + +target "drupal-amd64-ci" { + inherits = ["drupal-amd64"] + contexts = dependencies("drupal", "amd64-ci") + cache-to = cacheTo("drupal", "amd64") +} + +target "fcrepo6-amd64-ci" { + inherits = ["fcrepo6-amd64"] + contexts = dependencies("fcrepo6", "amd64-ci") + cache-to = cacheTo("fcrepo6", "amd64") +} + +target "fits-amd64-ci" { + inherits = ["fits-amd64"] + contexts = dependencies("fits", "amd64-ci") + cache-to = cacheTo("fits", "amd64") +} + +target "handle-amd64-ci" { + inherits = ["handle-amd64"] + contexts = dependencies("handle", "amd64-ci") + cache-to = cacheTo("handle", "amd64") +} + +target "homarus-amd64-ci" { + inherits = ["homarus-amd64"] + contexts = dependencies("homarus", "amd64-ci") + cache-to = cacheTo("homarus", "amd64") +} + +target "houdini-amd64-ci" { + inherits = ["houdini-amd64"] + contexts = dependencies("houdini", "amd64-ci") + cache-to = cacheTo("houdini", "amd64") +} + +target "hypercube-amd64-ci" { + inherits = ["hypercube-amd64"] + contexts = dependencies("hypercube", "amd64-ci") + cache-to = cacheTo("hypercube", "amd64") +} + +target "java-amd64-ci" { + inherits = ["java-amd64"] + contexts = dependencies("java", "amd64-ci") + cache-to = cacheTo("java", "amd64") +} + +target "mariadb-amd64-ci" { + inherits = ["mariadb-amd64"] + contexts = dependencies("mariadb", "amd64-ci") + cache-to = cacheTo("mariadb", "amd64") +} + +target "matomo-amd64-ci" { + inherits = ["matomo-amd64"] + contexts = dependencies("matomo", "amd64-ci") + cache-to = cacheTo("matomo", "amd64") +} + +target "milliner-amd64-ci" { + inherits = ["milliner-amd64"] + contexts = dependencies("milliner", "amd64-ci") + cache-to = cacheTo("milliner", "amd64") +} + +target "nginx-amd64-ci" { + inherits = ["nginx-amd64"] + contexts = dependencies("nginx", "amd64-ci") + cache-to = cacheTo("nginx", "amd64") +} + +target "postgresql-amd64-ci" { + inherits = ["postgresql-amd64"] + contexts = dependencies("postgresql", "amd64-ci") + cache-to = cacheTo("postgresql", "amd64") +} + +target "riprap-amd64-ci" { + inherits = ["riprap-amd64"] + contexts = dependencies("riprap", "amd64-ci") + cache-to = cacheTo("riprap", "amd64") +} + +target "solr-amd64-ci" { + inherits = ["solr-amd64"] + contexts = dependencies("solr", "amd64-ci") + cache-to = cacheTo("solr", "amd64") +} + +target "test-amd64-ci" { + inherits = ["test-amd64"] + contexts = dependencies("test", "amd64-ci") + cache-to = cacheTo("test", "amd64") +} + +target "tomcat-amd64-ci" { + inherits = ["tomcat-amd64"] + contexts = dependencies("tomcat", "amd64-ci") + cache-to = cacheTo("tomcat", "amd64") +} + +############################################################################### +# CI linux/arm64 targets. +# +# Sets `cache-to` (requires authentication against the image registry). +############################################################################### +target "activemq-arm64-ci" { + inherits = ["activemq-arm64"] + contexts = dependencies("activemq", "arm64-ci") + cache-to = cacheTo("activemq", "arm64") +} + +target "alpaca-arm64-ci" { + inherits = ["alpaca-arm64"] + contexts = dependencies("alpaca", "arm64-ci") + cache-to = cacheTo("alpaca", "arm64") +} + +target "base-arm64-ci" { + inherits = ["base-arm64"] + cache-to = cacheTo("base", "arm64") +} + +target "blazegraph-arm64-ci" { + inherits = ["blazegraph-arm64"] + contexts = dependencies("blazegraph", "arm64-ci") + cache-to = cacheTo("blazegraph", "arm64") +} + +target "cantaloupe-arm64-ci" { + inherits = ["cantaloupe-arm64"] + contexts = dependencies("cantaloupe", "arm64-ci") + cache-to = cacheTo("cantaloupe", "arm64") +} + +target "code-server-arm64-ci" { + inherits = ["code-server-arm64"] + contexts = dependencies("code-server", "arm64-ci") + cache-to = cacheTo("code-server", "arm64") +} + +target "crayfish-arm64-ci" { + inherits = ["crayfish-arm64"] + contexts = dependencies("crayfish", "arm64-ci") + cache-to = cacheTo("crayfish", "arm64") +} + +target "crayfits-arm64-ci" { + inherits = ["crayfits-arm64"] + contexts = dependencies("crayfits", "arm64-ci") + cache-to = cacheTo("crayfits", "arm64") +} + +target "drupal-arm64-ci" { + inherits = ["drupal-arm64"] + contexts = dependencies("drupal", "arm64-ci") + cache-to = cacheTo("drupal", "arm64") +} + +target "fcrepo6-arm64-ci" { + inherits = ["fcrepo6-arm64"] + contexts = dependencies("fcrepo6", "arm64-ci") + cache-to = cacheTo("fcrepo6", "arm64") +} + +target "fits-arm64-ci" { + inherits = ["fits-arm64"] + contexts = dependencies("fits", "arm64-ci") + cache-to = cacheTo("fits", "arm64") +} + +target "handle-arm64-ci" { + inherits = ["handle-arm64"] + contexts = dependencies("handle", "arm64-ci") + cache-to = cacheTo("handle", "arm64") +} + +target "homarus-arm64-ci" { + inherits = ["homarus-arm64"] + contexts = dependencies("homarus", "arm64-ci") + cache-to = cacheTo("homarus", "arm64") +} + +target "houdini-arm64-ci" { + inherits = ["houdini-arm64"] + contexts = dependencies("houdini", "arm64-ci") + cache-to = cacheTo("houdini", "arm64") +} + +target "hypercube-arm64-ci" { + inherits = ["hypercube-arm64"] + contexts = dependencies("hypercube", "arm64-ci") + cache-to = cacheTo("hypercube", "arm64") +} + +target "java-arm64-ci" { + inherits = ["java-arm64"] + contexts = dependencies("java", "arm64-ci") + cache-to = cacheTo("java", "arm64") +} + +target "mariadb-arm64-ci" { + inherits = ["mariadb-arm64"] + contexts = dependencies("mariadb", "arm64-ci") + cache-to = cacheTo("mariadb", "arm64") +} + +target "matomo-arm64-ci" { + inherits = ["matomo-arm64"] + contexts = dependencies("matomo", "arm64-ci") + cache-to = cacheTo("matomo", "arm64") +} + +target "milliner-arm64-ci" { + inherits = ["milliner-arm64"] + contexts = dependencies("milliner", "arm64-ci") + cache-to = cacheTo("milliner", "arm64") +} + +target "nginx-arm64-ci" { + inherits = ["nginx-arm64"] + contexts = dependencies("nginx", "arm64-ci") + cache-to = cacheTo("nginx", "arm64") +} + +target "postgresql-arm64-ci" { + inherits = ["postgresql-arm64"] + contexts = dependencies("postgresql", "arm64-ci") + cache-to = cacheTo("postgresql", "arm64") +} + +target "riprap-arm64-ci" { + inherits = ["riprap-arm64"] + contexts = dependencies("riprap", "arm64-ci") + cache-to = cacheTo("riprap", "arm64") +} + +target "solr-arm64-ci" { + inherits = ["solr-arm64"] + contexts = dependencies("solr", "arm64-ci") + cache-to = cacheTo("solr", "arm64") +} + +target "test-arm64-ci" { + inherits = ["test-arm64"] + contexts = dependencies("test", "arm64-ci") + cache-to = cacheTo("test", "arm64") +} + +target "tomcat-arm64-ci" { + inherits = ["tomcat-arm64"] + contexts = dependencies("tomcat", "arm64-ci") + cache-to = cacheTo("tomcat", "arm64") +} diff --git a/docker-compose.darwin.yml b/docker-compose.darwin.yml new file mode 100644 index 00000000..c9d99b9f --- /dev/null +++ b/docker-compose.darwin.yml @@ -0,0 +1,8 @@ +version: "3.8" +services: + ide: + environment: + SSH_AUTH_SOCK: /run/host-services/ssh-auth.sock + volumes: + # Mount SSH agent so we can authenticate against github inside of the IDE container. + - /run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock diff --git a/docker-compose.linux.yml b/docker-compose.linux.yml new file mode 100644 index 00000000..9b0c4a41 --- /dev/null +++ b/docker-compose.linux.yml @@ -0,0 +1,8 @@ +version: "3.8" +services: + ide: + environment: + SSH_AUTH_SOCK: ${SSH_AUTH_SOCK} + volumes: + # Mount SSH agent so we can authenticate against github inside of the IDE container. + - ${SSH_AUTH_SOCK}:${SSH_AUTH_SOCK} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..f93b4fc6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,346 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + secrets: + - source: CERT_PUBLIC_KEY + - source: CERT_PRIVATE_KEY + - source: CERT_AUTHORITY + +x-traefik-https-redirect-middleware: &traefik-https-redirect-middleware + traefik.enable: true + traefik.http.middlewares.https-redirect.redirectscheme.permanent: true + traefik.http.middlewares.https-redirect.redirectscheme.scheme: https + +x-traefik-https-redirect: &traefik-https-redirect https-redirect + +networks: + default: + +volumes: + activemq-data: {} + blazegraph-data: {} + cantaloupe-data: {} + code-server-data: {} + drupal-private-files: {} + drupal-public-files: {} + drupal-root: {} + drupal-solr-config: {} + fcrepo-data: {} + mariadb-data: {} + matomo-data: {} + solr-data: {} + +secrets: + CERT_PUBLIC_KEY: + file: ./build/certs/cert.pem + CERT_PRIVATE_KEY: + file: ./build/certs/privkey.pem + CERT_AUTHORITY: + file: ./build/certs/rootCA.pem + +services: + alpaca: + <<: *common + image: ${REPOSITORY:-local}/alpaca:${TAG:-latest} + crayfits: + <<: *common + image: ${REPOSITORY:-local}/crayfits:${TAG:-latest} + fits: + <<: *common + image: ${REPOSITORY:-local}/fits:${TAG:-latest} + homarus: + <<: *common + image: ${REPOSITORY:-local}/homarus:${TAG:-latest} + houdini: + <<: *common + image: ${REPOSITORY:-local}/houdini:${TAG:-latest} + hypercube: + <<: *common + image: ${REPOSITORY:-local}/hypercube:${TAG:-latest} + mariadb: + <<: *common + image: ${REPOSITORY:-local}/mariadb:${TAG:-latest} + volumes: + - mariadb-data:/var/lib/mysql:rw + milliner: + <<: *common + image: ${REPOSITORY:-local}/milliner:${TAG:-latest} + activemq: + <<: *common + image: ${REPOSITORY:-local}/activemq:${TAG:-latest} + labels: + <<: *traefik-https-redirect-middleware + traefik.http.routers.activemq_http.entrypoints: http + traefik.http.routers.activemq_http.middlewares: *traefik-https-redirect + traefik.http.routers.activemq_http.rule: &traefik-host-activemq Host(`activemq.islandora.dev`) + traefik.http.routers.activemq_http.service: activemq + traefik.http.routers.activemq_https.entrypoints: https + traefik.http.routers.activemq_https.rule: *traefik-host-activemq + traefik.http.routers.activemq_https.tls: true + traefik.http.services.activemq.loadbalancer.server.port: 8161 + traefik.subdomain: activemq + volumes: + - activemq-data:/opt/activemq/data:rw + blazegraph: + <<: *common + image: ${REPOSITORY:-local}/blazegraph:${TAG:-latest} + labels: + <<: *traefik-https-redirect-middleware + traefik.http.routers.blazegraph_http.entrypoints: http + traefik.http.routers.blazegraph_http.middlewares: *traefik-https-redirect + traefik.http.routers.blazegraph_http.rule: &traefik-host-blazegraph Host(`blazegraph.islandora.dev`) + traefik.http.routers.blazegraph_http.service: blazegraph + traefik.http.routers.blazegraph_https.entrypoints: https + traefik.http.routers.blazegraph_https.rule: *traefik-host-blazegraph + traefik.http.routers.blazegraph_https.tls: true + traefik.http.services.blazegraph.loadbalancer.server.port: 8080 + volumes: + - blazegraph-data:/data:rw + cantaloupe: + <<: *common + image: ${REPOSITORY:-local}/cantaloupe:${TAG:-latest} + labels: + <<: *traefik-https-redirect-middleware + traefik.http.middlewares.cantaloupe-custom-request-headers.headers.customrequestheaders.X-Forwarded-Path: /cantaloupe + traefik.http.middlewares.cantaloupe-strip-prefix.stripprefix.prefixes: /cantaloupe + traefik.http.middlewares.cantaloupe.chain.middlewares: cantaloupe-strip-prefix,cantaloupe-custom-request-headers + traefik.http.routers.cantaloupe_http.entrypoints: http + traefik.http.routers.cantaloupe_http.middlewares: *traefik-https-redirect + traefik.http.routers.cantaloupe_http.rule: &traefik-host-cantaloupe Host(`islandora.dev`) && PathPrefix(`/cantaloupe`) + traefik.http.routers.cantaloupe_http.service: cantaloupe + traefik.http.routers.cantaloupe_https.middlewares: cantaloupe + traefik.http.routers.cantaloupe_https.entrypoints: https + traefik.http.routers.cantaloupe_https.rule: *traefik-host-cantaloupe + traefik.http.routers.cantaloupe_https.tls: true + traefik.http.services.cantaloupe.loadbalancer.server.port: 8182 + volumes: + - cantaloupe-data:/data:rw + drupal: + <<: *common + image: ${REPOSITORY:-local}/test:${TAG:-latest} + environment: + &drupal-environment # Keep this in sync with "islandora.drupal.properties" in the helm chart. + DRUPAL_DEFAULT_CANTALOUPE_URL: "https://islandora.dev/cantaloupe/iiif/2" + DRUPAL_DEFAULT_CONFIGDIR: "/var/www/drupal/config/sync" + DRUPAL_DEFAULT_FCREPO_HOST: "fcrepo" + DRUPAL_DEFAULT_FCREPO_PORT: 8080 + DRUPAL_DEFAULT_FCREPO_URL: "https://fcrepo.islandora.dev/fcrepo/rest/" + DRUPAL_DEFAULT_INSTALL_EXISTING_CONFIG: "true" + DRUPAL_DEFAULT_MATOMO_URL_HTTP: "http://islandora.dev/matomo/" + DRUPAL_DEFAULT_MATOMO_URL_HTTPS: "https://islandora.dev/matomo/" + DRUPAL_DEFAULT_NAME: "Islandora Digital Collections" + DRUPAL_DEFAULT_PROFILE: "minimal" + DRUPAL_DEFAULT_SITE_URL: "islandora.dev" + DRUPAL_DEFAULT_SOLR_CORE: "default" + DRUPAL_DRUSH_URI: "https://islandora.dev" # Used by docker/drupal/rootfs/usr/local/share/custom/install.sh + volumes: + # Allow code-server to serve Drupal / override it. + - &drupal-root + type: volume + source: drupal-root + target: /var/www/drupal + - &drupal-public-files + type: volume + source: drupal-public-files + target: /var/www/drupal/web/sites/default/files + - &drupal-private-files + type: volume + source: drupal-private-files + target: /var/www/drupal/private + - &drupal-custom-modules ./test/rootfs/var/www/drupal/web/modules/custom/sample_content:/var/www/drupal/web/modules/custom/sample_content:rw + - drupal-solr-config:/opt/solr/server/solr/default:ro + ide: + <<: *common + image: ${REPOSITORY}/code-server:${TAG} + labels: + <<: *traefik-https-redirect-middleware + # All Drupal traefik is routed through the IDE so that XDebug can be + # easily used. + traefik.http.routers.drupal_http.entrypoints: http + traefik.http.routers.drupal_http.middlewares: *traefik-https-redirect + traefik.http.routers.drupal_http.rule: &traefik-host-drupal Host(`islandora.dev`) + traefik.http.routers.drupal_http.service: drupal + traefik.http.routers.drupal_https.entrypoints: https + traefik.http.routers.drupal_https.rule: *traefik-host-drupal + traefik.http.routers.drupal_https.service: drupal + traefik.http.routers.drupal_https.tls: true + traefik.http.services.drupal.loadbalancer.server.port: 80 + traefik.http.routers.ide_http.entrypoints: http + traefik.http.routers.ide_http.middlewares: *traefik-https-redirect + traefik.http.routers.ide_http.rule: &traefik-host-ide Host(`ide.islandora.dev`) + traefik.http.routers.ide_http.service: ide + traefik.http.routers.ide_https.entrypoints: https + traefik.http.routers.ide_https.rule: *traefik-host-ide + traefik.http.routers.ide_https.service: ide + traefik.http.routers.ide_https.tls: true + traefik.http.services.ide.loadbalancer.server.port: 8443 + traefik.tcp.routers.ssh.entrypoints: ssh + traefik.tcp.routers.ssh.rule: HostSNI(`*`) + traefik.tcp.routers.ssh.service: ssh + traefik.tcp.services.ssh.loadbalancer.server.port: 22 + + environment: + <<: *drupal-environment + # Allow XDebug to be used with Drush as well. + # Use the following command in the IDE shell to enable it: + # export XDEBUG_SESSION=1 + DRUSH_ALLOW_XDEBUG: 1 + XDEBUG_MODE: debug + # Do not request a password for accessing the IDE. + CODE_SERVER_AUTHENTICATION: none + # Bump up time outs to allow for debugging. + NGINX_CLIENT_BODY_TIMEOUT: 600s + NGINX_FASTCGI_CONNECT_TIMEOUT: 600s + NGINX_FASTCGI_READ_TIMEOUT: 1200s + NGINX_FASTCGI_SEND_TIMEOUT: 600s + NGINX_KEEPALIVE_TIMEOUT: 750s + NGINX_LINGERING_TIMEOUT: 50s + NGINX_PROXY_CONNECT_TIMEOUT: 600s + NGINX_PROXY_READ_TIMEOUT: 600s + NGINX_PROXY_SEND_TIMEOUT: 600s + NGINX_SEND_TIMEOUT: 600s + PHP_DEFAULT_SOCKET_TIMEOUT: 600 + PHP_MAX_EXECUTION_TIME: 300 + PHP_MAX_INPUT_TIME: 600 + PHP_PROCESS_CONTROL_TIMEOUT: 600 + PHP_REQUEST_TERMINATE_TIMEOUT: 600 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + # Mount and serve contents of Drupal site. + - <<: *drupal-root + volume: + nocopy: true + # Mount and serve Drupal public files. + - <<: *drupal-public-files + volume: + nocopy: true + # Mount and serve Drupal private files. + - <<: *drupal-private-files + volume: + nocopy: true + # Volumes for code-server cache. + - type: volume + source: code-server-data + target: /opt/code-server/data + - *drupal-custom-modules + # Ensure drupal mounts the shared volumes first. + depends_on: + - drupal + fcrepo: + <<: *common + image: ${REPOSITORY}/fcrepo6:${TAG} + environment: + FCREPO_ALLOW_EXTERNAL_DEFAULT: "http://default/" + FCREPO_ALLOW_EXTERNAL_DRUPAL: "https://islandora.dev/" + labels: + <<: *traefik-https-redirect-middleware + # Due to weird logic in `fcrepo/static/js/common.js`, do not use https + # as it assumes it always needs to append /fcr:metadata to every request + # breaking the links. Though for files we do want that page to be accessed + # so check for a file extension. + traefik.http.middlewares.fcrepo-strip-suffix.replacepathregex.regex: "^(.*/fcrepo/rest/[^.]*)/fcr:metadata$$" + traefik.http.middlewares.fcrepo-strip-suffix.replacepathregex.replacement: "$$1" + traefik.http.routers.fcrepo_http.entrypoints: http + traefik.http.routers.fcrepo_http.middlewares: *traefik-https-redirect + traefik.http.routers.fcrepo_http.rule: &traefik-host-fcrepo Host(`fcrepo.islandora.dev`) + traefik.http.routers.fcrepo_http.service: fcrepo + traefik.http.routers.fcrepo_https.entrypoints: https + traefik.http.routers.fcrepo_https.middlewares: fcrepo-strip-suffix + traefik.http.routers.fcrepo_https.rule: *traefik-host-fcrepo + traefik.http.routers.fcrepo_https.tls: true + traefik.http.services.fcrepo.loadbalancer.server.port: 8080 + volumes: + - fcrepo-data:/data:rw + matomo: + <<: *common + image: ${REPOSITORY:-local}/matomo:${TAG:-latest} + labels: + <<: *traefik-https-redirect-middleware + traefik.http.middlewares.matomo-custom-request-headers.headers.customrequestheaders.X-Forwarded-Uri: /matomo + traefik.http.middlewares.matomo-append-slash.redirectregex.regex: ^(https?://[^/]+/matomo)$$ + traefik.http.middlewares.matomo-append-slash.redirectregex.replacement: $${1}/ + traefik.http.middlewares.matomo-strip-prefix.stripprefix.prefixes: /matomo + traefik.http.middlewares.matomo.chain.middlewares: matomo-append-slash,matomo-strip-prefix,matomo-custom-request-headers + traefik.http.routers.matomo_http.entrypoints: http + traefik.http.routers.matomo_http.middlewares: *traefik-https-redirect + traefik.http.routers.matomo_http.rule: &traefik-host-matomo Host(`islandora.dev`) && PathPrefix(`/matomo`) + traefik.http.routers.matomo_http.service: matomo + traefik.http.routers.matomo_https.entrypoints: https + traefik.http.routers.matomo_https.middlewares: matomo + traefik.http.routers.matomo_https.rule: *traefik-host-matomo + traefik.http.routers.matomo_https.tls: true + traefik.http.services.matomo.loadbalancer.server.port: 80 + environment: + MATOMO_DEFAULT_HOST: "https://islandora.dev" + volumes: + - matomo-data:/var/www/matomo:rw + solr: + <<: *common + image: ${REPOSITORY:-local}/solr:${TAG:-latest} + labels: + <<: *traefik-https-redirect-middleware + traefik.http.routers.solr_http.entrypoints: http + traefik.http.routers.solr_http.middlewares: *traefik-https-redirect + traefik.http.routers.solr_http.rule: &traefik-host-solr Host(`solr.islandora.dev`) + traefik.http.routers.solr_http.service: solr + traefik.http.routers.solr_https.entrypoints: https + traefik.http.routers.solr_https.rule: *traefik-host-solr + traefik.http.routers.solr_https.tls: true + traefik.http.services.solr.loadbalancer.server.port: 8983 + volumes: + - solr-data:/data:rw + - type: volume + source: drupal-solr-config + target: /opt/solr/server/solr/default + volume: + nocopy: true + traefik: + <<: *common + image: traefik:v2.8.3 + command: >- + --api.insecure=true + --api.dashboard=true + --api.debug=true + --entryPoints.http.address=:80 + --entryPoints.https.address=:443 + --entryPoints.ssh.address=:22 + --providers.file.filename=/etc/traefik/tls.yml + --providers.docker=true + --providers.docker.network=default + --providers.docker.exposedByDefault=false + '--providers.docker.defaultRule=Host(`{{index .Labels "com.docker.compose.service" }}.islandora.dev`)' + labels: + <<: *traefik-https-redirect-middleware + traefik.http.routers.traefik_http.entrypoints: http + traefik.http.routers.traefik_http.middlewares: *traefik-https-redirect + traefik.http.routers.traefik_http.service: traefik + traefik.http.routers.traefik_https.entrypoints: https + traefik.http.routers.traefik_https.tls: true + traefik.http.services.traefik.loadbalancer.server.port: 8080 + ports: + - "80:80" + - "443:443" + - "2222:22" + volumes: + - ./build/certs:/etc/ssl/traefik:rw + - ./tls.yml:/etc/traefik/tls.yml:rw + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + default: + aliases: + # Allow services to connect on the same name/port as the outside. + - blazegraph.islandora.dev + - fcrepo.islandora.dev + - islandora.dev + - solr.islandora.dev + depends_on: + # Sometimes traefik doesn't pick up on new containers so make sure they are started before traefik. + - activemq + - blazegraph + - drupal + - fcrepo + - solr + - ide diff --git a/docs/assets/phpstorm.gif b/docs/assets/phpstorm.gif new file mode 100644 index 00000000..fa71e295 Binary files /dev/null and b/docs/assets/phpstorm.gif differ diff --git a/docs/maintainers/release_process.md b/docs/maintainers/release_process.md new file mode 100644 index 00000000..4ebdd923 --- /dev/null +++ b/docs/maintainers/release_process.md @@ -0,0 +1,86 @@ +# isle-buildkit Release Process + +## Monthly Release process steps + +* On the second week of every month the ISLE release manager will organize: + * A new release [discussions thread](https://github.com/Islandora-Devops/isle-buildkit/discussions) for communication between all ISLE maintainers and the community + * The title will typically be something like `Release 1.0.0` etc with a message like `Determining what is to be included before we make 1.0.0 release.` + * [Example](https://github.com/Islandora-Devops/isle-buildkit/discussions/193) + * The Release manager will follow up with all maintainers for assignments. + * A new release [project](https://github.com/Islandora-Devops/isle-buildkit/projects) for determining what work is to be done + * The title will typically be something like `March / April 2022 - isle-buildkit 1.0.0 release` + * [Example](https://github.com/Islandora-Devops/isle-buildkit/projects/2) + * A list of outstanding PRs will be compiled and assigned + +--- + +## PR & testing process + +* When ISLE maintainers make a change via a git pull request (PR) + * ISLE maintainer should then assign a testing resource (_either another ISLE maintainer, community member or ISLE Release Manager_) + * PR creates new Docker images tag (TAG) using git commit hash + * Assigned testing resource can test this by + * `git clone git@github.com:Islandora-Devops/isle-dc.git` to local laptop + * `cd isle-dc` + * `cp sample.env .env` + * `vi / nano .env` + * Change `TAG` to appropriate git commit hash + * Run `make demo` + * QC site and report back on Github issue if pass / fail + +* Recommend the following for filing tickets / issues. Example below + +### Example for isle-buildkit testing + +```bash +Reporting results from testing process: + +#### Test Environment + +* OS: Ubuntu 20.04 LTS Desktop +* CPU: Intel i7-10510U (8 cores) @ 4.900 GHZ +* Mem: 32 GB + +--- + +#### Test process / steps + +When testing isle-buildkit +* `git clone git@github.com:Islandora-Devops/isle-buildkit.git` to local laptop +* `git checkout `/matomo-volume-redux` +* `./gradlew build` + +#### Results + +Describe output, expectation and steps. + +Include screenshots etc. +``` + +### Example for isle-dc testing + +```bash +Reporting results from testing process: + +#### Test Environment + +* OS: Ubuntu 20.04 LTS Desktop +* CPU: Intel i7-10510U (8 cores) @ 4.900 GHZ +* Mem: 32 GB + +--- + + * `git clone git@github.com:Islandora-Devops/isle-dc.git` to local laptop + * `cd isle-dc` + * `cp sample.env .env` + * `vi / nano .env` + * Change TAG to appropriate git commit hash + * `make demo` +--- + +#### Results + +Describe output, expectation and steps. + +Include screenshots etc. +``` diff --git a/docs/maintainers/testing_process.md b/docs/maintainers/testing_process.md new file mode 100644 index 00000000..e50ea8ef --- /dev/null +++ b/docs/maintainers/testing_process.md @@ -0,0 +1,55 @@ +#### isle-buildkit testing + +When testing isle-buildkit image releases or possible changes, a tester can: + +* clone down the latest `isle-dc` to their local laptop / workstation + * `git clone https://github.com/Islandora-Devops/isle-dc.git` + +* Look up the last commit hash in the PR on the isle-buildkit Github.com PR page. + * In this example - we'll be using this PR [Allow containers to run without allocating a tty.](https://github.com/Islandora-Devops/isle-buildkit/commits/issue-174) and the value `79de15828971c10894c3cdf14eec431434c457ea` which is both the commit hash and the resulting [Docker image](https://hub.docker.com/u/islandora) / tag needed for testing. + * In the image below one would click the overlapping squares icon to copy the full SHA of the commit. + +**Example** + +![Screenshot from 2022-04-28 15-00-42](https://user-images.githubusercontent.com/501554/165828803-088d6fe6-e9cf-4238-8cfe-d697fac64ef4.png) + +Within the newly cloned `isle-dc` project +* Copy the `sample.env` to `.env` as you'll need to edit the TAG value for testing + * `cp sample.env .env` +* Change **Line 65** within the new `.env` file to the test commit hash from above + * `nano / vi .env` + * e.g. `TAG=79de15828971c10894c3cdf14eec431434c457ea` + +* Follow the instructions from the isle-dc [Getting Started](https://github.com/Islandora-Devops/isle-dc#getting-started) section and run the following + * `make demo` + +* QC the resulting site at [https://islandora.traefik.me](https://islandora.traefik.me) + * Ensure that there aren't new errors in the Status page + * If additional testing parameters are called out in the ticket, review and test. + +* If everything passes or doesn't, update the PR / issue with the following style of response. + +```bash +#### Test Environment + +* OS: Ubuntu 20.04 LTS Desktop +* CPU: Intel i7-10510U (8 cores) @ 4.900 GHZ +* RAM: 32 GB + +--- + +#### Steps taken to test + + * `git clone git@github.com:Islandora-Devops/isle-dc.git` to local laptop + * `cd isle-dc` + * `cp sample.env .env` + * `vi / nano .env` + * Changed `TAG=` to `TAG=79de15828971c10894c3cdf14eec431434c457ea` + * `make demo` +--- + +#### Results + +Status = Working +@nigelgbanks @g7morris Process worked great. No errors to report. +``` diff --git a/docs/release-notes/release-template.md b/docs/release-notes/release-template.md new file mode 100644 index 00000000..73e6fe91 --- /dev/null +++ b/docs/release-notes/release-template.md @@ -0,0 +1,121 @@ +# Release Notes - isle-buildkit 03-2022 + +### Contributions to this release from: + +Code updates, documentation, testing + +* [Nigel Banks](https://github.com/nigelgbanks), Lead Dev +* [Don Richards](https://github.com/DonRichards) +* [Jeffrey Antoniuk](https://github.com/jefferya) +* [Gavin Morris](https://github.com/g7morris), Release Manager + +### Description + +* Updates for the following Gradle related software + + + + + +* Security and package updates for the following Docker images + * `apk upgrade --available` dist-upgrades for dependencies security and package updates + * abuild + * base + * build + * download + +* Updates, fixes or PRs merged for the following services or Docker images + +Release Manager to pull PRs from Release Sprint and copy here ---> + + + +#### isle-apache + + +* `ImageMagick` upgraded to version `7.1.0-25` +* `Apache Xerces` upgraded to `2.12.2` (_used with FITS_) +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-blazegraph + +* ISLE Tomcat base image upgrade +* `apt-get` dist-upgrades for dependencies security and package updates +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-fedora + +* ISLE Tomcat base image upgrade +* `apt-get` dist-upgrades for dependencies security and package updates +* Apache `Maven` **held** at version `3.6.3` despite a recent April `3.8.1` release. Breaks POM dependencies and blocks mirrors. +* Apache `Ant` **held** at version `1.10.9` despite a recent April `1.10.10` release. Upstream dependencies fail to download in Github Actions. +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-imageservices + +* ISLE Tomcat base image upgrade +* `apt-get` dist-upgrades for dependencies security and package updates +* `ImageMagick` upgraded to version `7.1.0-25` +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-mysql + +* `apt-get` dist-upgrades for dependencies security and package updates +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-solr + +* ISLE Tomcat base image upgrade +* `apt-get` dist-upgrades for dependencies security and package updates +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-tomcat + +* `apt-get` dist-upgrades for dependencies security and package updates +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated + +#### isle-varnish + +* `apt-get` dist-upgrades for dependencies security and package updates +* Github Actions [workflow](https://github.com/marketplace/actions/build-and-push-docker-images) updated diff --git a/drupal/.dockerignore b/drupal/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/drupal/.dockerignore +++ b/drupal/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/drupal/Dockerfile b/drupal/Dockerfile index 02f6d7ae..41b97e4e 100644 --- a/drupal/Dockerfile +++ b/drupal/Dockerfile @@ -1,23 +1,70 @@ -# syntax=docker/dockerfile:experimental -FROM local/nginx:latest - -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - DRUSH_VERSION="0.6.0" && \ - DRUSH_FILE="drush.phar" && \ - DRUSH_URL="https://github.com/drush-ops/drush-launcher/releases/download/${DRUSH_VERSION}/${DRUSH_FILE}" && \ - DRUSH_SHA256="c3f32a800a2f18470b0010cd71c49e49ef5c087f8131eecfe9b686dc1f3f3d4e" && \ - download.sh --url "${DRUSH_URL}" --sha256 "${DRUSH_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - cp "${DOWNLOAD_CACHE_DIRECTORY}/${DRUSH_FILE}" /usr/bin/drush && \ - chmod a+x /usr/bin/drush && \ - mkdir -p /var/www/drupal/config && \ - mkdir -p /var/www/drupal/web/libraries && \ - chown -R nginx:nginx /var/www && \ - mkdir -p /opt/keys/jwt && \ - chown nginx:nginx /opt/keys/jwt +# syntax=docker/dockerfile:1.5.1 +FROM nginx + +ARG TARGETARCH + +EXPOSE 80 WORKDIR /var/www/drupal -COPY rootfs / +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=drupal-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ + patch \ + && \ + mkdir -p \ + /var/www/drupal/config \ + /var/www/drupal/web/libraries \ + && \ + chown -R nginx:nginx /var/www && \ + addgroup nginx jwt && \ + cleanup.sh -EXPOSE 80 +# Installation typically needs more than the default 30 seconds defined in the +# base image. Set to 10 minutes just incase it ran on very old or overallocated +# hardware. +ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=600000 + +ENV \ + DRUPAL_DEFAULT_ACCOUNT_EMAIL=webmaster@localhost.com \ + DRUPAL_DEFAULT_ACCOUNT_NAME=admin \ + DRUPAL_DEFAULT_ACCOUNT_PASSWORD=password \ + DRUPAL_DEFAULT_BROKER_HOST=activemq \ + DRUPAL_DEFAULT_BROKER_PORT=61613 \ + DRUPAL_DEFAULT_BROKER_URL=tcp://activemq:61613 \ + DRUPAL_DEFAULT_BROKER_WEB_ADMIN_PASSWORD=password \ + DRUPAL_DEFAULT_BROKER_WEB_ADMIN_USER=admin \ + DRUPAL_DEFAULT_BROKER_WEB_PORT=8161 \ + DRUPAL_DEFAULT_CANTALOUPE_URL=https://islandora.traefik.me/cantaloupe/iiif/2 \ + DRUPAL_DEFAULT_CONFIGDIR=/var/www/drupal/config/sync \ + DRUPAL_DEFAULT_DB_NAME=drupal_default \ + DRUPAL_DEFAULT_DB_PASSWORD=password \ + DRUPAL_DEFAULT_DB_USER=drupal_default \ + DRUPAL_DEFAULT_EMAIL=webmaster@localhost.com \ + DRUPAL_DEFAULT_FCREPO_HOST=islandora.traefik.me \ + DRUPAL_DEFAULT_FCREPO_PORT=8081 \ + DRUPAL_DEFAULT_FITS_HOST=fits \ + DRUPAL_DEFAULT_FITS_PORT=8080 \ + DRUPAL_DEFAULT_INSTALL_EXISTING_CONFIG=false \ + DRUPAL_DEFAULT_INSTALL=true \ + DRUPAL_DEFAULT_LOCALE=en \ + DRUPAL_DEFAULT_MATOMO_URL_HTTP=http://islandora.traefik.me/matomo/ \ + DRUPAL_DEFAULT_MATOMO_URL_HTTPS=https://islandora.traefik.me/matomo/ \ + DRUPAL_DEFAULT_NAME=Default \ + DRUPAL_DEFAULT_PROFILE=standard \ + DRUPAL_DEFAULT_SALT=9PPaL0CxZAIcq0l9wxgDGlCZrp7JdT_x7v9gVzpdbUjMt1PqDz3uD0Zy-i16DuJ1-Htuq5hqeg \ + DRUPAL_DEFAULT_SITE_URL=https://islandora.traefik.me \ + DRUPAL_DEFAULT_SOLR_CORE=ISLANDORA \ + DRUPAL_DEFAULT_SOLR_HOST=solr \ + DRUPAL_DEFAULT_SOLR_PORT=8983 \ + DRUPAL_DEFAULT_SUBDIR=default \ + DRUPAL_DEFAULT_TRIPLESTORE_HOST=blazegraph \ + DRUPAL_DEFAULT_TRIPLESTORE_NAMESPACE=islandora \ + DRUPAL_DEFAULT_TRIPLESTORE_PORT=8080 \ + DRUPAL_ENABLE_HTTPS=true \ + DRUPAL_REVERSE_PROXY_IPS= \ + DRUPAL_SITES=DEFAULT + +COPY --link rootfs / + +RUN chown -R nginx:nginx /var/www diff --git a/drupal/README.md b/drupal/README.md index 807dcbef..8677dbc4 100644 --- a/drupal/README.md +++ b/drupal/README.md @@ -21,45 +21,80 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------------------ | :------------------------------- | :---------------------- | :-------------------------------------------------------- | -| DRUPAL_DB_DRIVER | /drupal/db/driver | mysql | The database driver | -| DRUPAL_DB_HOST | /drupal/db/host | database | The database host | -| DRUPAL_DB_PORT | /drupal/db/port | 3306 | The database port | -| DRUPAL_DB_ROOT_PASSWORD | /drupal/db/root/password | password | The database root user (used to create the site database) | -| DRUPAL_DB_ROOT_USER | /drupal/db/root/user | root | The database root user password | -| DRUPAL_DEFAULT_ACCOUNT_EMAIL | /drupal/default/account/email | webmaster@localhost.com | The email to use for the admin account | -| DRUPAL_DEFAULT_ACCOUNT_NAME | /drupal/default/account/name | admin | The Drupal administrator user | -| DRUPAL_DEFAULT_ACCOUNT_PASSWORD | /drupal/default/account/password | password | The Drupal administrator user password | -| DRUPAL_DEFAULT_DB_NAME | /drupal/default/db/name | drupal_default | The name of the sites database | -| DRUPAL_DEFAULT_DB_PASSWORD | /drupal/default/db/password | password | The database users password | -| DRUPAL_DEFAULT_DB_USER | /drupal/default/db/user | drupal_default | The database user used by the site | -| DRUPAL_DEFAULT_EMAIL | /drupal/default/email | webmaster@localhost.com | The Drupal administrators email | -| DRUPAL_DEFAULT_LOCALE | /drupal/default/locale | en | The Drupal sites locale | -| DRUPAL_DEFAULT_NAME | /drupal/default/name | default | The Drupal sites name | -| DRUPAL_DEFAULT_PROFILE | /drupal/default/profile | standard | The installation profile to use | -| DRUPAL_DEFAULT_SUBDIR | /drupal/default/subdir | default | The installation profile to use | -| DRUPAL_DEFAULT_CONFIGDIR | /drupal/default/configdir | | Install using existing config files from directory | -| DRUPAL_DEFAULT_INSTALL | /drupal/default/install | true | Perform install if not already installed | +### Network Settings + +| Environment Variable | Default | Description | +| :----------------------- | :------ | :--------------------------------------------------------------------------------- | +| DRUPAL_ENABLE_HTTPS | true | Inform PHP that `https` should be used. | +| DRUPAL_REVERSE_PROXY_IPS | | Use the IP address for the host 'traefik' if found otherwise default to `0.0.0.0`. | + +### Database Settings + +[Drupal] can make use of different database backends for storage. Please see the +documentation in the [base image] for more information about the default +database connection configuration. + +| Environment Variable | Default | Description | +| :------------------------------ | :------ | :------------------------------------------------------------------------------------ | +| DRUPAL_DEFAULT_DB_DRIVER | | The database driver. Defaults to `DB_DRIVER` | +| DRUPAL_DEFAULT_DB_HOST | | The database host. Defaults to `DB_HOST` | +| DRUPAL_DEFAULT_DB_PORT | | The database port. Defaults to `DB_PORT` | +| DRUPAL_DEFAULT_DB_ROOT_PASSWORD | | The database root user password. Defaults to `DB_ROOT_PASSWORD` | +| DRUPAL_DEFAULT_DB_ROOT_USER | | The database root user (used to create the site database). Defaults to `DB_ROOT_USER` | + +These variables also provide the default for their site specific variants such +as `DRUPAL_SITE_{SITE}_DB_HOST` are defined. + +### JWT Settings + +[Drupal] is expected to make use of JWT for authentication. Please see the +documentation in the [base image] for more information. + +The public/private key pair used here should be the same key as is used in the +`crayfish` and `fcrepo` based containers. + +### Default Site + +| Environment Variable | Default | Description | +| :------------------------------ | :---------------------- | :------------------------------------------------- | +| DRUPAL_DEFAULT_ACCOUNT_EMAIL | webmaster@localhost.com | The email to use for the admin account | +| DRUPAL_DEFAULT_ACCOUNT_NAME | admin | The Drupal administrator user | +| DRUPAL_DEFAULT_ACCOUNT_PASSWORD | password | The Drupal administrator user password | +| DRUPAL_DEFAULT_DB_NAME | drupal_default | The name of the sites database | +| DRUPAL_DEFAULT_DB_PASSWORD | password | The database users password | +| DRUPAL_DEFAULT_DB_USER | drupal_default | The database user used by the site | +| DRUPAL_DEFAULT_EMAIL | webmaster@localhost.com | The Drupal administrators email | +| DRUPAL_DEFAULT_LOCALE | en | The Drupal sites locale | +| DRUPAL_DEFAULT_NAME | default | The Drupal sites name | +| DRUPAL_DEFAULT_PROFILE | standard | The installation profile to use | +| DRUPAL_DEFAULT_SUBDIR | default | The installation profile to use | +| DRUPAL_DEFAULT_CONFIGDIR | | Install using existing config files from directory | +| DRUPAL_DEFAULT_INSTALL | true | Perform install if not already installed | + +Of the above you should provide at a minium your own passwords when running in +production. + +### Multi-site Additional multi-sites can be defined by adding more environment variables, following the above conventions, only the `DRUPAL_SITE_{SITE}_NAME` is required to create an additional site: -| Environment Variable | Etcd Key | Default | Description | -| :---------------------------------- | :----------------------------------- | :---------------------- | :------------------------------------------------- | -| DRUPAL_SITE_{SITE}_ACCOUNT_EMAIL | /drupal/site/{SITE}/account/email | webmaster@localhost.com | The email to use for the admin account | -| DRUPAL_SITE_{SITE}_ACCOUNT_NAME | /drupal/site/{SITE}/account/name | admin | The Drupal administrator user | -| DRUPAL_SITE_{SITE}_ACCOUNT_PASSWORD | /drupal/site/{SITE}/account/password | password | The Drupal administrator user password | -| DRUPAL_SITE_{SITE}_DB_NAME | /drupal/site/{SITE}/db/name | drupal_{SITE} | The name of the sites database | -| DRUPAL_SITE_{SITE}_DB_PASSWORD | /drupal/site/{SITE}/db/password | password | The database users password | -| DRUPAL_SITE_{SITE}_DB_USER | /drupal/site/{SITE}/db/user | drupal_{SITE} | The database user used by the site | -| DRUPAL_SITE_{SITE}_EMAIL | /drupal/site/{SITE}/email | webmaster@localhost.com | The Drupal administrators email | -| DRUPAL_SITE_{SITE}_LOCALE | /drupal/site/{SITE}/locale | en | The Drupal sites locale | -| DRUPAL_SITE_{SITE}_NAME | /drupal/site/{SITE}/name | | The Drupal sites name | -| DRUPAL_SITE_{SITE}_PROFILE | /drupal/site/{SITE}/profile | standard | The installation profile to use | -| DRUPAL_SITE_{SITE}_SUBDIR | /drupal/site/{SITE}/subdir | {SITE} | The subdirectory to install the sub-site into | -| DRUPAL_SITE_{SITE}_CONFIGDIR | /drupal/site/{SITE}/configdir | | Install using existing config files from directory | -| DRUPAL_SITE_{SITE}_INSTALL | /drupal/site/{SITE}/install | true | Perform install if not already installed | +| Environment Variable | Default | Description | +| :---------------------------------- | :---------------------- | :------------------------------------------------- | +| DRUPAL_SITE_{SITE}_ACCOUNT_EMAIL | webmaster@localhost.com | The email to use for the admin account | +| DRUPAL_SITE_{SITE}_ACCOUNT_NAME | admin | The Drupal administrator user | +| DRUPAL_SITE_{SITE}_ACCOUNT_PASSWORD | password | The Drupal administrator user password | +| DRUPAL_SITE_{SITE}_DB_NAME | drupal_{SITE} | The name of the sites database | +| DRUPAL_SITE_{SITE}_DB_PASSWORD | password | The database users password | +| DRUPAL_SITE_{SITE}_DB_USER | drupal_{SITE} | The database user used by the site | +| DRUPAL_SITE_{SITE}_EMAIL | webmaster@localhost.com | The Drupal administrators email | +| DRUPAL_SITE_{SITE}_LOCALE | en | The Drupal sites locale | +| DRUPAL_SITE_{SITE}_NAME | | The Drupal sites name | +| DRUPAL_SITE_{SITE}_PROFILE | standard | The installation profile to use | +| DRUPAL_SITE_{SITE}_SUBDIR | {SITE} | The subdirectory to install the sub-site into | +| DRUPAL_SITE_{SITE}_CONFIGDIR | | Install using existing config files from directory | +| DRUPAL_SITE_{SITE}_INSTALL | true | Perform install if not already installed | +[base image]: ../base/README.md [Drupal]: https://www.drupal.org/ diff --git a/drupal/rootfs/etc/bash.bashrc b/drupal/rootfs/etc/bash.bashrc old mode 100644 new mode 100755 index cbe06a15..f588dd7c --- a/drupal/rootfs/etc/bash.bashrc +++ b/drupal/rootfs/etc/bash.bashrc @@ -1,4 +1,6 @@ -#!/bin/env bash +#!/command/with-contenv bash +# shellcheck shell=bash # For bash login-shells include utilities so they can be called directly. +# shellcheck disable=SC1091 source /etc/islandora/utilities.sh diff --git a/drupal/rootfs/etc/confd/conf.d/drupal.fpm.conf.toml b/drupal/rootfs/etc/confd/conf.d/drupal.fpm.conf.toml new file mode 100644 index 00000000..f83a1508 --- /dev/null +++ b/drupal/rootfs/etc/confd/conf.d/drupal.fpm.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "drupal.fpm.conf.tmpl" +dest = "/etc/nginx/shared/drupal.fpm.conf" +uid = 0 +gid = 0 +mode = "0644" +keys = [ "/" ] diff --git a/drupal/rootfs/etc/confd/conf.d/setup-environment.sh.toml b/drupal/rootfs/etc/confd/conf.d/setup-environment.sh.toml deleted file mode 100644 index d7fc515b..00000000 --- a/drupal/rootfs/etc/confd/conf.d/setup-environment.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setup-environment.sh.tmpl" -dest = "/var/run/islandora/setup-environment.sh" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/" ] diff --git a/drupal/rootfs/etc/confd/confd.toml b/drupal/rootfs/etc/confd/confd.toml deleted file mode 100644 index 925d1a48..00000000 --- a/drupal/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/drupal" diff --git a/drupal/rootfs/etc/confd/templates/drupal.fpm.conf.tmpl b/drupal/rootfs/etc/confd/templates/drupal.fpm.conf.tmpl new file mode 100644 index 00000000..60e4b3dc --- /dev/null +++ b/drupal/rootfs/etc/confd/templates/drupal.fpm.conf.tmpl @@ -0,0 +1,35 @@ +# In Drupal 8, we must also match new paths where the '.php' appears in +# the middle, such as update.php/selection. The rule we use is strict, +# and only allows this pattern with the update.php front controller. +# This allows legacy path aliases in the form of +# blog/index.php/legacy-path to continue to route to Drupal nodes. If +# you do not have any paths like that, then you might prefer to use a +# laxer rule, such as: +# location ~ \.php(/|$) { +# The laxer rule will continue to work if Drupal uses this new URL +# pattern with front controllers other than update.php in a future +# release. +location ~ '\.php$|^/update.php' { + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + # Ensure the php file exists. Mitigates CVE-2019-11043 + try_files $fastcgi_script_name =404; + # Security note: If you're running a version of PHP older than the + # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. + # See http://serverfault.com/q/627903/94922 for details. + include fastcgi_params; + # Block httpoxy attacks. See https://httpoxy.org/. + fastcgi_param HTTP_PROXY ""; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + {{ if eq (getenv "DRUPAL_ENABLE_HTTPS") "true" }} + fastcgi_param HTTPS on; + fastcgi_param HTTP_SCHEME https; + {{ end }} + fastcgi_intercept_errors on; + # Large Islandora repositories global searches end up with HUGE header sizes + fastcgi_buffers 16 800k; + fastcgi_buffer_size 1600k; + # PHP 8 socket location. + fastcgi_pass unix:/var/run/php-fpm81/php-fpm81.sock; +} diff --git a/drupal/rootfs/etc/confd/templates/setup-environment.sh.tmpl b/drupal/rootfs/etc/confd/templates/setup-environment.sh.tmpl deleted file mode 100644 index 486e6834..00000000 --- a/drupal/rootfs/etc/confd/templates/setup-environment.sh.tmpl +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -with-contenv -multisubstitute -{ - # Default settings to apply if none given. - define ACCOUNT_EMAIL "webmaster@localhost.com" - define ACCOUNT_NAME "admin" - define ACCOUNT_PASSWORD "password" - define CONFIGDIR "" - define DB_DRIVER "mysql" - define DB_HOST "mariadb" - define DB_NAME "drupal_default" - define DB_PASSWORD "password" - define DB_PORT "3306" - define DB_ROOT_PASSWORD "password" - define DB_ROOT_USER "root" - define DB_USER "drupal_default" - define EMAIL "webmaster@localhost.com" - define INSTALL "true" - define INSTALL_EXISTING_CONFIG "false" - define LOCALE "en" - define NAME "Default" - define PROFILE "standard" - define SALT "9PPaL0CxZAIcq0l9wxgDGlCZrp7JdT_x7v9gVzpdbUjMt1PqDz3uD0Zy-i16DuJ1-Htuq5hqeg" - define SUBDIR "default" - # Islandora Specific Variables. - define BROKER_HOST "activemq" - define BROKER_PORT "61613" - define CANTALOUPE_URL "http://islandora.isle-dc.localhost/cantaloupe/iiif/2" - define FCREPO_HOST "fcrepo.isle-dc.localhost" - define FCREPO_PORT "80" - define GEMINI_HOST "gemini" - define GEMINI_PORT "8000" - define MATOMO_URL "http://islandora.isle-dc.localhost/matomo/" - define SITE_URL "http://islandora.isle-dc.localhost" - define SOLR_CORE "ISLANDORA" - define SOLR_HOST "solr" - define SOLR_PORT "8983" - define TRIPLESTORE_HOST "blazegraph" - define TRIPLESTORE_NAMESPACE "islandora" - define TRIPLESTORE_PORT "80" -} -foreground { - # We add / update the environment defined for the container, - # this allows our other initialization and service scripts - # use these settings; but does not change the existing - # environment as seen by linked containers. - # Variables can only be seen when using '#!/usr/bin/with-contenv' - s6-env -i - DRUPAL_DEFAULT_ACCOUNT_EMAIL="{{ getv "/default/account/email" "${ACCOUNT_EMAIL}" }}" - DRUPAL_DEFAULT_ACCOUNT_NAME="{{ getv "/default/account/name" "${ACCOUNT_NAME}" }}" - DRUPAL_DEFAULT_ACCOUNT_PASSWORD="{{ getv "/default/account/password" "${ACCOUNT_PASSWORD}" }}" - DRUPAL_DEFAULT_CONFIGDIR="{{ getv "/default/configdir" "${CONFIGDIR}" }}" - DRUPAL_DEFAULT_DB_DRIVER="{{ getv "/default/db/driver" "${DB_DRIVER}" }}" - DRUPAL_DEFAULT_DB_HOST="{{ getv "/default/db/host" "${DB_HOST}" }}" - DRUPAL_DEFAULT_DB_NAME="{{ getv "/default/db/name" "${DB_NAME}" }}" - DRUPAL_DEFAULT_DB_PASSWORD="{{ getv "/default/db/password" "${DB_PASSWORD}" }}" - DRUPAL_DEFAULT_DB_PORT="{{ getv "/default/db/port" "${DB_PORT}" }}" - DRUPAL_DEFAULT_DB_ROOT_PASSWORD="{{ getv "/default/db/root/password" "${DB_ROOT_PASSWORD}" }}" - DRUPAL_DEFAULT_DB_ROOT_USER="{{ getv "/default/db/root/user" "${DB_ROOT_USER}" }}" - DRUPAL_DEFAULT_DB_USER="{{ getv "/default/db/user" "${DB_USER}" }}" - DRUPAL_DEFAULT_EMAIL="{{ getv "/default/email" "${EMAIL}" }}" - DRUPAL_DEFAULT_INSTALL="{{ getv "/default/install" "${INSTALL}" }}" - DRUPAL_DEFAULT_INSTALL_EXISTING_CONFIG="{{ getv "/default/install/existing/config" "${INSTALL_EXISTING_CONFIG}" }}" - DRUPAL_DEFAULT_LOCALE="{{ getv "/default/locale" "${LOCALE}" }}" - DRUPAL_DEFAULT_NAME="{{ getv "/default/name" "${NAME}" }}" - DRUPAL_DEFAULT_PROFILE="{{ getv "/default/profile" "${PROFILE}" }}" - DRUPAL_DEFAULT_SALT="{{ getv "/default/salt" "${SALT}" }}" - DRUPAL_DEFAULT_SUBDIR="{{ getv "/default/subdir" "${SUBDIR}" }}" - # Islandora Specific Variables. - DRUPAL_DEFAULT_BROKER_HOST="{{ getv "/default/broker/host" "${BROKER_HOST}" }}" - DRUPAL_DEFAULT_BROKER_PORT="{{ getv "/default/broker/port" "${BROKER_PORT}" }}" - DRUPAL_DEFAULT_CANTALOUPE_URL="{{ getv "/default/cantaloupe/url" "${CANTALOUPE_URL}" }}" - DRUPAL_DEFAULT_FCREPO_HOST="{{ getv "/default/fcrepo/host" "${FCREPO_HOST}" }}" - DRUPAL_DEFAULT_FCREPO_PORT="{{ getv "/default/fcrepo/port" "${FCREPO_PORT}" }}" - DRUPAL_DEFAULT_GEMINI_HOST="{{ getv "/default/gemini/host" "${GEMINI_HOST}" }}" - DRUPAL_DEFAULT_GEMINI_PORT="{{ getv "/default/gemini/port" "${GEMINI_PORT}" }}" - DRUPAL_DEFAULT_MATOMO_URL="{{ getv "/default/matomo/url" "${MATOMO_URL}" }}" - DRUPAL_DEFAULT_SITE_URL="{{ getv "/default/site/url" "${SITE_URL}" }}" - DRUPAL_DEFAULT_SOLR_CORE="{{ getv "/default/solr/core" "${SOLR_CORE}" }}" - DRUPAL_DEFAULT_SOLR_HOST="{{ getv "/default/solr/host" "${SOLR_HOST}" }}" - DRUPAL_DEFAULT_SOLR_PORT="{{ getv "/default/solr/port" "${SOLR_PORT}" }}" - DRUPAL_DEFAULT_TRIPLESTORE_HOST="{{ getv "/default/triplestore/host" "${TRIPLESTORE_HOST}" }}" - DRUPAL_DEFAULT_TRIPLESTORE_NAMESPACE="{{ getv "/default/triplestore/namespace" "${TRIPLESTORE_NAMESPACE}" }}" - DRUPAL_DEFAULT_TRIPLESTORE_PORT="{{ getv "/default/triplestore/port" "${TRIPLESTORE_PORT}" }}" - # Used by scripts to iterate over all/sub sites environment variables. - DRUPAL_SUBSITES="{{ toUpper (join (lsdir "/site") " ") }}" - DRUPAL_SITES="DEFAULT {{ toUpper (join (lsdir "/site") " ") }}" - s6-dumpenv -- /var/run/s6/container_environment -} -{{ range $site := lsdir "/site" }} -# Import default settings from the previous statement so the default value set -# by the user can propagate to subsites. -with-contenv -multisubstitute -{ - importas -i SUBSITE_ACCOUNT_EMAIL DRUPAL_DEFAULT_ACCOUNT_EMAIL - importas -i SUBSITE_ACCOUNT_NAME DRUPAL_DEFAULT_ACCOUNT_NAME - importas -i SUBSITE_ACCOUNT_PASSWORD DRUPAL_DEFAULT_ACCOUNT_PASSWORD - importas -i SUBSITE_DB_DRIVER DRUPAL_DEFAULT_DB_DRIVER - importas -i SUBSITE_DB_HOST DRUPAL_DEFAULT_DB_HOST - importas -i SUBSITE_DB_NAME DRUPAL_DEFAULT_DB_NAME - importas -i SUBSITE_DB_PASSWORD DRUPAL_DEFAULT_DB_PASSWORD - importas -i SUBSITE_DB_PORT DRUPAL_DEFAULT_DB_PORT - importas -i SUBSITE_DB_ROOT_PASSWORD DRUPAL_DEFAULT_DB_ROOT_PASSWORD - importas -i SUBSITE_DB_ROOT_USER DRUPAL_DEFAULT_DB_ROOT_USER - importas -i SUBSITE_DB_USER DRUPAL_DEFAULT_DB_USER - importas -i SUBSITE_EMAIL DRUPAL_DEFAULT_EMAIL - importas -i SUBSITE_INSTALL DRUPAL_DEFAULT_INSTALL - importas -i SUBSITE_INSTALL_EXISTING_CONFIG DRUPAL_DEFAULT_INSTALL_EXISTING_CONFIG - importas -i SUBSITE_LOCALE DRUPAL_DEFAULT_LOCALE - importas -i SUBSITE_NAME DRUPAL_DEFAULT_NAME - importas -i SUBSITE_PROFILE DRUPAL_DEFAULT_PROFILE - importas -i SUBSITE_SUBDIR DRUPAL_DEFAULT_SUBDIR - # Islandora Specific Variables. - importas -i SUBSITE_BROKER_HOST DRUPAL_DEFAULT_BROKER_HOST - importas -i SUBSITE_BROKER_PORT DRUPAL_DEFAULT_BROKER_PORT - importas -i SUBSITE_CANTALOUPE_URL DRUPAL_DEFAULT_CANTALOUPE_URL - importas -i SUBSITE_FCREPO_HOST DRUPAL_DEFAULT_FCREPO_HOST - importas -i SUBSITE_FCREPO_PORT DRUPAL_DEFAULT_FCREPO_PORT - importas -i SUBSITE_GEMINI_HOST DRUPAL_DEFAULT_GEMINI_HOST - importas -i SUBSITE_GEMINI_PORT DRUPAL_DEFAULT_GEMINI_PORT - importas -i SUBSITE_MATOMO_URL DRUPAL_DEFAULT_MATOMO_URL - importas -i SUBSITE_SITE_URL DRUPAL_DEFAULT_SITE_URL - importas -i SUBSITE_SOLR_HOST DRUPAL_DEFAULT_SOLR_HOST - importas -i SUBSITE_SOLR_PORT DRUPAL_DEFAULT_SOLR_PORT - importas -i SUBSITE_TRIPLESTORE_HOST DRUPAL_DEFAULT_TRIPLESTORE_HOST - importas -i SUBSITE_TRIPLESTORE_PORT DRUPAL_DEFAULT_TRIPLESTORE_PORT -} -foreground { - # In general subsites will use the same values specified for the default site - # except where it does not make sense like install directory or database name. - s6-env -i - DRUPAL_SITE_{{ toUpper $site }}_ACCOUNT_EMAIL="{{ getv (printf "/site/%s/account/email" $site) "${SUBSITE_ACCOUNT_EMAIL}" }}" - DRUPAL_SITE_{{ toUpper $site }}_ACCOUNT_NAME="{{ getv (printf "/site/%s/account/name" $site) "${SUBSITE_ACCOUNT_NAME}" }}" - DRUPAL_SITE_{{ toUpper $site }}_ACCOUNT_PASSWORD="{{ getv (printf "/site/%s/account/password" $site) }}" - DRUPAL_SITE_{{ toUpper $site }}_CONFIGDIR="{{ getv (printf "/site/%s/configdir" $site) "" }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_DRIVER="{{ getv (printf "/site/%s/db/driver" $site) "${SUBSITE_DB_DRIVER}" }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_HOST="{{ getv (printf "/site/%s/db/host" $site) "${SUBSITE_DB_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_NAME="{{ getv (printf "/site/%s/db/name" $site) (printf "drupal_%s" $site) }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_PASSWORD="{{ getv (printf "/site/%s/db/password" $site) }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_PORT="{{ getv (printf "/site/%s/db/port" $site) "${SUBSITE_DB_PORT}" }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_ROOT_PASSWORD="{{ getv (printf "/site/%s/db/root/password" $site) "${SUBSITE_DB_ROOT_PASSWORD}" }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_ROOT_USER="{{ getv (printf "/site/%s/db/root/password" $site) "${SUBSITE_DB_ROOT_USER}" }}" - DRUPAL_SITE_{{ toUpper $site }}_DB_USER="{{ getv (printf "/site/%s/db/user" $site) (printf "drupal_%s" $site) }}" - DRUPAL_SITE_{{ toUpper $site }}_EMAIL="{{ getv (printf "/site/%s/email" $site) "${SUBSITE_EMAIL}" }}" - DRUPAL_SITE_{{ toUpper $site }}_INSTALL="{{ getv (printf "/site/%s/install" $site) "${SUBSITE_INSTALL}" }}" - DRUPAL_SITE_{{ toUpper $site }}_INSTALL_EXISTING_CONFIG="{{ getv (printf "/site/%s/install/existing/config" $site) "${SUBSITE_INSTALL_EXISTING_CONFIG}" }}" - DRUPAL_SITE_{{ toUpper $site }}_LOCALE="{{ getv (printf "/site/%s/locale" $site) "${SUBSITE_LOCALE}" }}" - DRUPAL_SITE_{{ toUpper $site }}_NAME="{{ getv (printf "/site/%s/name" $site) $site }}" - DRUPAL_SITE_{{ toUpper $site }}_PROFILE="{{ getv (printf "/site/%s/profile" $site) "${SUBSITE_PROFILE}" }}" - DRUPAL_SITE_{{ toUpper $site }}_SALT="{{ getv (printf "/site/%s/salt" $site) }}" - DRUPAL_SITE_{{ toUpper $site }}_SUBDIR="{{ getv (printf "/site/%s/subdir" $site) $site }}" - # Islandora Specific Variables. - DRUPAL_SITE_{{ toUpper $site }}_BROKER_HOST="{{ getv (printf "/site/%s/broker/host" $site) "${SUBSITE_BROKER_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_BROKER_PORT="{{ getv (printf "/site/%s/broker/port" $site) "${SUBSITE_BROKER_PORT}" }}" - DRUPAL_SITE_{{ toUpper $site }}_CANTALOUPE_URL="{{ getv (printf "/site/%s/cantaloupe/url" $site) "${SUBSITE_CANTALOUPE_URL}" }}" - DRUPAL_SITE_{{ toUpper $site }}_FCREPO_HOST="{{ getv (printf "/site/%s/fcrepo/host" $site) "${SUBSITE_FCREPO_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_FCREPO_HOST="{{ getv (printf "/site/%s/fcrepo/host" $site) "${SUBSITE_FCREPO_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_GEMINI_HOST="{{ getv (printf "/site/%s/gemini/host" $site) "${SUBSITE_GEMINI_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_GEMINI_PORT="{{ getv (printf "/site/%s/gemini/port" $site) "${SUBSITE_GEMINI_PORT}" }}" - DRUPAL_SITE_{{ toUpper $site }}_MATOMO_URL="{{ getv (printf "/site/%s/matomo/url" $site) "${SUBSITE_MATOMO_URL}" }}" - DRUPAL_SITE_{{ toUpper $site }}_SITE_URL="{{ getv (printf "/site/%s/site/url" $site) "${SUBSITE_SITE_URL}" }}" - DRUPAL_SITE_{{ toUpper $site }}_SOLR_CORE="{{ getv (printf "/site/%s/solr/core" $site) $site }}" - DRUPAL_SITE_{{ toUpper $site }}_SOLR_HOST="{{ getv (printf "/site/%s/solr/host" $site) "${SUBSITE_SOLR_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_SOLR_PORT="{{ getv (printf "/site/%s/solr/port" $site) "${SUBSITE_SOLR_PORT}" }}" - DRUPAL_SITE_{{ toUpper $site }}_TRIPLESTORE_HOST="{{ getv (printf "/site/%s/triplestore/host" $site) "${SUBSITE_TRIPLESTORE_HOST}" }}" - DRUPAL_SITE_{{ toUpper $site }}_TRIPLESTORE_NAMESPACE="{{ getv (printf "/site/%s/triplestore/namespace" $site) $site }}" - DRUPAL_SITE_{{ toUpper $site }}_TRIPLESTORE_PORT="{{ getv (printf "/site/%s/triplestore/port" $site) "${SUBSITE_TRIPLESTORE_PORT}" }}" - s6-dumpenv -- /var/run/s6/container_environment -} -{{ end }} diff --git a/drupal/rootfs/etc/islandora/utilities.sh b/drupal/rootfs/etc/islandora/utilities.sh index bb25495e..658b38eb 100755 --- a/drupal/rootfs/etc/islandora/utilities.sh +++ b/drupal/rootfs/etc/islandora/utilities.sh @@ -1,28 +1,34 @@ -#!/usr/bin/with-contenv bash +#!/command/with-contenv bash +# shellcheck shell=bash # Capitalize the given string. function capitalize { - local string="${1}"; shift - echo $(tr '[:lower:]' '[:upper:]' <<< ${string:0:1})$(tr '[:upper:]' '[:lower:]' <<< ${string:1}) + local string="${1}" + shift + awk '{print toupper(substr($0,1,1)) tolower(substr($0,2))}' <<<"${string}" } # Transform the given string to uppercase. function uppercase { - local string="${1}"; shift - echo $(tr '[:lower:]' '[:upper:]' <<< ${string}) + local string="${1}" + shift + tr '[:lower:]' '[:upper:]' <<<"${string}" } # Joins the given array into a string delimited by the first argument. function join_by { - local IFS="${1}"; shift + local IFS="${1}" + shift echo "$*" } # Get variable value for given site. function drupal_site_env { - local site="$(uppercase ${1})"; shift - local suffix="$(uppercase ${1})"; shift - local var= + local site suffix var + site="$(uppercase "${1}")" + shift + suffix="$(uppercase "${1}")" + shift if [ "${site}" = "DEFAULT" ]; then var="DRUPAL_DEFAULT_${suffix}" echo "${!var}" @@ -35,11 +41,13 @@ function drupal_site_env { # Get the index of the given site in the lists of site. # Useful for generating distinct identifiers. function site_index { - local site="${1}"; shift - local array=(${DRUPAL_SITES}) - for i in "${!array[@]}"; do - if [[ "${array[$i]}" = "${site}" ]]; then - echo "${i}"; + local site sites + site="${1}" + shift + sites=("${DRUPAL_SITES[@]}") + for i in "${!sites[@]}"; do + if [[ "${sites[$i]}" = "${site}" ]]; then + echo "${i}" return 0 fi done @@ -49,14 +57,17 @@ function site_index { # Wait for service to respond. function wait_for_service { - local site="${1}"; shift - local service="${1}"; shift - local time="${1-300}"; - local host=$(drupal_site_env "${site}" "${service}_HOST") - local port=$(drupal_site_env "${site}" "${service}_PORT") - local service_name=$(capitalize "${service}") - - if timeout ${time} wait-for-open-port.sh "${host}" "${port}" ; then + local site service duration host port service_name + site="${1}" + shift + service="${1}" + shift + duration="${1-300}" + host=$(drupal_site_env "${site}" "${service}_HOST") + port=$(drupal_site_env "${site}" "${service}_PORT") + service_name=$(capitalize "${service}") + + if timeout "${duration}" wait-for-open-port.sh "${host}" "${port}"; then echo "${service_name} Found at ${host}:${port}" return 0 else @@ -67,48 +78,54 @@ function wait_for_service { # Waits for services that are required to be running to successfully ingest content. function wait_for_required_services { - local site="${1}"; shift + local site + site="${1}" + shift if [ $# -gt 0 ]; then while [ $# -gt 0 ]; do - local service="${1}"; shift + local service="${1}" + shift wait_for_service "${site}" "${service}" done else wait_for_service "${site}" "SOLR" wait_for_service "${site}" "FCREPO" wait_for_service "${site}" "BROKER" - wait_for_service "${site}" "GEMINI" wait_for_service "${site}" "TRIPLESTORE" fi } # Apply given function for all sites in parallel, up to the number of cores available. function for_all_sites { - local function="${1}"; shift - local n=$(nproc) - local pids=() + local func cpus pids + func="${1}" + shift + cpus=$(nproc) + pids=() for site in ${DRUPAL_SITES}; do - $function "${site}" ${@} & + "${func}" "${site}" "${@}" & pids+=(${!}) - # Allow only to execute ${n} jobs in parallel - if [[ $(jobs -r -p | wc -l) -gt ${n} ]]; then + # Allow only to execute ${cpu} jobs in parallel + if [[ $(jobs -r -p | wc -l) -gt ${cpus} ]]; then # Wait only for first job, exit code here will propigate wait -n fi done # To ensure the exit code propigates we must wait for each process individually - for pid in ${pids[@]}; do + for pid in "${pids[@]}"; do wait "${pid}" done } function execute_sql_file { - local site="${1}"; shift - local driver=$(drupal_site_env "${site}" "DB_DRIVER") - local host=$(drupal_site_env "${site}" "DB_HOST") - local port=$(drupal_site_env "${site}" "DB_PORT") - local user=$(drupal_site_env "${site}" "DB_ROOT_USER") - local password=$(drupal_site_env "${site}" "DB_ROOT_PASSWORD") + local site driver host port user password + site="${1}" + shift + driver=$(drupal_site_env "${site}" "DB_DRIVER") + host=$(drupal_site_env "${site}" "DB_HOST") + port=$(drupal_site_env "${site}" "DB_PORT") + user=$(drupal_site_env "${site}" "DB_ROOT_USER") + password=$(drupal_site_env "${site}" "DB_ROOT_PASSWORD") execute-sql-file.sh \ --driver "${driver}" \ --host "${host}" \ @@ -119,15 +136,17 @@ function execute_sql_file { } function mysql_query { - local site="${1}"; shift - local db_name=$(drupal_site_env "${site}" "DB_NAME") - local db_user=$(drupal_site_env "${site}" "DB_USER") - local db_password=$(drupal_site_env "${site}" "DB_PASSWORD") - cat <<- EOF + local site db_name db_user db_password + site="${1}" + shift + db_name=$(drupal_site_env "${site}" "DB_NAME") + db_user=$(drupal_site_env "${site}" "DB_USER") + db_password=$(drupal_site_env "${site}" "DB_PASSWORD") + cat <<-EOF -- Create if does not exist. CREATE DATABASE IF NOT EXISTS ${db_name} CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER IF NOT EXISTS ${db_user}@'%' IDENTIFIED BY "${db_password}"; -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES ON ${db_name}.* to ${db_user}@'%' IDENTIFIED BY "${db_password}"; +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON ${db_name}.* to ${db_user}@'%' IDENTIFIED BY "${db_password}"; FLUSH PRIVILEGES; -- Update DB_USER password if changed. @@ -136,16 +155,20 @@ EOF } function mysql_create_database { - local site="${1}"; shift + local site + site="${1}" + shift execute_sql_file "${site}" <(mysql_query "${site}") } function postgres_query { - local site="${1}"; shift - local db_name=$(drupal_site_env "${site}" "DB_NAME") - local db_user=$(drupal_site_env "${site}" "DB_USER") - local db_password=$(drupal_site_env "${site}" "DB_PASSWORD") - cat <<- EOF + local site db_name db_user db_password + site="${1}" + shift + db_name=$(drupal_site_env "${site}" "DB_NAME") + db_user=$(drupal_site_env "${site}" "DB_USER") + db_password=$(drupal_site_env "${site}" "DB_PASSWORD") + cat <<-EOF BEGIN; DO \$\$ @@ -167,14 +190,18 @@ EOF } function postgresql_database_exists { - local site="${1}"; shift - local db_name=$(drupal_site_env "${site}" "DB_NAME") + local site db_name + site="${1}" + shift + db_name=$(drupal_site_env "${site}" "DB_NAME") execute_sql_file "${site}" --database "${db_name}" <(echo 'select 1') } function postgresql_create_database { - local site="${1}"; shift - local db_name=$(drupal_site_env "${site}" "DB_NAME") + local site db_name + site="${1}" + shift + db_name=$(drupal_site_env "${site}" "DB_NAME") # Postgres does not support CREATE DATABASE IF NOT EXISTS so split our logic across multiple queries. if ! postgresql_database_exists "${site}"; then execute_sql_file "${site}" <(echo "CREATE DATABASE ${db_name}") @@ -184,48 +211,57 @@ function postgresql_create_database { # Create a database for the given site. function create_database { - local site="${1}"; shift - local driver=$(drupal_site_env "${site}" "DB_DRIVER") - + local site driver + site="${1}" + shift + driver=$(drupal_site_env "${site}" "DB_DRIVER") + case "${driver}" in - mysql|pdo_mysql) - mysql_create_database "${site}" - ;; - pgsql|postgresql|pdo_pgsql) - postgresql_create_database "${site}" - ;; - *) - echo "Only MySQL/PostgresSQL databases are supported for now." >&2 - exit 1 + mysql) + mysql_create_database "${site}" + ;; + postgresql) + postgresql_create_database "${site}" + ;; + *) + echo "Only MySQL/PostgresSQL databases are supported for now." >&2 + exit 1 + ;; esac } # Install the given site. function install_site { - local site="${1}"; shift - local drupal_root=$(drush drupal:directory) - local driver=$(drupal_site_env "${site}" "DB_DRIVER") - local host=$(drupal_site_env "${site}" "DB_HOST") - local port=$(drupal_site_env "${site}" "DB_PORT") - local user=$(drupal_site_env "${site}" "DB_USER") - local password=$(drupal_site_env "${site}" "DB_PASSWORD") - local db_name=$(drupal_site_env "${site}" "DB_NAME") - local account_email=$(drupal_site_env "${site}" "ACCOUNT_EMAIL") - local account_name=$(drupal_site_env "${site}" "ACCOUNT_NAME") - local account_password=$(drupal_site_env "${site}" "ACCOUNT_PASSWORD") - local profile=$(drupal_site_env "${site}" "PROFILE") - local site_email=$(drupal_site_env "${site}" "EMAIL") - local site_locale=$(drupal_site_env "${site}" "LOCALE") - local site_name=$(drupal_site_env "${site}" "NAME") - local subdir=$(drupal_site_env "${site}" "SUBDIR") - local site_directory=$(realpath "${drupal_root}/sites/${subdir}") - local files_directory=$(realpath "${site_directory}/files") - local install=$(drupal_site_env "${site}" "INSTALL") - local use_existing_config=$(drupal_site_env "${site}" "INSTALL_EXISTING_CONFIG") - local use_existing_config_arg= + local \ + site drupal_root driver host port user password db_name account_email \ + account_name account_password profile site_email site_locale site_name \ + subdir site_directory files_directory install use_existing_config \ + use_existing_config_arg + site="${1}" + shift + drupal_root=$(drush drupal:directory) + driver=$(drupal_site_env "${site}" "DB_DRIVER") + host=$(drupal_site_env "${site}" "DB_HOST") + port=$(drupal_site_env "${site}" "DB_PORT") + user=$(drupal_site_env "${site}" "DB_USER") + password=$(drupal_site_env "${site}" "DB_PASSWORD") + db_name=$(drupal_site_env "${site}" "DB_NAME") + account_email=$(drupal_site_env "${site}" "ACCOUNT_EMAIL") + account_name=$(drupal_site_env "${site}" "ACCOUNT_NAME") + account_password=$(drupal_site_env "${site}" "ACCOUNT_PASSWORD") + profile=$(drupal_site_env "${site}" "PROFILE") + site_email=$(drupal_site_env "${site}" "EMAIL") + site_locale=$(drupal_site_env "${site}" "LOCALE") + site_name=$(drupal_site_env "${site}" "NAME") + subdir=$(drupal_site_env "${site}" "SUBDIR") + site_directory=$(realpath "${drupal_root}/sites/${subdir}") + files_directory=$(realpath "${site_directory}/files") + install=$(drupal_site_env "${site}" "INSTALL") + use_existing_config=$(drupal_site_env "${site}" "INSTALL_EXISTING_CONFIG") + use_existing_config_arg= if [ "${install}" != "true" ]; then - echo "Skipping install of site: $(capitalize ${site})" + echo "Skipping install of site: $(capitalize "${site}")" return 0 fi @@ -239,14 +275,29 @@ function install_site { fi # Ensure the files directory is writable by nginx, as when it is a new volume it is owned by root. - chown -R 100:101 "${files_directory}" - chmod -R ug+rw "${files_directory}" + chown -R 100:101 "${files_directory}" + chmod -R ug+rw "${files_directory}" # Allow changes to settings.php if it exists. - if [[ -f "${site_directory}/settings.php" ]]; then - chmod a=rwx "${site_directory}/settings.php" + if [[ -f "${site_directory:?}/settings.php" ]]; then + chmod a=rwx "${site_directory:?}/settings.php" fi + echo "--driver ${driver}" + echo "--host ${host}" + echo "--port ${port}" + echo "--dbuser ${user}" + echo "--dbname ${db_name}" + echo "PROFILE: ${profile}" + echo "--account-mail=${account_email}" + echo "--account-name=${account_name}" + echo "--site-mail=${site_email}" + echo "--locale=${site_locale}" + echo "--site-name=${site_name}" + echo "--sites-subdir=${subdir}" + echo "USE_EXISTIG_CONFIG: ${use_existing_config_arg}" + echo "EVERYTHING ELSE: $*" + /usr/local/bin/install-drupal-site.sh \ --driver "${driver}" \ --host "${host}" \ @@ -263,19 +314,21 @@ function install_site { --site-name="${site_name}" \ --sites-subdir="${subdir}" \ "${use_existing_config_arg}" \ - ${@} + "${@}" # Restrict changes to settings.php - if [[ -f "${site_directory}/settings.php" ]]; then - chmod a=,ug=r "${site_directory}/settings.php" + if [[ -f "${site_directory:?}/settings.php" ]]; then + chmod a=,ug=r "${site_directory:?}/settings.php" fi } # Get the base url of fedora. function fedora_url { - local site="${1}"; shift - local fcrepo_host=$(drupal_site_env "${site}" "FCREPO_HOST") - local fcrepo_port=$(drupal_site_env "${site}" "FCREPO_PORT") + local site fcrepo_host fcrepo_port + site="${1}" + shift + fcrepo_host=$(drupal_site_env "${site}" "FCREPO_HOST") + fcrepo_port=$(drupal_site_env "${site}" "FCREPO_PORT") # Indexing fails if port 80 is given explicitly. if [[ "${fcrepo_port}" == "80" ]]; then @@ -285,26 +338,72 @@ function fedora_url { fi } +# Allow modifications to settings.php by changing ownership and perms +function allow_settings_modifications { + local site drupal_root subdir site_directory + site="${1}" + shift + drupal_root=$(drush drupal:directory) + subdir=$(drupal_site_env "${site}" "SUBDIR") + site_directory=$(realpath "${drupal_root}/sites/${subdir}") + + # send debug output to stderr because the caller typically captures output from this function. + #>&2 echo "adjusting ownership of "${site_directory:?}/settings.php"" + if [ -f "${site_directory:?}/settings.php" ]; then + previous_owner_group=$(stat -c "%u:%g" "${site_directory:?}/settings.php") + chown 100:101 "${site_directory:?}/settings.php" + chmod a=rwx "${site_directory:?}/settings.php" + fi + if [ -n "${previous_owner_group}" ]; then + echo "${previous_owner_group}" + fi +} + +# Restore ownership of settings.php so that it is readable/writable outside of docker +function restore_settings_ownership { + local site previous_owner_group drupal_root subdir site_directory + site="${1}" + shift + previous_owner_group="${1}" + shift + drupal_root=$(drush drupal:directory) + subdir=$(drupal_site_env "${site}" "SUBDIR") + site_directory=$(realpath "${drupal_root}/sites/${subdir}") + + # Restore owner/group to previous value. + # When the codebase is bind-mounted, this ensures the file remains readable/writable by the host user. + if [ -n "${previous_owner_group}" ]; then + chown "${previous_owner_group}" "${site_directory:?}/settings.php" + fi + + # Restrict access to settings.php + chmod 444 "${site_directory:?}/settings.php" +} + # Regenerate / Update settings.php function update_settings_php { - local site="${1}"; shift - local drupal_root=$(drush drupal:directory) - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local driver=$(drupal_site_env "${site}" "DB_DRIVER") - local host=$(drupal_site_env "${site}" "DB_HOST") - local port=$(drupal_site_env "${site}" "DB_PORT") - local user=$(drupal_site_env "${site}" "DB_USER") - local password=$(drupal_site_env "${site}" "DB_PASSWORD") - local db_name=$(drupal_site_env "${site}" "DB_NAME") - local config_dir=$(drupal_site_env "${site}" "CONFIGDIR") - local fcrepo_host=$(drupal_site_env "${site}" "FCREPO_HOST") - local fcrepo_port=$(drupal_site_env "${site}" "FCREPO_PORT") - local salt=$(drupal_site_env "${site}" "SALT") - local subdir=$(drupal_site_env "${site}" "SUBDIR") - local site_directory=$(realpath "${drupal_root}/sites/${subdir}") - local install=$(drupal_site_env "${site}" "INSTALL") - local fedora_url=$(fedora_url "${site}") - local previous_owner_group= + local \ + site drupal_root site_url driver host port user password db_name \ + config_dir fcrepo_host fcrepo_port salt subdir site_directory install \ + fedora_url previous_owner_group + site="${1}" + shift + drupal_root=$(drush drupal:directory) + site_url=$(drupal_site_env "${site}" "SITE_URL") + driver=$(drupal_site_env "${site}" "DB_DRIVER") + host=$(drupal_site_env "${site}" "DB_HOST") + port=$(drupal_site_env "${site}" "DB_PORT") + user=$(drupal_site_env "${site}" "DB_USER") + password=$(drupal_site_env "${site}" "DB_PASSWORD") + db_name=$(drupal_site_env "${site}" "DB_NAME") + config_dir=$(drupal_site_env "${site}" "CONFIGDIR") + fcrepo_host=$(drupal_site_env "${site}" "FCREPO_HOST") + fcrepo_port=$(drupal_site_env "${site}" "FCREPO_PORT") + salt=$(drupal_site_env "${site}" "SALT") + subdir=$(drupal_site_env "${site}" "SUBDIR") + site_directory=$(realpath "${drupal_root}/sites/${subdir}") + install=$(drupal_site_env "${site}" "INSTALL") + fedora_url=$(fedora_url "${site}") if [ "${install}" != "true" ]; then echo "Skipping update of settings.php for site: $(capitalize "${site}")" @@ -312,15 +411,24 @@ function update_settings_php { fi # Allow modifications to settings.php - if [ -f "${site_directory}/settings.php" ]; then - previous_owner_group=$(stat -c "%u:%g" "${site_directory}/settings.php") - chown 100:101 "${site_directory}/settings.php" - chmod a=rwx "${site_directory}/settings.php" + previous_owner_group=$(allow_settings_modifications "${site}") + + # shellcheck disable=SC2016 + if ! grep -q 'global $content_directories;' "${site_directory:?}/settings.php"; then + echo 'global $content_directories;' >>"${site_directory:?}/settings.php" + echo '$content_directories["sync"] = "/var/www/drupal/content/sync";' >>"${site_directory:?}/settings.php" + fi + + # shellcheck disable=SC2016 + if ! grep -q 'global $content_directories;' "${site_directory:?}/settings.php"; then + echo 'global $content_directories;' >>"${site_directory:?}/settings.php" + echo '$content_directories["sync"] = "/var/www/drupal/content/sync";' >>"${site_directory:?}/settings.php" fi drush -l "${site_url}" islandora:settings:create-settings-if-missing drush -l "${site_url}" islandora:settings:set-hash-salt "${salt}" drush -l "${site_url}" islandora:settings:set-flystem-fedora-url "${fedora_url}" + drush -l "${site_url}" islandora:settings:set-reverse-proxy "${DRUPAL_REVERSE_PROXY_IPS}" drush -l "${site_url}" islandora:settings:set-database-settings \ "${db_name}" \ "${user}" \ @@ -329,68 +437,71 @@ function update_settings_php { "${port}" \ "${driver}" - # Specifiying the config_dir is optional, some users will hardcode it in + # Specifiying the config_dir is optional, some users will hardcode it in # their settings.php so it does not need updating. - if [ ! -z "${config_dir}" ]; then - drush -l "${site_url}" islandora:settings:set-config-sync-directory ${config_dir} + if [ -n "${config_dir}" ]; then + drush -l "${site_url}" islandora:settings:set-config-sync-directory "${config_dir}" fi # Restore owner/group to previous value - if [ ! -z "${previous_owner_group}" ]; then - chown "${previous_owner_group}" "${site_directory}/settings.php" - fi - - # Restrict access to settings.php - chmod 444 "${site_directory}/settings.php" + restore_settings_ownership "${site}" "${previous_owner_group}" } # Enable module and apply configuration. function configure_jwt_module { - local site="${1}" - local site_url=$(drupal_site_env "${site}" "SITE_URL") + local site site_url + site="${1}" + site_url=$(drupal_site_env "${site}" "SITE_URL") drush -l "${site_url}" -y pm:enable jwt drush -l "${site_url}" -y config:import --partial --source=/etc/islandora/configs/jwt } # Install and configure the islandora module. function configure_islandora_module { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local broker_host=$(drupal_site_env "${site}" "BROKER_HOST") - local broker_port=$(drupal_site_env "${site}" "BROKER_PORT") - local broker_url="tcp://${broker_host}:${broker_port}" - local gemini_host=$(drupal_site_env "${site}" "GEMINI_HOST") - local gemini_port=$(drupal_site_env "${site}" "GEMINI_PORT") - local gemini_url="http://${gemini_host}:${gemini_port}" - - drush -l "${site_url}" -y pm:enable islandora + local site site_url broker_host broker_port broker_url + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + broker_host=$(drupal_site_env "${site}" "BROKER_HOST") + broker_port=$(drupal_site_env "${site}" "BROKER_PORT") + broker_url="tcp://${broker_host}:${broker_port}" + + drush -l "${site_url}" -y pm:enable islandora_core_feature drush -l "${site_url}" -y config:set --input-format=yaml jsonld.settings remove_jsonld_format true drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings broker_url "${broker_url}" - drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings gemini_url "${gemini_url}" - drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings gemini_pseudo_bundles.0 "islandora_object:node" - drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings gemini_pseudo_bundles.1 "image:media" - drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings gemini_pseudo_bundles.2 "file:media" - drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings gemini_pseudo_bundles.3 "audio:media" - drush -l "${site_url}" -y config:set --input-format=yaml islandora.settings gemini_pseudo_bundles.4 "video:media" + + if drush -l "${site_url}" role:list | grep -q fedoraadmin; then + echo "Fedora Admin role already exists. No need to create it." + else + drush -l "${site_url}" role:create fedoraadmin fedoraAdmin + fi + drush -l "${site_url}" -y user:role:add fedoraadmin admin } -# After enabling and importing features a number of configurations need to be updated. +# Configure Solr port and host. function configure_islandora_default_module { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local host=$(drupal_site_env "${site}" "SOLR_HOST") - local port=$(drupal_site_env "${site}" "SOLR_PORT") + local site site_url host port + if ! drush pm-list --format=string --type=module --status=enabled --no-core | grep -q search_api; then + echo "Search API is not installed. Skipping configuration" + return 0 + fi + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + host=$(drupal_site_env "${site}" "SOLR_HOST") + port=$(drupal_site_env "${site}" "SOLR_PORT") - drush -l "${site_url}" -y user:role:add fedoraadmin admin drush -l "${site_url}" -y config:set search_api.server.default_solr_server backend_config.connector_config.host "${host}" drush -l "${site_url}" -y config:set search_api.server.default_solr_server backend_config.connector_config.port "${port}" } # Install search_api_solr and configure. Also uninstall the default search module. function configure_search_api_solr_module { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local driver=$(drupal_site_env "${site}" "DB_DRIVER") + local site site_url driver + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + driver=$(drupal_site_env "${site}" "DB_DRIVER") drush -l "${site_url}" -y pm:enable search_api_solr @@ -402,9 +513,15 @@ function configure_search_api_solr_module { # Enables and sets carapace as the default theme. function set_carapace_default_theme { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - drush -l "${site_url}" -y theme:enable carapace + local site site_url + if ! drush pm-list --format=string --type=theme --status=enabled --no-core | grep -q carapace; then + echo "carapace is not available. Skipping configuration." + return 0 + fi + + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") drush -l "${site_url}" -y config:set system.theme default carapace } @@ -413,14 +530,19 @@ function set_carapace_default_theme { # Assumes the search_api_solr module has already been installed. # Assumes that the destination will be a shared volume. function generate_solr_config { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local core=$(drupal_site_env "${site}" "SOLR_CORE") - local dest="${1-/opt/solr/server/solr/${core}}"; + local site site_url core dest + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + core=$(drupal_site_env "${site}" "SOLR_CORE") + dest="${1-/opt/solr/server/solr/${core}}" mkdir -p "/tmp/${core}" || true chmod a+rwx "/tmp/${core}" - drush -l "${site_url}" -y search-api-solr:get-server-config default_solr_server "/tmp/${core}/solr_config.zip" 7.1 + if ! drush -l "${site_url}" -y search-api-solr:get-server-config default_solr_server "/tmp/${core}/solr_config.zip" 8; then + echo -e "\n\nERROR: Could not generate SOLR config.zip!\nIn Drupal, check Configuration -> Search API -> SOLR Server, and use the\n"+ Get config.zip" option which should give you information into the actual error.\n\n" + return 1 + fi mkdir -p "${dest}/conf" || true mkdir -p "${dest}/data" || true unzip -o "/tmp/${core}/solr_config.zip" -d "${dest}/conf" @@ -431,43 +553,67 @@ function generate_solr_config { # Creates a SOLR core for the site using the Solr REST API. function create_solr_core { - local site="${1}"; shift - local core=$(drupal_site_env "${site}" "SOLR_CORE") - local host=$(drupal_site_env "${site}" "SOLR_HOST") - local port=$(drupal_site_env "${site}" "SOLR_PORT") + local site core host port + site="${1}" + shift + core=$(drupal_site_env "${site}" "SOLR_CORE") + host=$(drupal_site_env "${site}" "SOLR_HOST") + port=$(drupal_site_env "${site}" "SOLR_PORT") # Require a running Solr to create a core. wait_for_service "${site}" "SOLR" - curl -s "http://${host}:${port}/solr/admin/cores?action=CREATE&name=${core}&instanceDir=${core}&config=solrconfig.xml&dataDir=data" &> /dev/null + curl -s "http://${host}:${port}/solr/admin/cores?action=CREATE&name=${core}&instanceDir=${core}&config=solrconfig.xml&dataDir=data" &>/dev/null } # Generate solr config and create a core for it. function create_solr_core_with_default_config { - local site="${1}"; shift - generate_solr_config "${site}" + local site + if ! drush pm-list --format=string --type=module --status=enabled --no-core | grep -q search_api_solr; then + echo "search_api_solr is not installed. Skipping core setup." + return 0 + fi + + site="${1}" + shift + generate_solr_config "${site}" || return 1 create_solr_core "${site}" } # Install matomo and configure. function configure_matomo_module { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local site_id=$(($(site_index "${site}")+1)) - local matomo_url=$(drupal_site_env "${site}" "MATOMO_URL") - local matomo_http_url="http${matomo_url#https}" + local site site_url site_id matomo_url matomo_http_url + + if ! drush pm-list --format=string --type=module --status=enabled --no-core | grep -q matomo; then + echo "matomo is not installed. Skipping configuration" + return 0 + fi + + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + site_id=$(($(site_index "${site}") + 1)) + matomo_url=$(drupal_site_env "${site}" "MATOMO_URL") + matomo_http_url="http${matomo_url#https}" - drush -l "${site_url}" -y pm:enable matomo drush -l "${site_url}" -y config-set matomo.settings site_id "${site_id}" drush -l "${site_url}" -y config-set matomo.settings url_http "${matomo_http_url}" drush -l "${site_url}" -y config-set matomo.settings url_https "${matomo_url}" } # Configure Openseadragon to point use cantaloupe. -function configure_openseadragon { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local cantaloupe_url=$(drupal_site_env "${site}" "CANTALOUPE_URL") +function configure_openseadragon { + local site site_url cantaloupe_url + + if ! drush pm-list --format=string --type=module --status=enabled --no-core | grep -q openseadragon; then + echo "openseadragon is not installed. Skipping configuration" + return 0 + fi + + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + cantaloupe_url=$(drupal_site_env "${site}" "CANTALOUPE_URL") drush -l "${site_url}" -y config-set --input-format=yaml media.settings standalone_url true drush -l "${site_url}" -y config-set --input-format=yaml openseadragon.settings iiif_server "${cantaloupe_url}" @@ -477,78 +623,95 @@ function configure_openseadragon { # Imports any migrations in the 'islandora' group. function import_islandora_migrations { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - drush -l "${site_url}" -y --userid=1 migrate:import --group=islandora + local site site_url + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + drush -l "${site_url}" -y --userid=1 migrate:import islandora_defaults_tags,islandora_tags } # Enable module and apply configuration. function enable_modules { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - drush -l "${site_url}" -y pm:enable ${@} + local site site_url + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + drush -l "${site_url}" -y pm:enable "${@}" } # Enable module and apply configuration. function import_features { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local features=$(join_by , ${@}); shift + local site site_url features + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + features=$(join_by , "${@}") + shift drush -l "${site_url}" fim --no-interaction --yes "${features}" } # Rebuild the cache for the given site. function cache_rebuild { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") + local site site_url + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") drush -l "${site_url}" -y cache:rebuild } # Changes the site ID to match the configuration folder to allow it to be imported. function set_site_uuid { - local site="${1}"; shift - local site_url=$(drupal_site_env "${site}" "SITE_URL") - local drupal_root=$(drush drupal:directory) - local config_dir=$(cd $drupal_root; realpath `drush php:eval "echo \Drupal\Core\Site\Settings::get('config_sync_directory');"`) # Handle the case if config_dir is a relative path. - local uuid=${1-$(cat ${config_dir}/system.site.yml | awk '/uuid/ { print $2 }')} - drush -l ${site_url} -y config:set --input-format=yaml system.site uuid ${uuid} + local site site_url drupal_root config_dir uuid + site="${1}" + shift + site_url=$(drupal_site_env "${site}" "SITE_URL") + drupal_root=$(drush drupal:directory) + # Handle the case if config_dir is a relative path. + config_dir=$(realpath "$(drush --root="${drupal_root}" php:eval "echo \Drupal\Core\Site\Settings::get('config_sync_directory');")") + uuid=$(awk '/uuid/ { print $2 }' "${config_dir:?}/system.site.yml") + drush -l "${site_url}" -y config:set --input-format=yaml system.site uuid "${uuid}" } # Replace references to standard profile in the config files with minimal. -# -# Often we build sites with the standard profile but it is not possible to install +# +# Often we build sites with the standard profile but it is not possible to install # from a configuration that was generated on a standard profile site. # # https://www.drupal.org/project/drupal/issues/2982052 function remove_standard_profile_references_from_config { + local config_files # Do not modify configuration in in the core module. - local config_files=$(find /var/www/drupal -name "core.extension.yml" ! -path '*/core/*') + config_files=$(find /var/www/drupal -name "core.extension.yml" ! -path '*/core/*') for config_file in ${config_files}; do # Remove standard profile references, and replace with minimal. - sed -i 's|\( *\)standard:\(.*\)|\1minimal:\2|' ${config_file} - sed -i 's|profile: *standard|profile: minimal|' ${config_file} + sed -i 's|\( *\)standard:\(.*\)|\1minimal:\2|' "${config_file}" + sed -i 's|profile: *standard|profile: minimal|' "${config_file}" done } # Import sites configuration. function import_config { - local site="${1}" - local site_url=$(drupal_site_env "${site}" "SITE_URL") - drush -l ${site_url} -y config:import + local site site_url + site="${1}" + site_url=$(drupal_site_env "${site}" "SITE_URL") + drush -l "${site_url}" -y config:import } # Export sites configuration. function export_config { - local site="${1}" - local site_url=$(drupal_site_env "${site}" "SITE_URL") - drush -l ${site_url} -y config:export + local site site_url + site="${1}" + site_url=$(drupal_site_env "${site}" "SITE_URL") + drush -l "${site_url}" -y config:export } # Generates blazegraph properties for the given site using its namespace. function default_blazegraph_properties { - local site="${1}"; shift - local namespace=$(drupal_site_env "${site}" "TRIPLESTORE_NAMESPACE") - cat <<- EOF + local site namespace + site="${1}" + shift + namespace=$(drupal_site_env "${site}" "TRIPLESTORE_NAMESPACE") + cat <<-EOF com.bigdata.rdf.store.AbstractTripleStore.textIndex=false com.bigdata.rdf.store.AbstractTripleStore.axiomsClass=com.bigdata.rdf.axioms.OwlAxioms com.bigdata.rdf.sail.isolatableIndices=false @@ -566,12 +729,15 @@ EOF # Create a namespace with the given properties file. function create_blazegraph_namespace { - local site="${1}"; shift - local properties_file="${1}"; shift - local host=$(drupal_site_env "${site}" "TRIPLESTORE_HOST") - local port=$(drupal_site_env "${site}" "TRIPLESTORE_PORT") - local namespace=$(drupal_site_env "${site}" "TRIPLESTORE_NAMESPACE") - local triplestore_url="http://${host}:${port}/bigdata" + local site properties_file host port namespace triplestore_url + site="${1}" + shift + properties_file="${1}" + shift + host=$(drupal_site_env "${site}" "TRIPLESTORE_HOST") + port=$(drupal_site_env "${site}" "TRIPLESTORE_PORT") + namespace=$(drupal_site_env "${site}" "TRIPLESTORE_NAMESPACE") + triplestore_url="http://${host}:${port}/bigdata" # Require a running blazegraph to update it. wait_for_service "${site}" "TRIPLESTORE" @@ -583,6 +749,7 @@ function create_blazegraph_namespace { # Create a namespace with default properties for the given site. function create_blazegraph_namespace_with_default_properties { - local site="${1}"; shift + local site="${1}" + shift create_blazegraph_namespace "${site}" <(default_blazegraph_properties "${site}") } diff --git a/drupal/rootfs/etc/nginx/conf.d/default.conf b/drupal/rootfs/etc/nginx/conf.d/default.conf deleted file mode 100644 index 281eb7fd..00000000 --- a/drupal/rootfs/etc/nginx/conf.d/default.conf +++ /dev/null @@ -1,121 +0,0 @@ -# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ -server { - server_name drupal; - root /var/www/drupal/web; - - location = /favicon.ico { - log_not_found off; - access_log off; - } - - location = /robots.txt { - allow all; - log_not_found off; - access_log off; - } - - # Very rarely should these ever be accessed outside of your lan - location ~* \.(txt|log)$ { - allow 192.168.0.0/16; - deny all; - } - - location ~ \..*/.*\.php$ { - return 403; - } - - location ~ ^/sites/.*/private/ { - return 403; - } - - # Block access to scripts in site files directory - location ~ ^/sites/[^/]+/files/.*\.php$ { - deny all; - } - - # Allow "Well-Known URIs" as per RFC 5785 - location ~* ^/.well-known/ { - allow all; - } - - # Block access to "hidden" files and directories whose names begin with a - # period. This includes directories used by version control systems such - # as Subversion or Git to store control files. - location ~ (^|/)\. { - return 403; - } - - location / { - # try_files $uri @rewrite; # For Drupal <= 6 - try_files $uri /index.php?$query_string; # For Drupal >= 7 - } - - location @rewrite { - rewrite ^/(.*)$ /index.php?q=$1; - } - - # Don't allow direct access to PHP files in the vendor directory. - location ~ /vendor/.*\.php$ { - deny all; - return 404; - } - - # Protect files and directories from prying eyes. - location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ { - deny all; - return 404; - } - - # In Drupal 8, we must also match new paths where the '.php' appears in - # the middle, such as update.php/selection. The rule we use is strict, - # and only allows this pattern with the update.php front controller. - # This allows legacy path aliases in the form of - # blog/index.php/legacy-path to continue to route to Drupal nodes. If - # you do not have any paths like that, then you might prefer to use a - # laxer rule, such as: - # location ~ \.php(/|$) { - # The laxer rule will continue to work if Drupal uses this new URL - # pattern with front controllers other than update.php in a future - # release. - location ~ '\.php$|^/update.php' { - fastcgi_split_path_info ^(.+?\.php)(|/.*)$; - # Ensure the php file exists. Mitigates CVE-2019-11043 - try_files $fastcgi_script_name =404; - # Security note: If you're running a version of PHP older than the - # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. - # See http://serverfault.com/q/627903/94922 for details. - include fastcgi_params; - # Block httpoxy attacks. See https://httpoxy.org/. - fastcgi_param HTTP_PROXY ""; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param QUERY_STRING $query_string; - fastcgi_intercept_errors on; - # PHP 7 socket location. - fastcgi_pass unix:/var/run/php-fpm7/php-fpm7.sock; - } - - # Fighting with Styles? This little gem is amazing. - # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 - location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7 - try_files $uri @rewrite; - } - - # Handle private files through Drupal. Private file's path can come - # with a language prefix. - location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7 - try_files $uri /index.php?$query_string; - } - - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { - try_files $uri @rewrite; - expires max; - log_not_found off; - } - # Enforce clean URLs - # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page - # Could be done with 301 for permanent or other redirect codes. - if ($request_uri ~* "^(.*/)index\.php(.*)") { - return 307 $1$2; - } -} diff --git a/drupal/rootfs/etc/nginx/http.d/default.conf b/drupal/rootfs/etc/nginx/http.d/default.conf new file mode 100644 index 00000000..fad70f8e --- /dev/null +++ b/drupal/rootfs/etc/nginx/http.d/default.conf @@ -0,0 +1,10 @@ +# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +server { + server_name drupal; + + include /etc/nginx/shared/drupal.defaults.conf; + include /etc/nginx/shared/drupal.fpm.conf; + # Required for Nginx service to validate that fpm is working. + # @see nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check + include /etc/nginx/shared/fpm.conf; +} diff --git a/drupal/rootfs/etc/nginx/shared/drupal.defaults.conf b/drupal/rootfs/etc/nginx/shared/drupal.defaults.conf new file mode 100644 index 00000000..07329aaf --- /dev/null +++ b/drupal/rootfs/etc/nginx/shared/drupal.defaults.conf @@ -0,0 +1,99 @@ +# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +root /var/www/drupal/web; + +location = /favicon.ico { + log_not_found off; + access_log off; +} + +location = /robots.txt { + allow all; + log_not_found off; + access_log off; +} + +# Allow access to .txt files in site files directory +location ~ ^/sites/[^/]+/files/.*\.txt$ { + allow all; +} + +# Very rarely should these ever be accessed outside of your lan +# Allow txt/log files served from flysystem. +location ~* ^/(?!_flysystem).*\.(txt|log)$ { + allow 192.168.0.0/16; + deny all; +} + +location ~ \..*/.*\.php$ { + return 403; +} + +location ~ ^/sites/.*/private/ { + return 403; +} + +# Block access to scripts in site files directory +location ~ ^/sites/[^/]+/files/.*\.php$ { + deny all; +} + +# Allow "Well-Known URIs" as per RFC 5785 +location ~* ^/.well-known/ { + allow all; +} + +# Block access to "hidden" files and directories whose names begin with a +# period. This includes directories used by version control systems such +# as Subversion or Git to store control files. +location ~ (^|/)\. { + return 403; +} + +location / { + # try_files $uri @rewrite; # For Drupal <= 6 + proxy_buffer_size 512k; + proxy_buffers 8 256k; + proxy_busy_buffers_size 512k; + try_files $uri /index.php?$query_string; # For Drupal >= 7 +} + +location @rewrite { + rewrite ^/(.*)$ /index.php?q=$1; +} + +# Don't allow direct access to PHP files in the vendor directory. +location ~ /vendor/.*\.php$ { + deny all; + return 404; +} + +# Protect files and directories from prying eyes. +location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^/(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^/#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ { + deny all; + return 404; +} + +# Fighting with Styles? This little gem is amazing. +# location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 +location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7 + try_files $uri @rewrite; +} + +# Handle private files through Drupal. Private file's path can come +# with a language prefix. +location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7 + try_files $uri /index.php?$query_string; +} + +location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + try_files $uri @rewrite; + expires max; + log_not_found off; +} + +# Enforce clean URLs +# Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page +# Could be done with 301 for permanent or other redirect codes. +if ($request_uri ~* "^(.*/)index\.php(.*)") { + return 307 $1$2; +} diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/development-environment b/drupal/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/development-environment new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/set-reverse-proxy b/drupal/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/set-reverse-proxy new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/set-subsite-defaults b/drupal/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/set-subsite-defaults new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/dependencies.d/container-environment b/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/type b/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/type @@ -0,0 +1 @@ +oneshot diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/up b/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/up new file mode 100755 index 00000000..3667cac5 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/s6-rc.d/development-environment/up @@ -0,0 +1,2 @@ +# Change uid of nginx user to match host. +/etc/s6-overlay/scripts/development-environment.sh diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/development-environment b/drupal/rootfs/etc/s6-overlay/s6-rc.d/ready/dependencies.d/development-environment new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/dependencies.d/base b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/dependencies.d/base new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/type b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/type @@ -0,0 +1 @@ +oneshot diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/up b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/up new file mode 100755 index 00000000..9a225d14 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-reverse-proxy/up @@ -0,0 +1,2 @@ +# Some directories must exist prior to rendering templates. +/etc/s6-overlay/scripts/set-reverse-proxy.sh diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/dependencies.d/database-defaults b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/dependencies.d/database-defaults new file mode 100644 index 00000000..e69de29b diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/type b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/type @@ -0,0 +1 @@ +oneshot diff --git a/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/up b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/up new file mode 100755 index 00000000..868efc4c --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/s6-rc.d/set-subsite-defaults/up @@ -0,0 +1,2 @@ +# Some directories must exist prior to rendering templates. +/etc/s6-overlay/scripts/set-subsite-defaults.sh diff --git a/drupal/rootfs/etc/s6-overlay/scripts/development-environment.sh b/drupal/rootfs/etc/s6-overlay/scripts/development-environment.sh new file mode 100755 index 00000000..9cc9efc4 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/scripts/development-environment.sh @@ -0,0 +1,15 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# UID should only be set in the development environments. +if [[ "${DEVELOPMENT_ENVIRONMENT}" == "true" ]]; then + if [[ -n "${UID}" ]]; then + if ! getent passwd ${UID}; then + usermod -u ${UID} nginx + fi + if [[ "$(stat -c %u /var/www/drupal)" != "${UID}" ]]; then + chown -R nginx:nginx /var/www + fi + fi +fi diff --git a/drupal/rootfs/etc/s6-overlay/scripts/set-reverse-proxy.sh b/drupal/rootfs/etc/s6-overlay/scripts/set-reverse-proxy.sh new file mode 100755 index 00000000..54ae0972 --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/scripts/set-reverse-proxy.sh @@ -0,0 +1,12 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# If not explicitly set by confd backend already attempt to set it from querying +# current networking environment. +if [[ -z "${DRUPAL_REVERSE_PROXY_IPS}" ]]; then + IPS=$(getent hosts traefik | awk '{ print $1 }') + # Use the IP address for the host 'traefik' if found otherwise default to + # '0.0.0.0'. + s6-env -i DRUPAL_REVERSE_PROXY_IPS="${IPS:-0.0.0.0}" s6-dumpenv -- /var/run/s6/container_environment +fi diff --git a/drupal/rootfs/etc/s6-overlay/scripts/set-subsite-defaults.sh b/drupal/rootfs/etc/s6-overlay/scripts/set-subsite-defaults.sh new file mode 100755 index 00000000..3070f13c --- /dev/null +++ b/drupal/rootfs/etc/s6-overlay/scripts/set-subsite-defaults.sh @@ -0,0 +1,56 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Update container environment with site specific environment +# variables: +# +# 1. Get the list of subsites from confd backend. +# 2. For each subsite set container variables if not already defined. +# +# At this point the 'default' site variables have already been updated to match +# the confd backend. As such for any subsite will use those values unless the +# subsite variable is explicitly overriden. + +# Import sites/subsites environment var so we can generate defaults for each site. +cat <&2 + usage + exit 1 + ;; esac done @@ -96,8 +101,8 @@ function cmdline { fi # All remaning parameters are passed to 'drush site-install'. - shift $((OPTIND-1)) - readonly DRUSH_ARGS="$@" + shift $((OPTIND - 1)) + readonly DRUSH_ARGS=("$@") return 0 } @@ -113,7 +118,7 @@ function execute_sql_file { } function mysql_count_query { - cat <<- EOF + cat <<-EOF SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_schema = '${DB_NAME}'; @@ -125,7 +130,7 @@ function mysql_count { } function postgresql_count_query { - cat <<- EOF + cat <<-EOF SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public'; @@ -133,37 +138,41 @@ EOF } function postgresql_count { - execute_sql_file --database ${DB_NAME} <(postgresql_count_query) -- -t 2>/dev/null + execute_sql_file --database "${DB_NAME}" <(postgresql_count_query) -- -t 2>/dev/null } # Check the number of tables to determine if it has already been installed. function installed { local count= case "${DRIVER}" in - mysql|pdo_mysql) - count=$(mysql_count) - ;; - pgsql|postgresql|pdo_pgsql) - count=$(postgresql_count) - ;; - *) - echo "Only MySQL/PostgresSQL databases are supported for now." >&2 - exit 1 + mysql) + count=$(mysql_count) + ;; + postgresql) + count=$(postgresql_count) + ;; + *) + echo "Only MySQL/PostgresSQL databases are supported for now." >&2 + exit 1 + ;; esac [[ $count -ne 0 ]] } function main { - cmdline ${ARGS} - + cmdline "${ARGS[@]}" + local protocol=mysql if installed; then echo "Site already is installed." return 0 fi + if [[ "${DRIVER}" == "postgresql" ]]; then + protocol=pgsql + fi echo "Installing site." drush \ -n \ - si ${DRUSH_ARGS} \ - --db-url="${DRIVER}://${DB_USER}:${DB_PASSWORD}@${HOST}:${PORT}/${DB_NAME}" + si "${DRUSH_ARGS[@]}" \ + --db-url="${protocol}://${DB_USER}:${DB_PASSWORD}@${HOST}:${PORT}/${DB_NAME}" } main diff --git a/drupal/rootfs/usr/share/drush/Commands/UpdateSettingsCommands.php b/drupal/rootfs/usr/share/drush/Commands/UpdateSettingsCommands.php index 1b4acbe5..403133c6 100644 --- a/drupal/rootfs/usr/share/drush/Commands/UpdateSettingsCommands.php +++ b/drupal/rootfs/usr/share/drush/Commands/UpdateSettingsCommands.php @@ -34,7 +34,13 @@ public function createSettingsIfMissing() $settings_file = $this->getSettingFilePath(); $fs = new Filesystem(); if (!$fs->exists($settings_file)) { + // After drush site-install has been run it is possible for the default + // directory to be non-writable by anyone. + $site_directory = dirname($settings_file); + $prev = fileperms($site_directory); + $fs->chmod($site_directory, 0775); $fs->copy(DRUPAL_ROOT . '/sites/default/default.settings.php', $settings_file); + $fs->chmod($site_directory, $prev); } } @@ -175,6 +181,34 @@ public function setTrustedHostPatterns($patterns) $this->writeSettings($settings); } + /** + * Set `reverse_proxy` in settings.php + * + * @command islandora:settings:set-reverse-proxy + * @bootstrap site + * @param $reverse_proxy_ips List of comma separated ip adresses for the reverse proxy. + * @usage drush islandora:settings:set-reverse-proxy + * Sets `reverse_proxy` in settings.php. + * Be aware that shell escaping can have an affect on the arguments. + */ + public function setReverseProxySettings($reverse_proxy_ips) { + $settings['settings']['reverse_proxy'] = (object) [ + 'value' => TRUE, + 'required' => TRUE, + ]; + $settings['settings']['reverse_proxy_addresses'] = (object) [ + 'value' => explode(',', $reverse_proxy_ips), + 'required' => TRUE, + ]; + $settings['settings']['reverse_proxy_trusted_headers'] = (object) [ + 'value' => \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_FOR | + \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_PROTO | + \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_PORT, + 'required' => TRUE, + ]; + $this->writeSettings($settings); + } + /** * Determine which settings file to update. */ diff --git a/drupal/tests/ServiceStartsWithBackendMySQL/build.gradle.kts b/drupal/tests/ServiceStartsWithBackendMySQL/build.gradle.kts new file mode 100644 index 00000000..f14f3046 --- /dev/null +++ b/drupal/tests/ServiceStartsWithBackendMySQL/build.gradle.kts @@ -0,0 +1,7 @@ +import java.time.Duration.ofMinutes +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // This test requires more time that normal. + timeout.convention(ofMinutes(10)) +} diff --git a/drupal/tests/ServiceStartsWithBackendMySQL/docker-compose.yml b/drupal/tests/ServiceStartsWithBackendMySQL/docker-compose.yml new file mode 100644 index 00000000..a80d83b3 --- /dev/null +++ b/drupal/tests/ServiceStartsWithBackendMySQL/docker-compose.yml @@ -0,0 +1,17 @@ +# file: docker-compose.yml +# +# Tests that we can bring up the demo site. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +name: drupal-servicestartswithbackendmysql +services: + drupal: + image: ${DRUPAL:-islandora/drupal:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + mariadb: + image: ${MARIADB:-islandora/mariadb:local} diff --git a/drupal/tests/ServiceStartsWithBackendMySQL/test.sh b/drupal/tests/ServiceStartsWithBackendMySQL/test.sh new file mode 100755 index 00000000..b81e0255 --- /dev/null +++ b/drupal/tests/ServiceStartsWithBackendMySQL/test.sh @@ -0,0 +1,37 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Install basic Drupal +cd /var/www/drupal || exit 1 +rm -fr /var/www/drupal/* +composer create-project drupal/recommended-project:^10.1.2 \ + --prefer-dist \ + --no-interaction \ + --stability stable \ + --no-dev \ + -- /var/www/drupal + +# Install Drush. +composer require drush/drush:^12.1.3 + +# Install actual site. +# shellcheck disable=SC1091 +source /etc/islandora/utilities.sh +mkdir -p /var/www/drupal/web/sites/default/files +chown -R nginx:nginx /var/www/drupal +create_database "DEFAULT" +install_site "DEFAULT" + +# Exit non-zero if database does not exist. +cat <<-EOF | execute-sql-file.sh + use ${DB_NAME} +EOF + +# Wait for Drupal to start. +wait_20x http://localhost:80/user + +# All tests were successful +exit 0 diff --git a/drupal/tests/ServiceStartsWithBackendPostgreSQL/build.gradle.kts b/drupal/tests/ServiceStartsWithBackendPostgreSQL/build.gradle.kts new file mode 100644 index 00000000..f14f3046 --- /dev/null +++ b/drupal/tests/ServiceStartsWithBackendPostgreSQL/build.gradle.kts @@ -0,0 +1,7 @@ +import java.time.Duration.ofMinutes +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // This test requires more time that normal. + timeout.convention(ofMinutes(10)) +} diff --git a/drupal/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml b/drupal/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml new file mode 100644 index 00000000..706e0efa --- /dev/null +++ b/drupal/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml @@ -0,0 +1,19 @@ +# file: docker-compose.yml +# +# Tests that we can bring up the demo site. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +name: drupal-servicestartswithbackendpostgresql +services: + drupal: + image: ${DRUPAL:-islandora/drupal:local} + environment: + DRUPAL_DEFAULT_DB_DRIVER: postgresql + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - bash # /test.sh # Run test and exit. + postgresql: + image: ${POSTGRESQL:-islandora/postgresql:local} diff --git a/drupal/tests/ServiceStartsWithBackendPostgreSQL/test.sh b/drupal/tests/ServiceStartsWithBackendPostgreSQL/test.sh new file mode 100755 index 00000000..5f64bb2a --- /dev/null +++ b/drupal/tests/ServiceStartsWithBackendPostgreSQL/test.sh @@ -0,0 +1,40 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Install basic Drupal +cd /var/www/drupal || exit 1 +rm -fr /var/www/drupal/* +composer create-project drupal/recommended-project:^10.1.2 \ + --prefer-dist \ + --no-interaction \ + --stability stable \ + --no-dev \ + -- /var/www/drupal + +# Install Drush. +composer require drush/drush:^12.1.3 + +# Install actual site. +# shellcheck disable=SC1091 +source /etc/islandora/utilities.sh +mkdir -p /var/www/drupal/web/sites/default/files +chown -R nginx:nginx /var/www/drupal +create_database "DEFAULT" +install_site "DEFAULT" + +# Exit non-zero if database does not exist. +PGPASSWORD="${DB_ROOT_PASSWORD}" psql \ + --host="${DB_HOST}" \ + --port="${DB_PORT}" \ + --username="${DB_ROOT_USER}" \ + --dbname="drupal_default" \ + -c "\q" + +# Wait for Drupal to start. +wait_20x http://localhost:80/user + +# All tests were successful +exit 0 diff --git a/fcrepo/.dockerignore b/fcrepo/.dockerignore deleted file mode 100644 index b43bf86b..00000000 --- a/fcrepo/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/fcrepo/Dockerfile b/fcrepo/Dockerfile deleted file mode 100644 index 4257ed25..00000000 --- a/fcrepo/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM local/tomcat:latest - -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - FCREPO_VERSION="5.1.0" && \ - FCREPO_FILE="fcrepo-webapp-${FCREPO_VERSION}.war" && \ - FCREPO_URL="https://github.com/fcrepo4/fcrepo4/releases/download/fcrepo-${FCREPO_VERSION}/${FCREPO_FILE}" && \ - FCREPO_SHA256="fdcb43cfd1468a84ddb89c20e4f4c7f54476ab9a24f69beb335d26f2b58ecec5" && \ - download.sh --url "${FCREPO_URL}" --sha256 "${FCREPO_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-war-into-tomcat.sh --name "fcrepo" --file "${DOWNLOAD_CACHE_DIRECTORY}/${FCREPO_FILE}" && \ - SYN_VERSION="1.1.0" && \ - SYN_FILE="islandora-syn-${SYN_VERSION}-all.jar" && \ - SYN_URL="https://github.com/Islandora-CLAW/Syn/releases/download/v${SYN_VERSION}/${SYN_FILE}" && \ - SYN_SHA256="bcad5f872930b1bcc9ea4a176c60e22683297121357336769a21ead9fadcbbd5" && \ - download.sh --url "${SYN_URL}" --sha256 "${SYN_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - cp "${DOWNLOAD_CACHE_DIRECTORY}/${SYN_FILE}" /opt/tomcat/lib && \ - mkdir -p /opt/keys/jwt && \ - chown tomcat:tomcat /opt/keys/jwt && \ - mkdir /data && \ - chown tomcat:tomcat /data && \ - chown -R tomcat:tomcat /opt/tomcat && \ - cleanup.sh - -COPY rootfs / diff --git a/fcrepo/README.md b/fcrepo/README.md deleted file mode 100644 index 8056b8a7..00000000 --- a/fcrepo/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# Fcrepo - -Docker image for [Fcrepo] version 5.1.0. - -Please refer to the [Fcrepo Documentation] for more in-depth information. - -As a quick example this will bring up an instance of [Fcrepo], and allow you -to view on . - -```bash -docker run --rm -ti -p 80:80 islandora/fcrepo -``` - -## Dependencies - -Requires `islandora/tomcat` docker image to build. Please refer to the -[Tomcat Image README](../tomcat/README.md) for additional information including -additional settings, volumes, ports, etc. - -## Volumes - -| Path | Description | -| :---- | :-------------------------------------------------------------------------------------------------- | -| /data | Fcrepo Object / Binary Store if FCREPO_BINARYSTORAGE_TYPE or FCREPO_PERSISTENCE_TYPE is set to file | - -## Settings - -| Environment Variable | Etcd Key | Default | Description | -| :----------------------------- | :------------------------------ | :-------------------------------- | :---------- | -| FCREPO_ACTIVEMQ_BROKER | /fcrepo/activemq/broker | tcp://activemq:61616 | | -| FCREPO_ACTIVEMQ_QUEUE | /fcrepo/activemq/queue | fedora | | -| FCREPO_ACTIVEMQ_TOPIC | /fcrepo/activemq/topic | fedora | | -| FCREPO_BINARYSTORAGE_TYPE | /fcrepo/binarystorage/type | file | | -| FCREPO_CATALINA_OPTS | /fcrepo/catalina/opts | | | -| FCREPO_DB_HOST | /fcrepo/db/host | mariadb | | -| FCREPO_DB_NAME | /fcrepo/db/name | fcrepo | | -| FCREPO_DB_PASSWORD | /fcrepo/db/password | password | | -| FCREPO_DB_PORT | /fcrepo/db/port | 3306 | | -| FCREPO_DB_ROOT_PASSWORD | /fcrepo/db/root/password | password | | -| FCREPO_DB_ROOT_USER | /fcrepo/db/root/user | root | | -| FCREPO_DB_USER | /fcrepo/db/user | fcrepo | | -| FCREPO_JAVA_OPTS | /fcrepo/java/opts | | | -| FCREPO_JWT_ADMIN_TOKEN | /fcrepo/jwt/admin/token | islandora | | -| FCREPO_MODESHAPE_CONFIGURATION | /fcrepo/modeshape/configuration | classpath:/config/repository.json | | -| FCREPO_PERSISTENCE_TYPE | /fcrepo/persistence/type | file | | -| FCREPO_QUEUE | /fcrepo/queue | fedora | | -| FCREPO_S3_BUCKET | /fcrepo/s3/bucket | | | -| FCREPO_S3_PASSWORD | /fcrepo/s3/password | | | -| FCREPO_S3_USER | /fcrepo/s3/user | | | -| FCREPO_TOPIC | /fcrepo/topic | fedora | | - -To allow -[external content](https://wiki.lyrasis.org/display/FEDORA51/External+Content) -provide sites as key pairs. Wherein multiple values is the url and the 'name' is -a key that replaces the '*' symbol below. - -| Environment Variable | Etcd Key | -| :---------------------- | :----------------------- | -| FCREPO_ALLOW_EXTERNAL_* | /fcrepo/allow/external/* | - -[Fcrepo Documentation]: https://wiki.lyrasis.org/display/FF -[Fcrepo]: https://github.com/fcrepo4/fcrepo4 diff --git a/fcrepo/rootfs/etc/confd/conf.d/activemq.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/activemq.xml.toml deleted file mode 100644 index 9b161299..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/activemq.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "activemq.xml.tmpl" -dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/activemq.xml" -uid = 100 -gid = 1000 -mode = "0640" -keys = [ "/activemq" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml b/fcrepo/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml deleted file mode 100644 index bf5ab47b..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "allowed-external-content.txt.tmpl" -dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/allowed-external-content.txt" -uid = 100 -gid = 1000 -mode = "0640" -keys = [ "/allow/external" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/claw.cnd.toml b/fcrepo/rootfs/etc/confd/conf.d/claw.cnd.toml deleted file mode 100644 index 298e52d0..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/claw.cnd.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "claw.cnd.tmpl" -dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/claw.cnd" -uid = 100 -gid = 1000 -mode = "0655" diff --git a/fcrepo/rootfs/etc/confd/conf.d/fcrepo-config.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/fcrepo-config.xml.toml deleted file mode 100644 index e994be5b..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/fcrepo-config.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "fcrepo-config.xml.tmpl" -dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/spring/fcrepo-config.xml" -uid = 100 -gid = 1000 -mode = "0640" -keys = [ "/activemq" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/repository.json.toml b/fcrepo/rootfs/etc/confd/conf.d/repository.json.toml deleted file mode 100644 index 0bcba8f5..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/repository.json.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "repository.json.tmpl" -dest = "/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/repository.json" -uid = 100 -gid = 1000 -mode = "0640" -keys = [ "/" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/setenv.sh.toml b/fcrepo/rootfs/etc/confd/conf.d/setenv.sh.toml deleted file mode 100644 index 45d63894..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/setenv.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setenv.sh.tmpl" -dest = "/opt/tomcat/bin/setenv.sh" -uid = 100 -gid = 1000 -mode = "0655" -keys = [ "/modeshape/configuration" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/setup-environment.sh.toml b/fcrepo/rootfs/etc/confd/conf.d/setup-environment.sh.toml deleted file mode 100644 index d7fc515b..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/setup-environment.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setup-environment.sh.tmpl" -dest = "/var/run/islandora/setup-environment.sh" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/syn-settings.xml.toml b/fcrepo/rootfs/etc/confd/conf.d/syn-settings.xml.toml deleted file mode 100644 index 58529b7e..00000000 --- a/fcrepo/rootfs/etc/confd/conf.d/syn-settings.xml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "syn-settings.xml.tmpl" -dest = "/opt/tomcat/conf/syn-settings.xml" -uid = 100 -gid = 1000 -mode = "0655" -keys = [ "/jwt/admin/token" ] diff --git a/fcrepo/rootfs/etc/confd/confd.toml b/fcrepo/rootfs/etc/confd/confd.toml deleted file mode 100644 index 68d47055..00000000 --- a/fcrepo/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/fcrepo" diff --git a/fcrepo/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl b/fcrepo/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl deleted file mode 100644 index 5b0bb6d2..00000000 --- a/fcrepo/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -http://drupal/ -{{ range gets "/allow/external/*" }}{{.Value}} -{{ end }} diff --git a/fcrepo/rootfs/etc/confd/templates/claw.cnd.tmpl b/fcrepo/rootfs/etc/confd/templates/claw.cnd.tmpl deleted file mode 100644 index 404341f4..00000000 --- a/fcrepo/rootfs/etc/confd/templates/claw.cnd.tmpl +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Islandora CLAW namespaces - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fcrepo/rootfs/etc/confd/templates/fcrepo-config.xml.tmpl b/fcrepo/rootfs/etc/confd/templates/fcrepo-config.xml.tmpl deleted file mode 100644 index 7d09a6c2..00000000 --- a/fcrepo/rootfs/etc/confd/templates/fcrepo-config.xml.tmpl +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /** = servletContainerAuthFilter,headerProvider,delegatedPrincipalProvider,webACFilter - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fcrepo/rootfs/etc/confd/templates/repository.json.tmpl b/fcrepo/rootfs/etc/confd/templates/repository.json.tmpl deleted file mode 100644 index d3422f0d..00000000 --- a/fcrepo/rootfs/etc/confd/templates/repository.json.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name" : "repo", - "jndiName" : "", - "workspaces" : { - "predefined" : ["default"], - "default" : "default", - "allowCreation" : true, - "cacheSize" : 10000 - }, - "storage" : { - {{ if eq (getv "/persistence/type" "file") "file" }} - "persistence": { - "type": "file", - "path" : "/data/objects" - }, - {{ end }} - {{ if eq (getv "/persistence/type" "file") "mysql" }} - "persistence": { - "type" : "db", - "connectionUrl": "jdbc:mysql://{{ getv "/db/host" "mariadb" }}:{{ getv "/db/port" "3306" }}/{{ getv "/db/name" "fcrepo" }}?createDatabaseIfNotExist=true", - "driver" : "com.mysql.jdbc.Driver", - "username" : "{{ getv "/db/user" "fcrepo" }}", - "password" : "{{ getv "/db/password" "password" }}" - }, - {{ end }} - {{ if eq (getv "/persistence/type" "file") "postgresql" }} - "persistence": { - "type" : "db", - "connectionUrl": "jdbc:postgresql://{{ getv "/db/host" "postgresql" }}:{{ getv "/db/port" "5432" }}/{{ getv "/db/name" "fcrepo" }}?createDatabaseIfNotExist=true", - "driver" : "org.postgresql.Driver", - "username" : "{{ getv "/db/user" "fcrepo" }}", - "password" : "{{ getv "/db/password" "password" }}" - }, - {{ end }} - {{ if eq (getv "/binarystorage/type" "file") "file" }} - "binaryStorage" : { - "type" : "file", - "directory" : "/data/binaries", - "minimumBinarySizeInBytes" : 4096 - } - {{ end }} - {{ if eq (getv "/binarystorage/type" "file") "s3" }} - "binaryStorage" : { - "type" : "s3", - "username" : "{{ getv "/s3/user" }}", - "password" : "{{ getv "/s3/password" }}", - "bucketName" : "{{ getv "/s3/bucket" }}" - } - {{ end }} - }, - "security" : { - "anonymous" : { - "roles" : ["readonly","readwrite","admin"], - "useOnFailedLogin" : false - }, - "providers" : [ - { "classname" : "org.fcrepo.auth.common.BypassSecurityServletAuthenticationProvider" } - ] - }, - "garbageCollection" : { - "threadPool" : "modeshape-gc", - "initialTime" : "00:00", - "intervalInHours" : 24 - }, - "node-types" : ["fedora-node-types.cnd", "file:/opt/tomcat/webapps/fcrepo/WEB-INF/classes/config/claw.cnd"] -} diff --git a/fcrepo/rootfs/etc/confd/templates/setenv.sh.tmpl b/fcrepo/rootfs/etc/confd/templates/setenv.sh.tmpl deleted file mode 100644 index 0f190348..00000000 --- a/fcrepo/rootfs/etc/confd/templates/setenv.sh.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -export JAVA_OPTS="{{ getv "/java/opts" "" }}" -export CATALINA_OPTS="{{ getv "/catalina/opts" "" }}" -export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.home=/data/home" -export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.velocity.runtime.log=/opt/tomcat/logs/velocity.log" -export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.modeshape.configuration={{ getv "/modeshape/configuration" "classpath:/config/repository.json" }} -Dfcrepo.jms.baseUrl=http://{{ index (lookupIP (getenv "HOSTNAME")) 0 }}/fcrepo/rest" diff --git a/fcrepo/rootfs/etc/confd/templates/setup-environment.sh.tmpl b/fcrepo/rootfs/etc/confd/templates/setup-environment.sh.tmpl deleted file mode 100644 index 96a3e781..00000000 --- a/fcrepo/rootfs/etc/confd/templates/setup-environment.sh.tmpl +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -with-contenv -foreground { - # We add / update the environment defined for the container, - # this allows our other initialization and service scripts - # use these settings; but does not change the existing - # environment as seen by linked containers. - # Variables can only be seen when using '#!/usr/bin/with-contenv' - s6-env -i - FCREPO_BINARYSTORAGE_TYPE="{{ getv "/binarystorage/type" "file" }}" - FCREPO_DB_HOST="{{ getv "/db/host" "mariadb" }}" - FCREPO_DB_NAME="{{ getv "/db/name" "fcrepo" }}" - FCREPO_DB_PASSWORD="{{ getv "/db/password" "password" }}" - FCREPO_DB_PORT="{{ getv "/db/port" "3306" }}" - FCREPO_DB_ROOT_PASSWORD="{{ getv "/db/root/password" "passwod" }}" - FCREPO_DB_ROOT_USER="{{ getv "/db/root/user" "root" }}" - FCREPO_DB_USER="{{ getv "/db/user" "fcrepo" }}" - FCREPO_PERSISTENCE_TYPE="{{ getv "/persistence/type" "file" }}" - FCREPO_S3_BUCKET="{{ getv "/s3/bucket" "" }}" - FCREPO_S3_PASSWORD="{{ getv "/s3/password" "" }}" - FCREPO_S3_USER="{{ getv "/s3/user" "" }}" - s6-dumpenv -- /var/run/s6/container_environment -} diff --git a/fcrepo/rootfs/etc/cont-init.d/03-fcrepo-setup.sh b/fcrepo/rootfs/etc/cont-init.d/03-fcrepo-setup.sh deleted file mode 100755 index dc3e4ae8..00000000 --- a/fcrepo/rootfs/etc/cont-init.d/03-fcrepo-setup.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -function execute_sql_file { - execute-sql-file.sh \ - --driver "${FCREPO_PERSISTENCE_TYPE}" \ - --host "${FCREPO_DB_HOST}" \ - --port "${FCREPO_DB_PORT}" \ - --user "${FCREPO_DB_ROOT_USER}" \ - --password "${FCREPO_DB_ROOT_PASSWORD}" \ - "${@}" -} - -function mysql_query { - cat <<- EOF --- Create fcrepo database in mariadb or mysql. -CREATE DATABASE IF NOT EXISTS ${FCREPO_DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci; - --- Create fcrepo user and grant rights. -CREATE USER IF NOT EXISTS '${FCREPO_DB_USER}'@'%' IDENTIFIED BY '${FCREPO_DB_PASSWORD}'; -GRANT ALL PRIVILEGES ON ${FCREPO_DB_NAME}.* to '${FCREPO_DB_USER}'@'%'; -FLUSH PRIVILEGES; - --- Update fcrepo password if changed. -SET PASSWORD FOR ${FCREPO_DB_USER}@'%' = PASSWORD('${FCREPO_DB_PASSWORD}') -EOF -} - -function mysql_create_database { - execute_sql_file <(mysql_query) -} - -function postgres_query { - cat <<- EOF -BEGIN; - -DO \$\$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${FCREPO_DB_USER}') THEN - CREATE ROLE ${FCREPO_DB_USER}; - END IF; -END -\$\$; - -ALTER ROLE ${FCREPO_DB_USER} WITH LOGIN; -ALTER USER ${FCREPO_DB_USER} PASSWORD '${FCREPO_DB_PASSWORD}'; - -ALTER DATABASE ${FCREPO_DB_NAME} OWNER TO ${FCREPO_DB_USER}; -GRANT ALL PRIVILEGES ON DATABASE ${FCREPO_DB_NAME} TO ${FCREPO_DB_USER}; - -COMMIT; -EOF -} - -function postgresql_database_exists { - execute_sql_file --database "${FCREPO_DB_NAME}" <(echo 'select 1') -} - -function postgresql_create_database { - # Postgres does not support CREATE DATABASE IF NOT EXISTS so split our logic across multiple queries. - if ! postgresql_database_exists; then - execute_sql_file <(echo "CREATE DATABASE ${FCREPO_DB_NAME}") - fi - execute_sql_file --database "${FCREPO_DB_NAME}" <(postgres_query) -} - -function create_database { - case "${FCREPO_PERSISTENCE_TYPE}" in - mysql|pdo_mysql) - mysql_create_database - ;; - pgsql|postgresql|pdo_pgsql) - postgresql_create_database - ;; - *) - echo "Only MySQL/PostgresSQL databases are supported for now." >&2 - exit 1 - esac -} - -# Change log files to redirect to stdout/stderr -function redirect_logs_to_stdout { - ln -sf /dev/stdout /opt/tomcat/logs/velocity.log - chown tomcat:tomcat /opt/tomcat/logs/velocity.log -} - -function requires_database { - [[ "${FCREPO_PERSISTENCE_TYPE}" = "mysql" ]] || [[ "${FCREPO_PERSISTENCE_TYPE}" = "postgresql" ]] -} - -function main { - redirect_logs_to_stdout - if requires_database; then - create_database - fi - - # When bind mounting we need to ensure that we - # actually can write to the folder. - chown tomcat:tomcat /data -} -main diff --git a/fcrepo6/.dockerignore b/fcrepo6/.dockerignore new file mode 100644 index 00000000..1b2f9f5c --- /dev/null +++ b/fcrepo6/.dockerignore @@ -0,0 +1,4 @@ +build.gradle.kts +README.md +tests +tests/**/* diff --git a/fcrepo6/Dockerfile b/fcrepo6/Dockerfile new file mode 100644 index 00000000..cc02f509 --- /dev/null +++ b/fcrepo6/Dockerfile @@ -0,0 +1,67 @@ +# syntax=docker/dockerfile:1.5.1 +FROM tomcat + +ARG TARGETARCH +ARG FCREPO_VERSION="6.4.0" +ARG FCREPO_FILE="fcrepo-webapp-${FCREPO_VERSION}.war" +ARG FCREPO_URL="https://github.com/fcrepo/fcrepo/releases/download/fcrepo-${FCREPO_VERSION}/${FCREPO_FILE}" +ARG FCREPO_SHA256="50c4300b71a16e644ea0f2fec0a888ff9ae9f3a4a295a54e9c09cd213483028f" + +ARG SYN_VERSION="1.1.0" +ARG SYN_FILE="islandora-syn-${SYN_VERSION}-all.jar" +ARG SYN_URL="https://github.com/Islandora-CLAW/Syn/releases/download/v${SYN_VERSION}/${SYN_FILE}" +ARG SYN_SHA256="bcad5f872930b1bcc9ea4a176c60e22683297121357336769a21ead9fadcbbd5" + +ARG IMPORT_EXPORT_VERSION="1.0.1" +ARG IMPORT_EXPORT_FILE="fcrepo-import-export-${IMPORT_EXPORT_VERSION}.jar" +ARG IMPORT_EXPORT_URL="https://github.com/fcrepo-exts/fcrepo-import-export/releases/download/fcrepo-import-export-${IMPORT_EXPORT_VERSION}/${IMPORT_EXPORT_FILE}" +ARG IMPORT_EXPORT_SHA256="89c579d1223c8f3c0da60c4309a06e47f5919c51929d976e60ea525c60cb33d1" + +ARG UPGRADE_UTILS_VERSION="6.0.0-beta-1" +ARG UPGRADE_UTILS_FILE="fcrepo-upgrade-utils-${UPGRADE_UTILS_VERSION}.jar" +ARG UPGRADE_UTILS_URL="https://github.com/fcrepo-exts/fcrepo-upgrade-utils/releases/download/fcrepo-upgrade-utils-${UPGRADE_UTILS_VERSION}/${UPGRADE_UTILS_FILE}" +ARG UPGRADE_UTILS_SHA256="e8a0bbbabca45ff95b2ffb5c62cad49e02548bc116b80f2747d5215f80d02a0a" + +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=fcrepo6-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${FCREPO_URL}" \ + --sha256 "${FCREPO_SHA256}" \ + --dest "/opt/tomcat/webapps/fcrepo" \ + && \ + download.sh \ + --url "${SYN_URL}" \ + --sha256 "${SYN_SHA256}" \ + --dest "/opt/tomcat/lib" \ + && \ + download.sh \ + --url "${IMPORT_EXPORT_URL}" \ + --sha256 "${IMPORT_EXPORT_SHA256}" \ + --dest "/opt/tomcat" \ + && \ + download.sh \ + --url "${UPGRADE_UTILS_URL}" \ + --sha256 "${UPGRADE_UTILS_SHA256}" \ + --dest "/opt/tomcat" \ + && \ + cleanup.sh + +ENV \ + FCREPO_ACTIVEMQ_BROKER=tcp://activemq:61616 \ + FCREPO_ACTIVEMQ_QUEUE=fedora \ + FCREPO_ACTIVEMQ_TOPIC=fedora \ + FCREPO_DB_NAME=fcrepo \ + FCREPO_DB_PASSWORD=password \ + FCREPO_DB_USER=fcrepo \ + FCREPO_DISABLE_SYN=false \ + FCREPO_PERSISTENCE_TYPE=file \ + FCREPO_TOMCAT_ADMIN_ROLES=manager-gui,fedoraAdmin \ + FCREPO_S3_BUCKET= \ + FCREPO_S3_PASSWORD= \ + FCREPO_S3_USER= \ + FCREPO_AWS_REGION=us-east-1 \ + FCREPO_S3_PREFIX= + +COPY --link rootfs / + +RUN chown -R tomcat:tomcat /opt/tomcat diff --git a/fcrepo6/README.md b/fcrepo6/README.md new file mode 100644 index 00000000..14cbd5be --- /dev/null +++ b/fcrepo6/README.md @@ -0,0 +1,89 @@ +# Fcrepo + +Docker image for [Fcrepo] version 6.4.0. + +Please refer to the [Fcrepo Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Fcrepo], and allow you +to view on . + +```bash +docker run --rm -ti -p 80:80 islandora/fcrepo +``` + +## Dependencies + +Requires `islandora/tomcat` docker image to build. Please refer to the +[Tomcat Image README](../tomcat/README.md) for additional information including +additional settings, volumes, ports, etc. + +## Volumes + +| Path | Description | +| :---- | :-------------- | +| /data | OCFL Filesystem | + +> N.B. Volumes are not created automatically. It is up to the user to either bind +> mount or attach a volume at the paths specified above. + +## Settings + +### Confd Settings + +| Environment Variable | Default | Description | +| :--------------------------- | :------------------- | :----------------------------------------------------------------------------------- | +| FCREPO_ACTIVEMQ_BROKER | tcp://activemq:61616 | The location of the ActiveMQ Broker in which to publish JMS messages to | +| FCREPO_ACTIVEMQ_QUEUE | fedora | The ActiveMQ Queue in which to publish JMS messages | +| FCREPO_ACTIVEMQ_QUEUE_ENABLE | false | If `true` publish JMS messages on the queue `FCREPO_ACTIVEMQ_QUEUE` | +| FCREPO_ACTIVEMQ_TOPIC | fedora | The ActiveMQ Topic in which to publish JMS messages | +| FCREPO_ACTIVEMQ_TOPIC_ENABLE | true | If `true` publish JMS messages on the topic `FCREPO_ACTIVEMQ_TOPIC` | +| FCREPO_BINARYSTORAGE_TYPE | file | The binary storage type. Only `file` and `s3` are supported at this time | +| FCREPO_AWS_REGION | us-east-1 | AWS Region for S3 Bucket | +| FCREPO_S3_BUCKET | | Bucket to use for S3 Storage | +| FCREPO_S3_USER | | AWS User for S3 Storage | +| FCREPO_S3_PASSWORD | | AWS Secret Token for S3 Storage | +| FCREPO_S3_PREFIX | | AWS Prefix for S3 Storage | +| FCREPO_PERSISTENCE_TYPE | file | The object store type. Only `file`, `mysql`, `postgresql` are supported at this time | +| FCREPO_DISABLE_SYN | false | Enable or disable authentication via [Syn](https://github.com/Islandora/Syn) | + +To allow [external content] provide sites as key pairs. Wherein multiple values +is the url and the 'name' is a key that replaces the '*' symbol below. + +| Environment Variable | +| :---------------------- | +| FCREPO_ALLOW_EXTERNAL_* | + +### JWT Settings + +[Fcrepo] makes use of JWT for authentication. Please see the documentation in +the [base image] for more information. + +### Database Settings + +[Fcrepo] can optionally make use of a database for object storage. Please see +the documentation in the [base image] for more information about the default +database connection configuration. + +The following settings are only used if `FCREPO_PERSISTENCE_TYPE` is set to +`mysql` or `postgresql`. + +| Environment Variable | Default | Description | +| :------------------- | :------- | :------------------------------------------------------- | +| FCREPO_DB_NAME | fedora | The name of the database | +| FCREPO_DB_USER | fedora | The user to connect to the database | +| FCREPO_DB_PASSWORD | password | The password of the user used to connect to the database | + +Additionally the `DB_DRIVER` variable is derived from the +`FCREPO_PERSISTENCE_TYPE` so users do not need to specify it separately. + +### Tomcat Settings + +Fcrepo is deployed in as a servlet in Tomcat. Please see the documentation in +the [tomcat image] for more information. + +[base image]: ../base/README.md +[external content]: https://wiki.lyrasis.org/display/FEDORA6x/External+Content +[Fcrepo Documentation]: https://wiki.lyrasis.org/display/FF +[Fcrepo]: https://github.com/fcrepo/fcrepo +[s3]: https://aws.amazon.com/s3/ +[tomcat image]: ../tomcat/README.md diff --git a/fcrepo6/rootfs/etc/confd/conf.d/activemq.xml.toml b/fcrepo6/rootfs/etc/confd/conf.d/activemq.xml.toml new file mode 100644 index 00000000..6c4d9ba1 --- /dev/null +++ b/fcrepo6/rootfs/etc/confd/conf.d/activemq.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "activemq.xml.tmpl" +dest = "/opt/tomcat/conf/activemq.xml" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/fcrepo6/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml b/fcrepo6/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml new file mode 100644 index 00000000..ce78946b --- /dev/null +++ b/fcrepo6/rootfs/etc/confd/conf.d/allowed-external-content.txt.toml @@ -0,0 +1,7 @@ +[template] +src = "allowed-external-content.txt.tmpl" +dest = "/opt/tomcat/conf/allowed-external-content.txt" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/context.xml.toml b/fcrepo6/rootfs/etc/confd/conf.d/context.xml.toml similarity index 87% rename from fcrepo/rootfs/etc/confd/conf.d/context.xml.toml rename to fcrepo6/rootfs/etc/confd/conf.d/context.xml.toml index 16c8f081..746afa81 100644 --- a/fcrepo/rootfs/etc/confd/conf.d/context.xml.toml +++ b/fcrepo6/rootfs/etc/confd/conf.d/context.xml.toml @@ -4,3 +4,4 @@ dest = "/opt/tomcat/conf/context.xml" uid = 100 gid = 1000 mode = "0640" +keys = [ "/" ] diff --git a/fcrepo/rootfs/etc/confd/templates/activemq.xml.tmpl b/fcrepo6/rootfs/etc/confd/templates/activemq.xml.tmpl similarity index 84% rename from fcrepo/rootfs/etc/confd/templates/activemq.xml.tmpl rename to fcrepo6/rootfs/etc/confd/templates/activemq.xml.tmpl index 4ec3ccfc..c7ef582d 100644 --- a/fcrepo/rootfs/etc/confd/templates/activemq.xml.tmpl +++ b/fcrepo6/rootfs/etc/confd/templates/activemq.xml.tmpl @@ -17,10 +17,10 @@ - + - - + + diff --git a/fcrepo6/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl b/fcrepo6/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl new file mode 100644 index 00000000..9f8e0a83 --- /dev/null +++ b/fcrepo6/rootfs/etc/confd/templates/allowed-external-content.txt.tmpl @@ -0,0 +1,4 @@ +http://drupal/ +{{- range gets "/fcrepo/allow/external/*" }} +{{.Value}} +{{- end }} diff --git a/fcrepo/rootfs/etc/confd/templates/context.xml.tmpl b/fcrepo6/rootfs/etc/confd/templates/context.xml.tmpl similarity index 81% rename from fcrepo/rootfs/etc/confd/templates/context.xml.tmpl rename to fcrepo6/rootfs/etc/confd/templates/context.xml.tmpl index 40ad286d..9635887d 100644 --- a/fcrepo/rootfs/etc/confd/templates/context.xml.tmpl +++ b/fcrepo6/rootfs/etc/confd/templates/context.xml.tmpl @@ -4,5 +4,7 @@ WEB-INF/web.xml ${catalina.base}/conf/web.xml - +{{ if eq (getenv "FCREPO_DISABLE_SYN") "false" }} + +{{ end }} diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-db-driver b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-db-driver new file mode 100644 index 00000000..e69de29b diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/dependencies.d/ready b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/type b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/up b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/up new file mode 100755 index 00000000..b4bef441 --- /dev/null +++ b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/fcrepo-setup/up @@ -0,0 +1,2 @@ +# Some directories must exist prior to rendering templates. +/etc/s6-overlay/scripts/fcrepo-setup.sh diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/dependencies.d/container-environment b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/type b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/type @@ -0,0 +1 @@ +oneshot diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/up b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/up new file mode 100755 index 00000000..68952fda --- /dev/null +++ b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/up @@ -0,0 +1,2 @@ +# Some directories must exist prior to rendering templates. +/etc/s6-overlay/scripts/set-db-driver.sh diff --git a/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/tomcat/dependencies.d/fcrepo-setup b/fcrepo6/rootfs/etc/s6-overlay/s6-rc.d/tomcat/dependencies.d/fcrepo-setup new file mode 100644 index 00000000..e69de29b diff --git a/fcrepo6/rootfs/etc/s6-overlay/scripts/fcrepo-setup.sh b/fcrepo6/rootfs/etc/s6-overlay/scripts/fcrepo-setup.sh new file mode 100755 index 00000000..72fe0aad --- /dev/null +++ b/fcrepo6/rootfs/etc/s6-overlay/scripts/fcrepo-setup.sh @@ -0,0 +1,83 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +function mysql_create_database { + cat <<-EOF | create-database.sh +-- Create fcrepo database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS ${FCREPO_DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci; + +-- Create fcrepo user and grant rights. +CREATE USER IF NOT EXISTS '${FCREPO_DB_USER}'@'%' IDENTIFIED BY '${FCREPO_DB_PASSWORD}'; +GRANT ALL PRIVILEGES ON ${FCREPO_DB_NAME}.* to '${FCREPO_DB_USER}'@'%'; +FLUSH PRIVILEGES; + +-- Update fcrepo password if changed. +SET PASSWORD FOR ${FCREPO_DB_USER}@'%' = PASSWORD('${FCREPO_DB_PASSWORD}') +EOF +} + +function postgresql_create_database { + cat <<-EOF | create-database.sh +BEGIN; + +DO \$\$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${FCREPO_DB_USER}') THEN + CREATE ROLE ${FCREPO_DB_USER}; + END IF; +END +\$\$; + +ALTER ROLE ${FCREPO_DB_USER} WITH LOGIN; +ALTER USER ${FCREPO_DB_USER} PASSWORD '${FCREPO_DB_PASSWORD}'; + +ALTER DATABASE ${FCREPO_DB_NAME} OWNER TO ${FCREPO_DB_USER}; +GRANT ALL PRIVILEGES ON DATABASE ${FCREPO_DB_NAME} TO ${FCREPO_DB_USER}; + +COMMIT; +EOF +} + +# Some persistence backends require setup. +function setup_persistence_backend { + case "${DB_DRIVER}" in + none) + # No action required. + ;; + mysql) + mysql_create_database + ;; + postgresql) + postgresql_create_database + ;; + *) + echo "Only mysql/postgresql are supported values for DB_DRIVER." >&2 + exit 1 + ;; + esac +} + +function wait_for_broker { + local tcp="${FCREPO_ACTIVEMQ_BROKER%:*}" + local host="${tcp##*/}" + local port="${FCREPO_ACTIVEMQ_BROKER##*:}" + + if timeout 300 wait-for-open-port.sh "${host}" "${port}"; then + echo "Broker Found at ${host}:${port}" + return 0 + else + echo "Could not connect to broker at ${host}:${port}" + exit 1 + fi +} + +function main { + setup_persistence_backend + # When bind mounting we need to ensure that we + # actually can write to the folder. + chown tomcat:tomcat /data + # Fcrepo can fail to start if it cannot connect to an broker on startup. + wait_for_broker +} +main diff --git a/fcrepo6/rootfs/etc/s6-overlay/scripts/set-db-driver.sh b/fcrepo6/rootfs/etc/s6-overlay/scripts/set-db-driver.sh new file mode 100755 index 00000000..b1722335 --- /dev/null +++ b/fcrepo6/rootfs/etc/s6-overlay/scripts/set-db-driver.sh @@ -0,0 +1,23 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# FCREPO_PERSISTENCE_TYPE dictates which DB_DRIVER should be used. +case "${FCREPO_PERSISTENCE_TYPE}" in +file) + DB_DRIVER=none + ;; +mysql) + DB_DRIVER=mysql + ;; +postgresql) + DB_DRIVER=postgresql + ;; +*) + echo "Only file/mysql/postgresql are supported values for FCREPO_PERSISTENCE_TYPE." >&2 + exit 1 + ;; +esac + +# Import derived value for DB_DRIVER into the container environment. +echo "DB_DRIVER=${DB_DRIVER}" | /usr/local/bin/confd-import-environment.sh diff --git a/fcrepo6/rootfs/opt/tomcat/bin/setenv.sh b/fcrepo6/rootfs/opt/tomcat/bin/setenv.sh new file mode 100755 index 00000000..44116653 --- /dev/null +++ b/fcrepo6/rootfs/opt/tomcat/bin/setenv.sh @@ -0,0 +1,46 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +export JAVA_OPTS="${TOMCAT_JAVA_OPTS}" +export CATALINA_OPTS="${TOMCAT_CATALINA_OPTS}" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.home=/data/home" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.velocity.runtime.log=/dev/stdout" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.jms.baseUrl=http://${HOSTNAME}/fcrepo/rest" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.external.content.allowed=/opt/tomcat/conf/allowed-external-content.txt" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.autoversioning.enabled=false" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.activemq.directory=file:///data/home/data/Activemq" +export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.activemq.configuration=file:///opt/tomcat/conf/activemq.xml" +# Set timeout +export CATALINA_OPTS="${CATALINA_OPTS} -DconnectionTimeout=${FCREPO_CATALINA_TIMEOUT:=-1}" + +case "${DB_DRIVER}" in +none) + # No action required. + ;; +mysql) + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.db.url=jdbc:mysql://${DB_MYSQL_HOST}:${DB_MYSQL_PORT}/${FCREPO_DB_NAME}" + ;; +postgresql) + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.db.url=jdbc:postgresql://${DB_POSTGRESQL_HOST}:${DB_POSTGRESQL_PORT}/${FCREPO_DB_NAME}" + ;; +*) + echo "Only mysql/postgresql are supported values for DB_DRIVER." >&2 + exit 1 + ;; +esac + +if [[ "${DB_DRIVER}" != "none" ]]; then + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.db.user=${FCREPO_DB_USER}" + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.db.password=${FCREPO_DB_PASSWORD}" +fi + +if [[ "${FCREPO_DISABLE_SYN}" == "true" ]]; then + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.properties.management=relaxed" +fi + +if [[ "${FCREPO_BINARYSTORAGE_TYPE}" == "file" ]]; then + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.storage=ocfl-fs" +fi +if [[ "${FCREPO_BINARYSTORAGE_TYPE}" == "s3" ]]; then + # Enable S3 mode and set default options + export CATALINA_OPTS="${CATALINA_OPTS} -Dfcrepo.storage=ocfl-s3 -Dfcrepo.aws.region=${FCREPO_AWS_REGION} -Dfcrepo.ocfl.s3.bucket=${FCREPO_S3_BUCKET} -Dfcrepo.ocfl.s3.prefix=${FCREPO_S3_PREFIX}" +fi diff --git a/fcrepo6/rootfs/opt/tomcat/webapps/fcrepo/META-INF/context.xml b/fcrepo6/rootfs/opt/tomcat/webapps/fcrepo/META-INF/context.xml new file mode 100644 index 00000000..7aff0ac4 --- /dev/null +++ b/fcrepo6/rootfs/opt/tomcat/webapps/fcrepo/META-INF/context.xml @@ -0,0 +1,3 @@ + + + diff --git a/fcrepo6/tests/ServiceStartsWithBackendFile/build.gradle.kts b/fcrepo6/tests/ServiceStartsWithBackendFile/build.gradle.kts new file mode 100644 index 00000000..dc591889 --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendFile/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("fcrepo6", 0, 143) +} diff --git a/fcrepo6/tests/ServiceStartsWithBackendFile/docker-compose.yml b/fcrepo6/tests/ServiceStartsWithBackendFile/docker-compose.yml new file mode 100644 index 00000000..73f4fdae --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendFile/docker-compose.yml @@ -0,0 +1,24 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +x-common: &common + restart: "no" + +name: fcrepo6-servicestartswithbackendfile +services: + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} + fcrepo6: + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${FCREPO6:-islandora/fcrepo6:local} + depends_on: + - activemq diff --git a/fcrepo6/tests/ServiceStartsWithBackendFile/test.sh b/fcrepo6/tests/ServiceStartsWithBackendFile/test.sh new file mode 100755 index 00000000..a69afcc2 --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendFile/test.sh @@ -0,0 +1,15 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Wait for fcrepo to start. +wait_20x http://localhost:8080/fcrepo/rest + +# Add some content. +object=$(curl --fail -X POST -H "Authorization: Bearer islandora" -H "Content-Type:text/plain" "http://localhost:8080/fcrepo/rest" 2>/dev/null) +echo "Create Object: $object" + +# All tests were successful +exit 0 diff --git a/fcrepo6/tests/ServiceStartsWithBackendMySQL/build.gradle.kts b/fcrepo6/tests/ServiceStartsWithBackendMySQL/build.gradle.kts new file mode 100644 index 00000000..dc591889 --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendMySQL/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("fcrepo6", 0, 143) +} diff --git a/fcrepo6/tests/ServiceStartsWithBackendMySQL/docker-compose.yml b/fcrepo6/tests/ServiceStartsWithBackendMySQL/docker-compose.yml new file mode 100644 index 00000000..01c1685f --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendMySQL/docker-compose.yml @@ -0,0 +1,29 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +x-common: &common + restart: "no" + +name: fcrepo6-servicestartswithbackendmysql +services: + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} + mariadb: + image: ${MARIADB:-islandora/mariadb:local} + fcrepo6: + environment: + FCREPO_PERSISTENCE_TYPE: mysql + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${FCREPO6:-islandora/fcrepo6:local} + depends_on: + - activemq + - mariadb diff --git a/fcrepo6/tests/ServiceStartsWithBackendMySQL/test.sh b/fcrepo6/tests/ServiceStartsWithBackendMySQL/test.sh new file mode 100755 index 00000000..f9ef12dd --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendMySQL/test.sh @@ -0,0 +1,35 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +function count { + cat <<-EOF | execute-sql-file.sh --database "fcrepo" - -- -N 2>/dev/null +SELECT COUNT(*) as count FROM containment; +EOF +} + +# Wait for fcrepo to start. +wait_20x http://localhost:8080/fcrepo/rest + +# Add some content. +old_count=$(count) +echo "Old Count: ${old_count}" +object=$(curl --fail -X POST -H "Authorization: Bearer islandora" -H "Content-Type:text/plain" "http://localhost:8080/fcrepo/rest" 2>/dev/null) +echo "Create Object: $object" + +# Check that the database has been modified. +new_count=$(count) +echo "New Count: ${new_count}" + +# Check if results meet expectations. +if [[ "${new_count}" -gt "${old_count}" ]]; then + echo "Database was modified." +else + echo "Database was not modified." + exit 1 +fi + +# All tests were successful +exit 0 diff --git a/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/build.gradle.kts b/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/build.gradle.kts new file mode 100644 index 00000000..dc591889 --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("fcrepo6", 0, 143) +} diff --git a/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml b/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml new file mode 100644 index 00000000..9698c235 --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml @@ -0,0 +1,29 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" +x-common: &common + restart: "no" + +name: fcrepo6-servicestartswithbackendpostgresql +services: + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} + postgresql: + image: ${POSTGRESQL:-islandora/postgresql:local} + fcrepo6: + # Allow downstream container to override `DB` environment variables. + environment: + FCREPO_PERSISTENCE_TYPE: postgresql + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${FCREPO6:-islandora/fcrepo6:local} + depends_on: + - activemq + - postgresql diff --git a/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/test.sh b/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/test.sh new file mode 100755 index 00000000..0b1a800b --- /dev/null +++ b/fcrepo6/tests/ServiceStartsWithBackendPostgreSQL/test.sh @@ -0,0 +1,35 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +function count { + cat <<-EOF | execute-sql-file.sh -x --database "fcrepo" -- -XAt 2>/dev/null +SELECT COUNT(*) as count FROM containment; +EOF +} + +# Wait for fcrepo to start. +wait_20x http://localhost:8080/fcrepo/rest + +# Add some content. +old_count=$(count) +echo "Old Count: ${old_count}" +object=$(curl --fail -X POST -H "Authorization: Bearer islandora" -H "Content-Type:text/plain" "http://localhost:8080/fcrepo/rest" 2>/dev/null) +echo "Create Object: $object" + +# Check that the database has been modified. +new_count=$(count) +echo "New Count: ${new_count}" + +# Check if results meet expectations. +if [[ "${new_count}" -gt "${old_count}" ]]; then + echo "Database was modified." +else + echo "Database was not modified." + exit 1 +fi + +# All tests were successful +exit 0 diff --git a/fits/.dockerignore b/fits/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/fits/.dockerignore +++ b/fits/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/fits/Dockerfile b/fits/Dockerfile index 4bf076f8..de464561 100644 --- a/fits/Dockerfile +++ b/fits/Dockerfile @@ -1,20 +1,60 @@ -# syntax=docker/dockerfile:experimental -FROM local/tomcat:latest +# syntax=docker/dockerfile:1.5.1 +FROM tomcat -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - FITSSERVLET_VERSION=1.2.1 && \ - FITSSERVLET_FILE="fits-${FITSSERVLET_VERSION}.war" && \ - FITSSERVLET_URL="http://projects.iq.harvard.edu/files/fits/files/${FITSSERVLET_FILE}" && \ - FITSSERVLET_SHA256="13cfcb910092b197757e459353f0c30381febfca6baf3031ac69ff92789b200c" && \ - download.sh --url "${FITSSERVLET_URL}" --sha256 "${FITSSERVLET_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-war-into-tomcat.sh --name "fits" --file "${DOWNLOAD_CACHE_DIRECTORY}/${FITSSERVLET_FILE}" && \ - FITS_VERSION="1.5.0" && \ - FITS_FILE="fits-${FITS_VERSION}.zip" && \ - FITS_URL="https://github.com/harvard-lts/fits/releases/download/${FITS_VERSION}/${FITS_FILE}" \ - FITS_SHA256="1378a78892db103b3a00e45c510b58c70e19a1a401b3720ff4d64a51438bfe0b" && \ +ARG TARGETARCH +ARG FITSSERVLET_VERSION="1.2.3" +ARG FITSSERVLET_FILE="fits-service-${FITSSERVLET_VERSION}.war" +ARG FITSSERVLET_URL="https://github.com/harvard-lts/FITSservlet/releases/download/${FITSSERVLET_VERSION}/${FITSSERVLET_FILE}" +ARG FITSSERVLET_SHA256="e98450a1617c491976966a307da8b9c783c83e9e1a79bca9dbd9bc6c9a7226cd" + +ARG FITS_VERSION="1.5.5" +ARG FITS_FILE="fits-${FITS_VERSION}.zip" +ARG FITS_URL="https://github.com/harvard-lts/fits/releases/download/${FITS_VERSION}/${FITS_FILE}" +ARG FITS_SHA256="48be7ad9f27d9cc0b52c63f1aea1a3814e1b6996ca4e8467e77772c187ac955c" + +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=fits-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${FITSSERVLET_URL}" \ + --sha256 "${FITSSERVLET_SHA256}" \ + --dest "/opt/tomcat/webapps/fits" \ + && \ mkdir /opt/fits && \ - download.sh --url "${FITS_URL}" --sha256 "${FITS_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - unzip "${DOWNLOAD_CACHE_DIRECTORY}/${FITS_FILE}" -d /opt/fits + download.sh \ + --url "${FITS_URL}" \ + --sha256 "${FITS_SHA256}" \ + --dest "/opt/fits" \ + tools/exiftool/perl/html \ + tools/exiftool/windows \ + tools/file_utility_windows \ + tools/mediainfo \ + && \ + rm /opt/fits/lib/jna-* && \ + cleanup.sh + +# Replace linux shared libraries with ones that target muslibc and are platform specific. +# Also add perl for exiftool, and platform specific jna so native libs can be loaded. +# +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=fits-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ + file \ + java-jna \ + libmediainfo \ + libzen \ + perl \ + && \ + cleanup.sh + +ENV \ + FITS_MAX_IN_MEMORY_FILE_SIZE=4 \ + FITS_MAX_OBJECTS_IN_POOL=5 \ + FITS_MAX_REQUEST_SIZE=2000 \ + FITS_MAX_UPLOAD_FILE_SIZE=2000 \ + FITS_SERVICE_LOG_LEVEL=INFO + +COPY --link rootfs / -COPY rootfs / +RUN cp $(realpath /usr/share/java/jna.jar) /opt/fits/lib && \ + chown -R tomcat:tomcat /opt/tomcat /opt/fits && \ + cleanup.sh diff --git a/fits/README.md b/fits/README.md index 71e7a970..b4b77e31 100644 --- a/fits/README.md +++ b/fits/README.md @@ -1,10 +1,10 @@ # Fits -Docker image for [Fits] version 5.1.0. +Docker image for [Fits](https://projects.iq.harvard.edu/fits/home) version 1.5.5. Please refer to the [Fits Documentation] for more in-depth information. -As a quick example this will bring up an instance of [Fits], and allow you +As a quick example this will bring up an instance of [Fits](https://projects.iq.harvard.edu/fits/home), and allow you to view on . ```bash @@ -19,18 +19,15 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :--------------------------- | :---------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------- | -| FITS_MAX_IN_MEMORY_FILE_SIZE | /fits/max/in/memory/file/size | 4 | Maximum size of an uploaded size kept in memory in MiB. Otherwise temporarily persisted to disk. | -| FITS_MAX_OBJECTS_IN_POOL | /fits/max/objects/in/pool | 5 | Number of objects in FITSServlet object pool. | -| FITS_MAX_REQUEST_SIZE | /fits/max/request/size | 2000 | Maximum size of HTTP Request object in MiB. Must be equal to or larger than the value for /fits/max/upload/file/size | -| FITS_MAX_UPLOAD_FILE_SIZE | /fits/max/upload/file/size | 2000 | Maximum allowable size of uploaded file in MiB. | +| Environment Variable | Default | Description | +| :--------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------- | +| FITS_MAX_IN_MEMORY_FILE_SIZE | 4 | Maximum size of an uploaded size kept in memory in MiB. Otherwise temporarily persisted to disk. | +| FITS_MAX_OBJECTS_IN_POOL | 5 | Number of objects in FITSServlet object pool. | +| FITS_MAX_REQUEST_SIZE | 2000 | Maximum size of HTTP Request object in MiB. Must be equal to or larger than the value for /fits/max/upload/file/size | +| FITS_MAX_UPLOAD_FILE_SIZE | 2000 | Maximum allowable size of uploaded file in MiB. | +| FITS_SERVICE_LOG_LEVEL | INFO | Log level. Possible Values: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE or ALL | ## Logs -| Path | Description | -| :-------------------------------- | :---------- | -| /opt/tomcat/logs/fits-service.log | | - [Fits Documentation]: https://wiki.lyrasis.org/display/FF [Fits]: https://github.com/fits4/fits4 diff --git a/fits/rootfs/etc/confd/conf.d/catalina.properties.toml b/fits/rootfs/etc/confd/conf.d/catalina.properties.toml deleted file mode 100644 index cc6b2a90..00000000 --- a/fits/rootfs/etc/confd/conf.d/catalina.properties.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "catalina.properties.tmpl" -dest = "/opt/tomcat/conf/catalina.properties" -uid = 100 -gid = 1000 -mode = "0644" diff --git a/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml b/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml index 8a27f595..bd757eb4 100644 --- a/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml +++ b/fits/rootfs/etc/confd/conf.d/fits-service.properties.toml @@ -1,7 +1,7 @@ [template] src = "fits-service.properties.tmpl" -dest = "/opt/tomcat/conf/fit-service.properties" +dest = "/opt/tomcat/conf/fits-service.properties" uid = 100 gid = 1000 mode = "0644" -keys = ["/"] +keys = [ "/" ] diff --git a/fits/rootfs/etc/confd/conf.d/log4j.properties.toml b/fits/rootfs/etc/confd/conf.d/log4j.properties.toml new file mode 100644 index 00000000..2d966c9b --- /dev/null +++ b/fits/rootfs/etc/confd/conf.d/log4j.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "log4j.properties.tmpl" +dest = "/opt/fits/log4j.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/fits/rootfs/etc/confd/conf.d/log4j2.xml.toml b/fits/rootfs/etc/confd/conf.d/log4j2.xml.toml new file mode 100644 index 00000000..47d89317 --- /dev/null +++ b/fits/rootfs/etc/confd/conf.d/log4j2.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "log4j2.xml.tmpl" +dest = "/opt/tomcat/webapps/fits/WEB-INF/classes/log4j2.xml" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/fits/rootfs/etc/confd/confd.toml b/fits/rootfs/etc/confd/confd.toml deleted file mode 100644 index 331ea474..00000000 --- a/fits/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/fits" diff --git a/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl b/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl index 6edb5e70..4e3b7c8f 100644 --- a/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl +++ b/fits/rootfs/etc/confd/templates/fits-service.properties.tmpl @@ -1,8 +1,8 @@ # Number of objects in FITSServlet object pool -max.objects.in.pool={{ getv "/max/objects/in/pool" "5" }} +max.objects.in.pool={{ getenv "FITS_MAX_OBJECTS_IN_POOL" }} # Maximum allowable size of uploaded file -max.upload.file.size.MB={{ getv "/max/upload/file/size" "2000" }} +max.upload.file.size.MB={{ getenv "FITS_MAX_UPLOAD_FILE_SIZE" }} # Maximum size of HTTP Request object. Must be equal to or larger than the value for max.upload.file.size.MB -max.request.size.MB={{ getv "/max/request/size" "2000" }} +max.request.size.MB={{ getenv "FITS_MAX_REQUEST_SIZE" }} # Maximum size of an uploaded size kept in memory. Otherwise temporarily persisted to disk. -max.in.memory.file.size.MB={{ getv "/max/in/memory/file/size" "4" }} +max.in.memory.file.size.MB={{ getenv "FITS_MAX_IN_MEMORY_FILE_SIZE" }} diff --git a/fits/rootfs/etc/confd/templates/log4j.properties.tmpl b/fits/rootfs/etc/confd/templates/log4j.properties.tmpl new file mode 100644 index 00000000..0bcf6f75 --- /dev/null +++ b/fits/rootfs/etc/confd/templates/log4j.properties.tmpl @@ -0,0 +1,56 @@ +# +# Copyright (c) 2016 by The President and Fellows of Harvard College +# 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 permission and limitations under the License. +# + +#------------------------------------------------------------------------------ +# +# The following properties set the logging levels and log appender. The +# log4j.rootCategory variable defines the default log level plus one or more +# appenders. +# +# To override the default (rootCategory) log level, +# define a property of the form (see below for available values): +# +# Available logger names: +# CONSOLE The command line console (defaults to standard error output) +# FILE The log file to write to. +# +# Possible Log Levels: +# ERROR - only errors during processing are logged, or FATAL. +# WARN - warnings, errors and fatal are logged. +# INFO - general info messages and all the above are logged. +# DEBUG - more detailed messages and all the above are logged. +# TRACE - the most detailed messages and all the above are logged. +# +# OFF - This will turn off logging for an appender. +# +#------------------------------------------------------------------------------ + +log4j.rootLogger={{ getenv "FITS_SERVICE_LOG_LEVEL" }}, CONSOLE + +# create substitutions for appenders +date-pattern={yyyy-MM-dd HH:mm:ss} + +#------------------------------------------------------------------------------ +# direct log messages to console +#------------------------------------------------------------------------------ +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.Target=System.out +log4j.appender.CONSOLE.Threshold={{ getenv "FITS_SERVICE_LOG_LEVEL" }} +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d${date-pattern} - %5p - %c{1}:%L - %m%n +# Detailed appender for debugging, includes thread name: +#log4j.appender.CONSOLE.layout.ConversionPattern=%d${date-pattern} - %5p - [%t] %c{1}:%L - %m%n + +#---------------------------------------------------------- +# +# Class- and package-specific loggers for debugging if necessary +log4j.logger.uk.gov.nationalarchives.droid=FATAL,CONSOLE +log4j.logger.edu.harvard.hul.ois.jhove=FATAL,CONSOLE +log4j.logger.org.apache.tika=FATAL,CONSOLE diff --git a/fits/rootfs/etc/confd/templates/log4j2.xml.tmpl b/fits/rootfs/etc/confd/templates/log4j2.xml.tmpl new file mode 100644 index 00000000..8addbca1 --- /dev/null +++ b/fits/rootfs/etc/confd/templates/log4j2.xml.tmpl @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/fits/rootfs/etc/cont-init.d/03-fits-setup.sh b/fits/rootfs/etc/cont-init.d/03-fits-setup.sh deleted file mode 100755 index 71255b35..00000000 --- a/fits/rootfs/etc/cont-init.d/03-fits-setup.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /opt/tomcat/logs/fits-service.log -chown tomcat:tomcat /opt/tomcat/logs/fits-service.log diff --git a/fits/rootfs/opt/fits/xml/mediainfo/mediainfo_common_to_fits.xslt b/fits/rootfs/opt/fits/xml/mediainfo/mediainfo_common_to_fits.xslt new file mode 100644 index 00000000..afa6901f --- /dev/null +++ b/fits/rootfs/opt/fits/xml/mediainfo/mediainfo_common_to_fits.xslt @@ -0,0 +1,12 @@ + + + + + + + diff --git a/fits/rootfs/opt/fits/xml/mediainfo/mediainfo_video_to_fits.xslt b/fits/rootfs/opt/fits/xml/mediainfo/mediainfo_video_to_fits.xslt new file mode 100644 index 00000000..07b5b486 --- /dev/null +++ b/fits/rootfs/opt/fits/xml/mediainfo/mediainfo_video_to_fits.xslt @@ -0,0 +1,586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fits/rootfs/opt/tomcat/bin/setenv.sh b/fits/rootfs/opt/tomcat/bin/setenv.sh new file mode 100755 index 00000000..445653b6 --- /dev/null +++ b/fits/rootfs/opt/tomcat/bin/setenv.sh @@ -0,0 +1,6 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +export JAVA_OPTS="${TOMCAT_JAVA_OPTS}" +export CATALINA_OPTS="${TOMCAT_CATALINA_OPTS}" +export CATALINA_OPTS="${CATALINA_OPTS} -Djna.boot.library.path=/usr/lib" +export CATALINA_OPTS="${CATALINA_OPTS} -Djna.nosys=false" diff --git a/fits/rootfs/etc/confd/templates/catalina.properties.tmpl b/fits/rootfs/opt/tomcat/conf/catalina.properties similarity index 100% rename from fits/rootfs/etc/confd/templates/catalina.properties.tmpl rename to fits/rootfs/opt/tomcat/conf/catalina.properties diff --git a/fits/tests/ServiceStartsWithDefaults/build.gradle.kts b/fits/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..c9e182ea --- /dev/null +++ b/fits/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("fits", 0, 143) +} diff --git a/fits/tests/ServiceStartsWithDefaults/docker-compose.yml b/fits/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..66643629 --- /dev/null +++ b/fits/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: fits-servicestartswithdefaults +services: + fits: + <<: *common + image: ${FITS:-islandora/fits:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/fits/tests/ServiceStartsWithDefaults/test.sh b/fits/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..42b63140 --- /dev/null +++ b/fits/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,11 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Wait for service to start. +wait_20x http://localhost:8080/fits + +# Service must start for us to get to this point. +exit 0 diff --git a/gemini/.dockerignore b/gemini/.dockerignore deleted file mode 100644 index b43bf86b..00000000 --- a/gemini/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/gemini/Dockerfile b/gemini/Dockerfile deleted file mode 100644 index b2fb897a..00000000 --- a/gemini/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM local/crayfish:latest - -RUN --mount=type=cache,target=/root/.composer/cache \ - composer install -d /var/www/crayfish/Gemini && \ - ln -s /var/www/crayfish/Gemini/src /var/www/html && \ - cleanup.sh - -COPY /rootfs / - -WORKDIR /var/www/crayfish/Gemini/ diff --git a/gemini/README.md b/gemini/README.md deleted file mode 100644 index 9d8213c3..00000000 --- a/gemini/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Gemini - -Docker image for [Gemini]. - -## Dependencies - -Requires `islandora/crayfish` docker image to build. Please refer to the -[Crayfish Image README](../crayfish/README.md) for additional information including -additional settings, volumes, ports, etc. - -## Settings - -| Environment Variable | Etcd Key | Default | Description | -| :---------------------- | :----------------------- | :----------------- | :------------------------------------------------------------------------------------------------ | -| GEMINI_DB_DRIVER | /gemini/db/driver | pdo_mysql | The database driver to use | -| GEMINI_DB_HOST | /gemini/db/host | database | The database host | -| GEMINI_DB_NAME | /gemini/db/name | gemini | The database name | -| GEMINI_DB_PASSWORD | /gemini/db/password | password | The database user password | -| GEMINI_DB_PORT | /gemini/db/port | 3306 | The database port | -| GEMINI_DB_ROOT_PASSWORD | /gemini/db/root/password | password | The root user password (used to create the database / user) | -| GEMINI_DB_ROOT_USER | /gemini/db/root/user | root | The root user (used to create the database / user) | -| GEMINI_DB_USER | /gemini/db/user | gemini | The user to create / use when interacting with the database | -| GEMINI_FCREPO_URL | /gemini/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | -| GEMINI_LOG_LEVEL | /gemini/log/level | debug | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | - -[Gemini]: https://github.com/Islandora/Crayfish/tree/main/Gemini diff --git a/gemini/rootfs/etc/confd/conf.d/config.yaml.toml b/gemini/rootfs/etc/confd/conf.d/config.yaml.toml deleted file mode 100644 index d6d186a0..00000000 --- a/gemini/rootfs/etc/confd/conf.d/config.yaml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "config.yaml.tmpl" -dest = "/var/www/crayfish/Gemini/cfg/config.yaml" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/log/level", "/db", "/fcrepo" ] diff --git a/gemini/rootfs/etc/confd/conf.d/setup-environment.sh.toml b/gemini/rootfs/etc/confd/conf.d/setup-environment.sh.toml deleted file mode 100644 index d7fc515b..00000000 --- a/gemini/rootfs/etc/confd/conf.d/setup-environment.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setup-environment.sh.tmpl" -dest = "/var/run/islandora/setup-environment.sh" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/" ] diff --git a/gemini/rootfs/etc/confd/confd.toml b/gemini/rootfs/etc/confd/confd.toml deleted file mode 100644 index fa30a27d..00000000 --- a/gemini/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/gemini" diff --git a/gemini/rootfs/etc/confd/templates/config.yaml.tmpl b/gemini/rootfs/etc/confd/templates/config.yaml.tmpl deleted file mode 100644 index c04a6917..00000000 --- a/gemini/rootfs/etc/confd/templates/config.yaml.tmpl +++ /dev/null @@ -1,24 +0,0 @@ ---- -debug: True -fedora_resource: - base_url: {{ getv "/fcrepo/url" "http://fcrepo/fcrepo/rest" }} -log: - # Valid log levels are: - # debug, info, notice, warning, error, critical, alert, emergency, none - type: stream - file: "php://stderr" - level: {{ getv "/log/level" "debug" }} -syn: - # toggles JWT security for service - enable: true - # Path to the syn config file for authentication. - # example can be found here: - # https://github.com/Islandora/Syn/blob/main/conf/syn-settings.example.xml - config: /var/www/crayfish/syn-settings.xml -db.options: - driver: {{ getv "/db/driver" "pdo_mysql" }} - host: {{ getv "/db/host" "mariadb" }} - port: {{ getv "/db/port" "3306" }} - dbname: {{ getv "/db/name" "gemini" }} - user: {{ getv "/db/user" "gemini" }} - password: {{ getv "/db/password" "password" }} diff --git a/gemini/rootfs/etc/confd/templates/setup-environment.sh.tmpl b/gemini/rootfs/etc/confd/templates/setup-environment.sh.tmpl deleted file mode 100644 index dc85e1b8..00000000 --- a/gemini/rootfs/etc/confd/templates/setup-environment.sh.tmpl +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -with-contenv -foreground { - # We add / update the environment defined for the container, - # this allows our other initialization and service scripts - # use these settings; but does not change the existing - # environment as seen by linked containers. - # Variables can only be seen when using '#!/usr/bin/with-contenv' - s6-env -i - GEMINI_DB_DRIVER="{{ getv "/db/driver" "pdo_mysql" }}" - GEMINI_DB_HOST="{{ getv "/db/host" "mariadb" }}" - GEMINI_DB_NAME="{{ getv "/db/name" "gemini" }}" - GEMINI_DB_PASSWORD="{{ getv "/db/password" "password" }}" - GEMINI_DB_PORT="{{ getv "/db/port" "3306" }}" - GEMINI_DB_ROOT_PASSWORD="{{ getv "/db/root/password" "password" }}" - GEMINI_DB_ROOT_USER="{{ getv "/db/root/user" "root" }}" - GEMINI_DB_USER="{{ getv "/db/user" "gemini" }}" - s6-dumpenv -- /var/run/s6/container_environment -} diff --git a/gemini/rootfs/etc/cont-init.d/03-gemini-setup.sh b/gemini/rootfs/etc/cont-init.d/03-gemini-setup.sh deleted file mode 100755 index 60d5897d..00000000 --- a/gemini/rootfs/etc/cont-init.d/03-gemini-setup.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -function execute_sql_file { - execute-sql-file.sh \ - --driver "${GEMINI_DB_DRIVER}" \ - --host "${GEMINI_DB_HOST}" \ - --port "${GEMINI_DB_PORT}" \ - --user "${GEMINI_DB_ROOT_USER}" \ - --password "${GEMINI_DB_ROOT_PASSWORD}" \ - "${@}" -} - -function mysql_query { - cat <<- EOF --- Create gemini database in mariadb or mysql. -CREATE DATABASE IF NOT EXISTS ${GEMINI_DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci; - -CREATE TABLE IF NOT EXISTS ${GEMINI_DB_NAME}.Gemini ( - id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, - drupal VARCHAR(2048) NOT NULL UNIQUE, - fedora VARCHAR(2048) NOT NULL UNIQUE -) ENGINE=InnoDB; - --- Create gemini user and grant rights. -CREATE USER IF NOT EXISTS '${GEMINI_DB_USER}'@'%' IDENTIFIED BY '${GEMINI_DB_PASSWORD}'; -GRANT ALL PRIVILEGES ON ${GEMINI_DB_NAME}.* to '${GEMINI_DB_USER}'@'%'; -FLUSH PRIVILEGES; - --- Update gemini user password if changed. -SET PASSWORD FOR ${GEMINI_DB_USER}@'%' = PASSWORD('${GEMINI_DB_PASSWORD}') -EOF -} - -function mysql_create_database { - execute_sql_file <(mysql_query) -} - -function postgres_query { - cat <<- EOF -BEGIN; - -DO \$\$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${GEMINI_DB_USER}') THEN - CREATE ROLE ${GEMINI_DB_USER}; - END IF; -END -\$\$; - -ALTER ROLE ${GEMINI_DB_USER} WITH LOGIN; -ALTER USER ${GEMINI_DB_USER} PASSWORD '${GEMINI_DB_PASSWORD}'; - -ALTER DATABASE ${GEMINI_DB_NAME} OWNER TO ${GEMINI_DB_USER}; -GRANT ALL PRIVILEGES ON DATABASE ${GEMINI_DB_NAME} TO ${GEMINI_DB_USER}; - -CREATE TABLE IF NOT EXISTS -Gemini ( - id SERIAL PRIMARY KEY, - drupal VARCHAR(2048) NOT NULL UNIQUE, - fedora VARCHAR(2048) NOT NULL UNIQUE -); -ALTER TABLE Gemini OWNER TO ${GEMINI_DB_USER}; - -COMMIT; -EOF -} - -function postgresql_database_exists { - execute_sql_file --database "${GEMINI_DB_NAME}" <(echo 'select 1') -} - -function postgresql_create_database { - # Postgres does not support CREATE DATABASE IF NOT EXISTS so split our logic across multiple queries. - if ! postgresql_database_exists; then - execute_sql_file <(echo "CREATE DATABASE ${GEMINI_DB_NAME}") - fi - execute_sql_file --database "${GEMINI_DB_NAME}" <(postgres_query) -} - -function create_database { - case "${GEMINI_DB_DRIVER}" in - mysql|pdo_mysql) - mysql_create_database - ;; - pgsql|postgresql|pdo_pgsql) - postgresql_create_database - ;; - *) - echo "Only MySQL/PostgresSQL databases are supported for now." >&2 - exit 1 - esac -} - -function run_migrations { - php bin/console --no-interaction migrations:migrate -} - -function main { - create_database - run_migrations -} -main diff --git a/gradle.properties b/gradle.properties index f72501a1..bc8dd38e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,63 @@ +# ============================================================================= +# For all of the properties listed in this file the default is given. +# You can override them on the command line using `-Pproperty.name=value` +# +# Or alternatively you can customize the values in your ~/.gradle/gradle.properties +# file. + +# ============================================================================= +# Gradle properties. +org.gradle.caching=true org.gradle.parallel=true -# Will be used as a tag to denote the images release. -version=0.0.1 -# The project can be build with/without Buildkit for those on older versions of Docker earlier than '18.09' or who -# cannot use the 'overlay2' filesystem with Docker due to using an earlier kernel version than 4.0. -useBuildKit=true -# The repository path to use for all images when building, defaults to local. -# Override to push to your choosen remote repository. -repository=local -# The remote repository to use as a cache for images when building. -# Override to pull from your private remote repository. -cacheRepository=islandora -# Location and credentials for pushing images. -registryUrl=https://index.docker.io/v1 -registryUsername= -registryPassword= -# Tags to add to all images, can be overridden on a project by project basis. -tags= -# By default all images have a 'prod' environment, even if they ignore it in the build, although some also have 'dev'. -environments=prod + +# ============================================================================= +# Grype properties. +# See https://github.com/anchore/grype for in-depth explaination. + +# Used to ignore specific vunerabilities. +isle.grype.config=grype.yaml + +# Only included vunerabilities that have known fixes in the report. +isle.grype.only-fixed=false + +# Upon scanning, if a severity is found at or above the given severity then the +# command will fail. The default is unset which will skip this validation. +# +# Options: +# - negligible +# - low +# - medium +# - high +# - critical +isle.grype.fail-on-severity= + +# The format of reports generated by grype, which can be found in: +# `build/{image-name}/{image-name}-grype.{ext}`: +# +# Options: +# - table: A columnar summary (default). +# - cyclonedx: An XML report conforming to the CycloneDX 1.2 specification. +# - json: Use this to get as much information out of Grype as possible! +# - template: Lets the user specify the output format. See "Using templates" +# . +isle.grype.format=table + +# ============================================================================= +# DockerHub properties. +# +# To modifiy resources in DockerHub we require the user to authenticate. + +# Required for deleting inactive tags. +isle.dockerhub.user=islandoracommunity +isle.dockerhub.personal.access.token= + +# The repository to remove tags from. +isle.dockerhub.repository=islandora + +# Only remove tags that are marked as "Inactive" i.e have not been +# pulled in over 6 months. +isle.dockerhub.remove.inactive.only=true + +# Additional tags aside from branches and tags in the repository to prevent the deletion of. +# List of values separated by comma. +isle.dockerhub.protected.tags= diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4b44297..070cb702 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/grype.yaml b/grype.yaml new file mode 100644 index 00000000..25272c67 --- /dev/null +++ b/grype.yaml @@ -0,0 +1,16 @@ +ignore: + # maven-resolver & maven-shared-utils +- vulnerability: CVE-2021-26291 + fix-state: unknown +- vulnerability: CVE-2021-26291 + fix-state: unknown +- vulnerability: CVE-2021-26291 + fix-state: unknown +- vulnerability: CVE-2021-26291 + fix-state: unknown +- vulnerability: CVE-2021-26291 + fix-state: unknown +- vulnerability: CVE-2021-26291 + fix-state: unknown +- vulnerability: CVE-2021-26291 + fix-state: unknown diff --git a/handle/Dockerfile b/handle/Dockerfile new file mode 100644 index 00000000..be22d050 --- /dev/null +++ b/handle/Dockerfile @@ -0,0 +1,76 @@ +# syntax=docker/dockerfile:1.5.1 +FROM java + +ARG TARGETARCH +ARG HANDLE_VERSION="9.3.0" +ARG HANDLE_FILE="handle-${HANDLE_VERSION}-distribution.tar.gz" +ARG HANDLE_URL="http://handle.net/hnr-source/${HANDLE_FILE}" +ARG HANDLE_FILE_SHA256="7bbf155842b098df9eb3e6e24778be23bc74365cf0f2b1b2acb0ae111a54bdaf" + +ARG MYSQL_DRIVER_VERSION="8.0.31" +ARG MYSQL_DRIVER_FILE="mysql-connector-j-${MYSQL_DRIVER_VERSION}.tar.gz" +ARG MYSQL_DRIVER_URL="https://dev.mysql.com/get/Downloads/Connector-J/${MYSQL_DRIVER_FILE}" +ARG MYSQL_DRIVER_FILE_SHA256="03e3908f070bfe216f0458c8c4de0b3e47ed3182b37d39bcd2082dbd767d5f91" + +ARG POSTGRES_DRIVER_VERSION="42.5.1" +ARG POSTGRES_DRIVER_FILE="postgresql-${POSTGRES_DRIVER_VERSION}.jar" +ARG POSTGRES_DRIVER_URL="https://jdbc.postgresql.org/download/${POSTGRES_DRIVER_FILE}" +ARG POSTGRES_DRIVER_FILE_SHA256="89e8bffa8b37b9487946012c690cf04f3103953051c1c193d88ee36b68d365ae" + +EXPOSE 8000/tcp 2641/tcp 2641/udp + +WORKDIR /var/handle + +# Download Handle & the java mysql driver +# And install them into /opt/handle directory +# +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=handle-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${HANDLE_URL}" \ + --sha256 "${HANDLE_FILE_SHA256}" \ + --strip \ + --dest "/opt/handle" \ + doc \ + handle-9.3.0-src.zip \ + jeUpgradeTool \ + && \ + download.sh \ + --url "${MYSQL_DRIVER_URL}" \ + --sha256 "${MYSQL_DRIVER_FILE_SHA256}" \ + --strip \ + --dest "/tmp/mysql-connector-java" \ + && \ + mv "/tmp/mysql-connector-java/${MYSQL_DRIVER_FILE%%.tar.gz}.jar" /opt/handle/lib && \ + download.sh \ + --url "${POSTGRES_DRIVER_URL}" \ + --sha256 "${POSTGRES_DRIVER_FILE_SHA256}" \ + --dest "/opt/handle/lib" \ + && \ + cleanup.sh + +RUN create-service-user.sh --name handle /opt/keys/handle /var/handle /var/handle/logs && \ + cleanup.sh + +# The following are defined in /etc/defaults: +# - HANDLE_ADMIN_PRIVATE_KEY_PEM +# - HANDLE_ADMIN_PUBLIC_KEY_PEM +# - HANDLE_PRIVATE_KEY_PEM +# - HANDLE_PUBLIC_KEY_PEM +# As Docker does not support setting multiline environment variables via ENV. +ENV \ + HANDLE_ADMIN_FULL_ACCESS=yes \ + HANDLE_ALLOW_NA_ADMINS=yes \ + HANDLE_CASE_SENSITIVE=no \ + HANDLE_DB_NAME=handle \ + HANDLE_DB_PASSWORD=password \ + HANDLE_DB_READONLY=no \ + HANDLE_DB_USER=handle \ + HANDLE_MAX_AUTH_TIME=60000 \ + HANDLE_MAX_SESSION_TIME=86400000 \ + HANDLE_PREFIX=200 \ + HANDLE_SERVER_ID=1 \ + HANDLE_PERSISTENCE_TYPE=bdbje \ + HANDLE_TEMPLATE_NS_OVERRIDE=no + +COPY --link rootfs / diff --git a/handle/README.md b/handle/README.md new file mode 100644 index 00000000..005bf7d6 --- /dev/null +++ b/handle/README.md @@ -0,0 +1,81 @@ +# Handle + +Docker image for [Handle] version 9.3.0. + +Please refer to the [Handle Documentation] for more in-depth information. + +As a quick example this will bring up an instance of [Handle], and allow you +to view on . + +```bash +docker run --rm -ti -p 8000:8000 islandora/handle +``` + +## Dependencies + +Requires `islandora/java` docker image to build. Please refer to the +[Java Image README](https://github.com/Islandora-Devops/isle-buildkit/blob/main/java/README.md) for additional information. + +## Ports + +| Port | Description | +| :------------- | :------------------------------------------------------------------------------------- | +| 8000 (tcp) | Port 8000 offers an HTTP and HTTPS interface. | +| 2641 (udp/tcp) | Port 2641 (UDP and TCP) is the IANA-assigned port number for the Handle wire protocol. | + +## Settings + +### Confd Settings + +| Environment Variable | Default | Description | +| :--------------------------- | :--------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | +| HANDLE_ADMIN_FULL_ACCESS | yes | "yes" or "no". If set to "no" the "server_admins" will have default permissions at the prefix level | +| HANDLE_ADMIN_PRIVATE_KEY_PEM | See rootfs/etc/defaults/HANDLE_ADMIN_PRIVATE_KEY_PEM | Please read the handle documentation for how this is use | +| HANDLE_ADMIN_PUBLIC_KEY_PEM | See rootfs/etc/defaults/HANDLE_ADMIN_PUBLIC_KEY_PEM | Please read the handle documentation for how this is use | +| HANDLE_ALLOW_NA_ADMINS | yes | "yes" or "no". Allow admins from GHR? | +| HANDLE_CASE_SENSITIVE | no | "yes" or "no". Whether or not handles are case sensitive | +| HANDLE_DB_NAME | handle | The name of the handle database | +| HANDLE_DB_PASSWORD | password | The database users password | +| HANDLE_DB_READONLY | no | A boolean setting (can be "yes" or "no") prevent / allow database modification | +| HANDLE_DB_USER | handle | The database user | +| HANDLE_MAX_AUTH_TIME | 60000 | The number of seconds to wait for a client to respond to an authentication challenge | +| HANDLE_MAX_SESSION_TIME | 86400000 | Time in milliseconds that an authenticated client session can persist | +| HANDLE_PREFIX | 200 | Please read the handle documentation for how this is use | +| HANDLE_PRIVATE_KEY_PEM | See rootfs/etc/defaults/HANDLE_PRIVATE_KEY_PEM | Please read the handle documentation for how this is use | +| HANDLE_PUBLIC_KEY_PEM | See rootfs/etc/defaults/HANDLE_PUBLIC_KEY_PEM | Please read the handle documentation for how this is use | +| HANDLE_SERVER_ID | 1 | Used to distinguish from other servers within the same site | +| HANDLE_PERSISTENCE_TYPE | bdbje | Can be 'sql', if 'bdbje' make sure to create a volume at `/var/handle/bdbje` to persist changes | +| HANDLE_TEMPLATE_NS_OVERRIDE | no | Prefer server_config settings. | + +**Note:** For PEM files the private key must conform to +[PKCS#8](https://en.wikipedia.org/wiki/PKCS_8) and not +[PKCS#1](https://en.wikipedia.org/wiki/PKCS_1) as the tools which do key +conversion into the handle format do not support `PKCS#1`. + +i.e PEM files which begin with `-----BEGIN RSA PRIVATE KEY-----` are not +supported only keys which start with `-----BEGIN PRIVATE KEY-----` or +`-----BEGIN ENCRYPTED PRIVATE KEY-----` are supported. Note if you use encrypted +keys you will need to handle the decryption of them as it is not handled by this +image at this time. + +### Database Settings + +[Handle] can optionally make use of different database backends for storage. Please see +the documentation in the [base image] for more information about the default +database connection configuration. + +The following settings are only used if `HANDLE_PERSISTENCE_TYPE` is set to +`mysql` or `postgresql`. + +| Environment Variable | Default | Description | +| :------------------- | :------- | :------------------------------------------------------- | +| HANDLE_DB_NAME | handle | The name of the database | +| HANDLE_DB_USER | handle | The user to connect to the database | +| HANDLE_DB_PASSWORD | password | The password of the user used to connect to the database | + +Additionally the `DB_DRIVER` variable is derived from the +`HANDLE_PERSISTENCE_TYPE` so users do not need to specify it separately. + +[base image]: ../base/README.md +[Handle Documentation]: https://www.handle.net/tech_manual/HN_Tech_Manual_9.pdf +[Handle]: https://handle.net/ diff --git a/handle/rootfs/etc/confd/conf.d/admin.private.key.toml b/handle/rootfs/etc/confd/conf.d/admin.private.key.toml new file mode 100644 index 00000000..a2d1f150 --- /dev/null +++ b/handle/rootfs/etc/confd/conf.d/admin.private.key.toml @@ -0,0 +1,7 @@ +[template] +src = "admin.private.key.tmpl" +dest = "/opt/keys/handle/admin.private.key" +uid = 100 +gid = 1000 +mode = "0600" +keys = [ "/" ] diff --git a/handle/rootfs/etc/confd/conf.d/admin.public.key.toml b/handle/rootfs/etc/confd/conf.d/admin.public.key.toml new file mode 100644 index 00000000..e37b95a1 --- /dev/null +++ b/handle/rootfs/etc/confd/conf.d/admin.public.key.toml @@ -0,0 +1,7 @@ +[template] +src = "admin.public.key.tmpl" +dest = "/opt/keys/handle/admin.public.key" +uid = 100 +gid = 1000 +mode = "0600" +keys = [ "/" ] diff --git a/handle/rootfs/etc/confd/conf.d/config.dct.toml b/handle/rootfs/etc/confd/conf.d/config.dct.toml new file mode 100644 index 00000000..0094e951 --- /dev/null +++ b/handle/rootfs/etc/confd/conf.d/config.dct.toml @@ -0,0 +1,7 @@ +[template] +src = "config.dct.tmpl" +dest = "/var/handle/config.dct" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/" ] diff --git a/handle/rootfs/etc/confd/conf.d/private.key.toml b/handle/rootfs/etc/confd/conf.d/private.key.toml new file mode 100644 index 00000000..47db6f53 --- /dev/null +++ b/handle/rootfs/etc/confd/conf.d/private.key.toml @@ -0,0 +1,7 @@ +[template] +src = "private.key.tmpl" +dest = "/opt/keys/handle/private.key" +uid = 100 +gid = 1000 +mode = "0600" +keys = [ "/" ] diff --git a/fcrepo/rootfs/etc/confd/conf.d/public.key.toml b/handle/rootfs/etc/confd/conf.d/public.key.toml similarity index 57% rename from fcrepo/rootfs/etc/confd/conf.d/public.key.toml rename to handle/rootfs/etc/confd/conf.d/public.key.toml index ec9810ec..a52930a6 100644 --- a/fcrepo/rootfs/etc/confd/conf.d/public.key.toml +++ b/handle/rootfs/etc/confd/conf.d/public.key.toml @@ -1,7 +1,7 @@ [template] src = "public.key.tmpl" -dest = "/opt/keys/jwt/public.key" +dest = "/opt/keys/handle/public.key" uid = 100 gid = 1000 mode = "0600" -keys = [ "/jwt" ] +keys = [ "/" ] diff --git a/handle/rootfs/etc/confd/conf.d/siteinfo.json.toml b/handle/rootfs/etc/confd/conf.d/siteinfo.json.toml new file mode 100644 index 00000000..a4164bc7 --- /dev/null +++ b/handle/rootfs/etc/confd/conf.d/siteinfo.json.toml @@ -0,0 +1,7 @@ +[template] +src = "siteinfo.json.tmpl" +dest = "/var/handle/siteinfo.json" +uid = 100 +gid = 1000 +mode = "0644" +keys = [ "/" ] diff --git a/handle/rootfs/etc/confd/templates/admin.private.key.tmpl b/handle/rootfs/etc/confd/templates/admin.private.key.tmpl new file mode 100644 index 00000000..18c64692 --- /dev/null +++ b/handle/rootfs/etc/confd/templates/admin.private.key.tmpl @@ -0,0 +1 @@ +{{ getenv "HANDLE_ADMIN_PRIVATE_KEY_PEM" }} \ No newline at end of file diff --git a/handle/rootfs/etc/confd/templates/admin.public.key.tmpl b/handle/rootfs/etc/confd/templates/admin.public.key.tmpl new file mode 100644 index 00000000..4086ae0a --- /dev/null +++ b/handle/rootfs/etc/confd/templates/admin.public.key.tmpl @@ -0,0 +1 @@ +{{ getenv "HANDLE_ADMIN_PUBLIC_KEY_PEM" }} \ No newline at end of file diff --git a/handle/rootfs/etc/confd/templates/config.dct.tmpl b/handle/rootfs/etc/confd/templates/config.dct.tmpl new file mode 100644 index 00000000..c6ecdd7d --- /dev/null +++ b/handle/rootfs/etc/confd/templates/config.dct.tmpl @@ -0,0 +1,78 @@ +{ + "hdl_http_config" = { + "num_threads" = "15" + "bind_port" = "8000" + "log_accesses" = "yes" + } + + "server_type" = "server" + "hdl_udp_config" = { + "num_threads" = "15" + "bind_port" = "2641" + "log_accesses" = "yes" + } + + "hdl_tcp_config" = { + "num_threads" = "15" + "bind_port" = "2641" + "log_accesses" = "yes" + } + + "log_save_config" = { + "log_save_directory" = "logs" + "log_save_interval" = "Never" + } + + "no_udp_resolution" = "yes" + "interfaces" = ( + "hdl_udp" + "hdl_tcp" + "hdl_http" + ) + + "server_config" = { + "server_admins" = ( + "300:0.NA/{{ getenv "HANDLE_PREFIX" }}" + ) + + "replication_admins" = ( + "300:0.NA/{{ getenv "HANDLE_PREFIX" }}" + ) + + "max_session_time" = "{{ getenv "HANDLE_MAX_SESSION_TIME" }}" + "this_server_id" = "{{ getenv "HANDLE_SERVER_ID" }}" + "max_auth_time" = "{{ getenv "HANDLE_MAX_AUTH_TIME" }}" + "server_admin_full_access" = "{{ getenv "HANDLE_ADMIN_FULL_ACCESS" }}" + "allow_na_admins" = "{{ getenv "HANDLE_ALLOW_NA_ADMINS" }}" + "template_ns_override" = "{{ getenv "HANDLE_TEMPLATE_NS_OVERRIDE" }}" + "trace_resolution" = "no" + "case_sensitive" = "{{ getenv "HANDLE_CASE_SENSITIVE" }}" + "allow_recursion" = "no" + "allow_list_hdls" = "yes" + + "auto_homed_prefixes" = ( + "0.NA/{{ getenv "HANDLE_PREFIX" }}" + ) + + {{ if eq (getenv "HANDLE_PERSISTENCE_TYPE" ) "bdbje" }} + storage_type = bdbje + {{ else }} + storage_type = sql + {{ end }} + + sql_settings = { + {{ if eq (getenv "DB_DRIVER" ) "mysql" }} + sql_url = "jdbc:mysql://{{ getenv "DB_MYSQL_HOST" }}:{{ getenv "DB_MYSQL_PORT" }}/{{ getenv "HANDLE_DB_NAME" }}" + sql_driver = "com.mysql.jdbc.Driver" + {{ end }} + {{ if eq (getenv "DB_DRIVER" ) "postgresql" }} + sql_url = "jdbc:postgresql://{{ getenv "DB_POSTGRESQL_HOST" }}:{{ getenv "DB_POSTGRESQL_PORT" }}/{{ getenv "HANDLE_DB_NAME" }}" + sql_driver = "org.postgresql.Driver" + {{ end }} + sql_login = "{{ getenv "HANDLE_DB_USER" }}" + sql_passwd = "{{ getenv "HANDLE_DB_PASSWORD" }}" + sql_read_only = "{{ getenv "HANDLE_DB_READONLY" }}" + } + } + +} diff --git a/handle/rootfs/etc/confd/templates/private.key.tmpl b/handle/rootfs/etc/confd/templates/private.key.tmpl new file mode 100644 index 00000000..96b347a4 --- /dev/null +++ b/handle/rootfs/etc/confd/templates/private.key.tmpl @@ -0,0 +1 @@ +{{ getenv "HANDLE_PRIVATE_KEY_PEM" }} \ No newline at end of file diff --git a/handle/rootfs/etc/confd/templates/public.key.tmpl b/handle/rootfs/etc/confd/templates/public.key.tmpl new file mode 100644 index 00000000..2580a635 --- /dev/null +++ b/handle/rootfs/etc/confd/templates/public.key.tmpl @@ -0,0 +1 @@ +{{ getenv "HANDLE_PUBLIC_KEY_PEM" }} \ No newline at end of file diff --git a/handle/rootfs/etc/confd/templates/siteinfo.json.tmpl b/handle/rootfs/etc/confd/templates/siteinfo.json.tmpl new file mode 100644 index 00000000..1f2e38b4 --- /dev/null +++ b/handle/rootfs/etc/confd/templates/siteinfo.json.tmpl @@ -0,0 +1,43 @@ +{ + "version": 1, + "protocolVersion": "2.10", + "serialNumber": 1, + "primarySite": true, + "multiPrimary": false, + "attributes": [ + { + "name": "desc", + "value": "LHS 1" + } + ], + "servers": [ + { + "serverId": 1, + "address": "0.0.0.0", + "publicKey": { + "format": "base64", + "value": "{{ getenv "HANDLE_PUBLICKEY_BASE64" }}" + }, + "interfaces": [ + { + "query": true, + "admin": false, + "protocol": "UDP", + "port": 2641 + }, + { + "query": true, + "admin": true, + "protocol": "TCP", + "port": 2641 + }, + { + "query": true, + "admin": true, + "protocol": "HTTP", + "port": 8000 + } + ] + } + ] +} diff --git a/handle/rootfs/etc/defaults/HANDLE_ADMIN_PRIVATE_KEY_PEM b/handle/rootfs/etc/defaults/HANDLE_ADMIN_PRIVATE_KEY_PEM new file mode 100644 index 00000000..2487161f --- /dev/null +++ b/handle/rootfs/etc/defaults/HANDLE_ADMIN_PRIVATE_KEY_PEM @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDq4reejPLBVpEI +AHcUd1Fk0e6dJm839zfVCKZkCpAwbGPsmsaHUsXwlFf5cBD4Ilw8P2vrFeMpJLUa +prY6zbABGv/1psjAblB42ysnwYy3dn9YgKc15oUCRRW+LApZwDrWIUla9MMC4jSE +JrECtEqyTQF8VIyH7i7ckB0P21TFTHoABRdQJ20/KW5oF3nfC4HSv3FGU+cPDoj1 +Ad8orzReuuy7U9gBOCuzLr2y3MKWfcqU7k7Fzo7w6Mx2MLYPZzceaw7gIo++9pW5 +qjD9r09rdI2N7hRc37/XFR9CyTFp8/wIpVKvzHG3DNK6t6KyRvn/3yagCK62lS2n +XnLICbSvAgMBAAECggEADQ9mHk7AALgLgGJmPKEVyYFSvzIv5PC+Df5ZIh7kPY0J +UVKZz1Ru5R2adqggiWt/rWnpWjzxUIxV9ZFneIWPT8BskwAfEXQQzWeCUseUR28z +TXx5z6lto96rgtN4D918aAOZzJDndvWU7fQoy3my3Y8ikgMxfS1lNaZdt0/+uqmW +qJCZ3AfSC/w/MQbpjZlUsF/m+Ifki9VGmDv2cOot97ZbbKUWJv4K2V5frbrFNTMZ +wnRqpNE/VSRjgmPk8jb/JWq21g+S8m3Flyjn/XgAQxy70UwGEAMJKT/TLVOQoIay +Lr9U13vwAH9GtkrfYd8cLBPDGhcdChpUqrqE1B+iQQKBgQD6R4Z1UmtcwPKVqYBF +B0N7+c2CWOplmF+QopgIZ5yQ2qOneKp+aV3+2oI9XEA7aYijx0018zYwy/qWgQ/H +0XZER7yT01tYWtRnjzp8wc947tace33YnJQO18klJnUZ0KSLU+2GamY/xZ2gXpWk +u+vkCDC5goDOQw22H45X92+CqQKBgQDwQR4TeYq948dX89Wwu3pNqolxkQoq7ov0 +SB4PLO/fPPj7bMbwxVy3JQXJ9KXgQgL+gnJfRPlOPWXgDeY/Bk4l9A6Reev1No81 +9/XOM3HXZGFRmMW0lTlX5afWV23Oz5fAIVzHk78HwtZiBXhs6LE2Vzq1NGr+bxPG ++117289rlwKBgQDc452fFEPfVAeF4VhtE/ESjTE81p7hVa8aZvZJjLCZA+6mUxAe +i35C/LUv1Kh4BzdqXO8fK21recvLY1L7Jzn7H1knGsYm39tRHw8epqsm75yH9VHn +iKH/y6EiYaO+Se+/bC5ZkLR3mkD5FiF6h8S0uCnQwIZQBMwoLgeiSaaoKQKBgESO +gFOUUiffcInDdY3J4Zt592Blv94CVgNt9M3lx8kO8Almv9oCp3NHaEB5xD+a9pnD +hXl0CCPwVzq5HKONXA1ueB3BCbjeSb1ftU+S1IBfD3omOvxNvKA9U0hRiG8EQ8w6 +eOwmV9OSIHS2FOgW+kKEX6dHfuR9s8oK/mESlzyfAoGBAJ0rIuLngWbbieoS5lhs +DHEYj1NVPvAmOgoafrglate1fvFGW2YkLe2cvA0KiNxvIbiRUH4zLOvY4S0WQ7jm +PzcaOtng76MK5KP4CYLERxzvE0D1yC726waxBd0aYggHQJuTng7Ic12xmBkJeL0Z +NEX269hkov2qS1L5RkwnVfP+ +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/crayfish/rootfs/etc/confd/templates/public.key.tmpl b/handle/rootfs/etc/defaults/HANDLE_ADMIN_PUBLIC_KEY_PEM similarity index 82% rename from crayfish/rootfs/etc/confd/templates/public.key.tmpl rename to handle/rootfs/etc/defaults/HANDLE_ADMIN_PUBLIC_KEY_PEM index e0e8e191..fcf18204 100644 --- a/crayfish/rootfs/etc/confd/templates/public.key.tmpl +++ b/handle/rootfs/etc/defaults/HANDLE_ADMIN_PUBLIC_KEY_PEM @@ -1,4 +1,4 @@ -{{ getv "/jwt/public/key" `-----BEGIN PUBLIC KEY----- +-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6uK3nozywVaRCAB3FHdR ZNHunSZvN/c31QimZAqQMGxj7JrGh1LF8JRX+XAQ+CJcPD9r6xXjKSS1Gqa2Os2w ARr/9abIwG5QeNsrJ8GMt3Z/WICnNeaFAkUVviwKWcA61iFJWvTDAuI0hCaxArRK @@ -6,4 +6,4 @@ sk0BfFSMh+4u3JAdD9tUxUx6AAUXUCdtPyluaBd53wuB0r9xRlPnDw6I9QHfKK80 Xrrsu1PYATgrsy69stzCln3KlO5Oxc6O8OjMdjC2D2c3HmsO4CKPvvaVuaow/a9P a3SNje4UXN+/1xUfQskxafP8CKVSr8xxtwzSureiskb5/98moAiutpUtp15yyAm0 rwIDAQAB ------END PUBLIC KEY-----` }} +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/handle/rootfs/etc/defaults/HANDLE_PRIVATE_KEY_PEM b/handle/rootfs/etc/defaults/HANDLE_PRIVATE_KEY_PEM new file mode 100644 index 00000000..2487161f --- /dev/null +++ b/handle/rootfs/etc/defaults/HANDLE_PRIVATE_KEY_PEM @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDq4reejPLBVpEI +AHcUd1Fk0e6dJm839zfVCKZkCpAwbGPsmsaHUsXwlFf5cBD4Ilw8P2vrFeMpJLUa +prY6zbABGv/1psjAblB42ysnwYy3dn9YgKc15oUCRRW+LApZwDrWIUla9MMC4jSE +JrECtEqyTQF8VIyH7i7ckB0P21TFTHoABRdQJ20/KW5oF3nfC4HSv3FGU+cPDoj1 +Ad8orzReuuy7U9gBOCuzLr2y3MKWfcqU7k7Fzo7w6Mx2MLYPZzceaw7gIo++9pW5 +qjD9r09rdI2N7hRc37/XFR9CyTFp8/wIpVKvzHG3DNK6t6KyRvn/3yagCK62lS2n +XnLICbSvAgMBAAECggEADQ9mHk7AALgLgGJmPKEVyYFSvzIv5PC+Df5ZIh7kPY0J +UVKZz1Ru5R2adqggiWt/rWnpWjzxUIxV9ZFneIWPT8BskwAfEXQQzWeCUseUR28z +TXx5z6lto96rgtN4D918aAOZzJDndvWU7fQoy3my3Y8ikgMxfS1lNaZdt0/+uqmW +qJCZ3AfSC/w/MQbpjZlUsF/m+Ifki9VGmDv2cOot97ZbbKUWJv4K2V5frbrFNTMZ +wnRqpNE/VSRjgmPk8jb/JWq21g+S8m3Flyjn/XgAQxy70UwGEAMJKT/TLVOQoIay +Lr9U13vwAH9GtkrfYd8cLBPDGhcdChpUqrqE1B+iQQKBgQD6R4Z1UmtcwPKVqYBF +B0N7+c2CWOplmF+QopgIZ5yQ2qOneKp+aV3+2oI9XEA7aYijx0018zYwy/qWgQ/H +0XZER7yT01tYWtRnjzp8wc947tace33YnJQO18klJnUZ0KSLU+2GamY/xZ2gXpWk +u+vkCDC5goDOQw22H45X92+CqQKBgQDwQR4TeYq948dX89Wwu3pNqolxkQoq7ov0 +SB4PLO/fPPj7bMbwxVy3JQXJ9KXgQgL+gnJfRPlOPWXgDeY/Bk4l9A6Reev1No81 +9/XOM3HXZGFRmMW0lTlX5afWV23Oz5fAIVzHk78HwtZiBXhs6LE2Vzq1NGr+bxPG ++117289rlwKBgQDc452fFEPfVAeF4VhtE/ESjTE81p7hVa8aZvZJjLCZA+6mUxAe +i35C/LUv1Kh4BzdqXO8fK21recvLY1L7Jzn7H1knGsYm39tRHw8epqsm75yH9VHn +iKH/y6EiYaO+Se+/bC5ZkLR3mkD5FiF6h8S0uCnQwIZQBMwoLgeiSaaoKQKBgESO +gFOUUiffcInDdY3J4Zt592Blv94CVgNt9M3lx8kO8Almv9oCp3NHaEB5xD+a9pnD +hXl0CCPwVzq5HKONXA1ueB3BCbjeSb1ftU+S1IBfD3omOvxNvKA9U0hRiG8EQ8w6 +eOwmV9OSIHS2FOgW+kKEX6dHfuR9s8oK/mESlzyfAoGBAJ0rIuLngWbbieoS5lhs +DHEYj1NVPvAmOgoafrglate1fvFGW2YkLe2cvA0KiNxvIbiRUH4zLOvY4S0WQ7jm +PzcaOtng76MK5KP4CYLERxzvE0D1yC726waxBd0aYggHQJuTng7Ic12xmBkJeL0Z +NEX269hkov2qS1L5RkwnVfP+ +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/fcrepo/rootfs/etc/confd/templates/public.key.tmpl b/handle/rootfs/etc/defaults/HANDLE_PUBLIC_KEY_PEM similarity index 82% rename from fcrepo/rootfs/etc/confd/templates/public.key.tmpl rename to handle/rootfs/etc/defaults/HANDLE_PUBLIC_KEY_PEM index e0e8e191..fcf18204 100644 --- a/fcrepo/rootfs/etc/confd/templates/public.key.tmpl +++ b/handle/rootfs/etc/defaults/HANDLE_PUBLIC_KEY_PEM @@ -1,4 +1,4 @@ -{{ getv "/jwt/public/key" `-----BEGIN PUBLIC KEY----- +-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6uK3nozywVaRCAB3FHdR ZNHunSZvN/c31QimZAqQMGxj7JrGh1LF8JRX+XAQ+CJcPD9r6xXjKSS1Gqa2Os2w ARr/9abIwG5QeNsrJ8GMt3Z/WICnNeaFAkUVviwKWcA61iFJWvTDAuI0hCaxArRK @@ -6,4 +6,4 @@ sk0BfFSMh+4u3JAdD9tUxUx6AAUXUCdtPyluaBd53wuB0r9xRlPnDw6I9QHfKK80 Xrrsu1PYATgrsy69stzCln3KlO5Oxc6O8OjMdjC2D2c3HmsO4CKPvvaVuaow/a9P a3SNje4UXN+/1xUfQskxafP8CKVSr8xxtwzSureiskb5/98moAiutpUtp15yyAm0 rwIDAQAB ------END PUBLIC KEY-----` }} +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-db-driver b/handle/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-db-driver new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/dependencies.d/process-keys b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/dependencies.d/process-keys new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/dependencies.d/ready b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/type b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/up b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/up new file mode 100755 index 00000000..e6d901f0 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle-setup/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/handle-setup.sh diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/dependencies.d/handle-setup b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/dependencies.d/handle-setup new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/finish b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/run b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/run new file mode 100755 index 00000000..a3114f57 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/run @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +exec s6-setuidgid handle /opt/handle/bin/hdl-server /var/handle diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/type b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/handle/type @@ -0,0 +1 @@ +longrun diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/dependencies.d/confd-oneshot b/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/dependencies.d/confd-oneshot new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/type b/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/type @@ -0,0 +1 @@ +oneshot diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/up b/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/up new file mode 100755 index 00000000..d9eaa1f1 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/process-keys/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/process-keys.sh diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/dependencies.d/container-environment b/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/type b/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/type @@ -0,0 +1 @@ +oneshot diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/up b/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/up new file mode 100755 index 00000000..b84d3add --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/s6-rc.d/set-db-driver/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/set-db-driver.sh diff --git a/handle/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/handle b/handle/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/handle new file mode 100644 index 00000000..e69de29b diff --git a/handle/rootfs/etc/s6-overlay/scripts/handle-setup.sh b/handle/rootfs/etc/s6-overlay/scripts/handle-setup.sh new file mode 100755 index 00000000..288ec33d --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/scripts/handle-setup.sh @@ -0,0 +1,111 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +function mysql_create_database { + echo "Initializing MySQL database" + cat <<-EOF | create-database.sh +-- Create handle database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS ${HANDLE_DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci; +-- Create handle user and grant rights. +CREATE USER IF NOT EXISTS '${HANDLE_DB_USER}'@'%' IDENTIFIED BY '${HANDLE_DB_PASSWORD}'; +GRANT ALL PRIVILEGES ON ${HANDLE_DB_NAME}.* to '${HANDLE_DB_USER}'@'%'; +FLUSH PRIVILEGES; +-- Update handle password if changed. +SET PASSWORD FOR ${HANDLE_DB_USER}@'%' = PASSWORD('${HANDLE_DB_PASSWORD}'); +USE ${HANDLE_DB_NAME}; +CREATE TABLE IF NOT EXISTS nas ( +na varchar(255) NOT NULL, +PRIMARY KEY(na) +); + +CREATE TABLE IF NOT EXISTS handles ( +handle varchar(255) NOT NULL, +idx int4 NOT NULL, +type blob, +data blob, +ttl_type int2, +ttl int4, +timestamp int4, +refs blob, +admin_read bool, +admin_write bool, +pub_read bool, +pub_write bool, +PRIMARY KEY(handle, idx) +); + +EOF +} + +function postgresql_create_database { + echo "Initializing PostGreSQL database" + cat <<-EOF | create-database.sh +BEGIN; +DO \$\$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${HANDLE_DB_USER}') THEN + CREATE ROLE ${HANDLE_DB_USER}; + END IF; +END +\$\$; +ALTER ROLE ${HANDLE_DB_USER} WITH LOGIN; +ALTER USER ${HANDLE_DB_USER} PASSWORD '${HANDLE_DB_PASSWORD}'; +ALTER DATABASE ${HANDLE_DB_NAME} OWNER TO ${HANDLE_DB_USER}; +GRANT ALL PRIVILEGES ON DATABASE ${HANDLE_DB_NAME} TO ${HANDLE_DB_USER}; +COMMIT; +CREATE TABLE IF NOT EXISTS nas ( +na varchar(255) NOT NULL, +PRIMARY KEY(na) +); +ALTER TABLE nas OWNER TO ${HANDLE_DB_USER}; + +CREATE TABLE IF NOT EXISTS handles ( +handle varchar(255) NOT NULL, +idx int4 NOT NULL, +type bytea, +data bytea, +ttl_type int2, +ttl int4, +timestamp int4, +refs bytea, +admin_read bytea, +admin_write bool, +pub_read bool, +pub_write bool, +PRIMARY KEY(handle, idx) +); +ALTER TABLE handles OWNER TO ${HANDLE_DB_USER}; +EOF +} + +function create_database { + case "${DB_DRIVER}" in + none) ;; + + mysql) + mysql_create_database + ;; + postgresql) + postgresql_create_database + ;; + *) + echo "Only mysql/postgresql are supported values for DB_DRIVER." >&2 + exit 1 + ;; + esac +} + +# Change log files to redirect to stdout/stderr +function redirect_logs_to_stdout { + ln -sf /dev/stdout /var/handle/logs/access.log + ln -sf /dev/stderr /var/handle/logs/error.log + chown -h handle:handle /var/handle/logs/* + chmod o+w /dev/stdout /dev/stderr +} + +function main { + redirect_logs_to_stdout + create_database +} +main diff --git a/handle/rootfs/etc/s6-overlay/scripts/process-keys.sh b/handle/rootfs/etc/s6-overlay/scripts/process-keys.sh new file mode 100755 index 00000000..862bf1b8 --- /dev/null +++ b/handle/rootfs/etc/s6-overlay/scripts/process-keys.sh @@ -0,0 +1,24 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Keys are provided via a confd and placed in "/opt/keys/handle" +function convert_key { + local in=${1} + shift + local out=${1} + shift + s6-setuidgid handle /opt/handle/bin/hdl-convert-key "/opt/keys/handle/${in}" -o "/var/handle/${out}" +} + +# Convert keys from PEM to DES bin files +convert_key "private.key" "privkey.bin" +convert_key "public.key" "pubkey.bin" +convert_key "admin.private.key" "admpriv.bin" +convert_key "admin.public.key" "admpub.bin" + +# Derive HANDLE_PUBLICKEY_BASE64 from the pubkey.bin file. +s6-env -i HANDLE_PUBLICKEY_BASE64="$(openssl base64 -A &2 + exit 1 + ;; +esac + +# Import derived value for DB_DRIVER into the container environment. +echo "DB_DRIVER=${DB_DRIVER}" | /usr/local/bin/confd-import-environment.sh diff --git a/handle/tests/ServiceStartsWithBackendMySQL/docker-compose.yml b/handle/tests/ServiceStartsWithBackendMySQL/docker-compose.yml new file mode 100644 index 00000000..43c706a3 --- /dev/null +++ b/handle/tests/ServiceStartsWithBackendMySQL/docker-compose.yml @@ -0,0 +1,20 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +name: handle-servicestartswithbackendmysql +services: + mariadb: + image: ${MARIADB:-islandora/mariadb:local} + handle: + environment: + HANDLE_PERSISTENCE_TYPE: mysql + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${HANDLE:-islandora/handle:local} diff --git a/handle/tests/ServiceStartsWithBackendMySQL/test.sh b/handle/tests/ServiceStartsWithBackendMySQL/test.sh new file mode 100755 index 00000000..c96ad1c5 --- /dev/null +++ b/handle/tests/ServiceStartsWithBackendMySQL/test.sh @@ -0,0 +1,13 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Exit non-zero if database does not exist. +cat <<-EOF | execute-sql-file.sh + use ${DB_NAME} +EOF + +# All tests were successful +exit 0 diff --git a/handle/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml b/handle/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml new file mode 100644 index 00000000..a98ecdcc --- /dev/null +++ b/handle/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml @@ -0,0 +1,20 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +name: handle-servicestartswithbackendpostgresql +services: + postgresql: + image: ${POSTGRESQL:-islandora/postgresql:local} + handle: + environment: + HANDLE_PERSISTENCE_TYPE: postgresql + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${HANDLE:-islandora/handle:local} diff --git a/handle/tests/ServiceStartsWithBackendPostgreSQL/test.sh b/handle/tests/ServiceStartsWithBackendPostgreSQL/test.sh new file mode 100755 index 00000000..b2af94ca --- /dev/null +++ b/handle/tests/ServiceStartsWithBackendPostgreSQL/test.sh @@ -0,0 +1,16 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh +count=$(execute-sql-file.sh <(echo "SELECT 1 FROM pg_database WHERE datname='handle'") -- --csv -t) + +if [[ "${count}" -eq "1" ]]; then + echo "Database exists." +else + echo "Database missing." + exit 1 +fi + +# All tests were successful +exit 0 diff --git a/homarus/.dockerignore b/homarus/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/homarus/.dockerignore +++ b/homarus/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/homarus/Dockerfile b/homarus/Dockerfile index a0e54691..66f0ae8e 100644 --- a/homarus/Dockerfile +++ b/homarus/Dockerfile @@ -1,20 +1,28 @@ -# syntax=docker/dockerfile:experimental -FROM local/crayfish:latest - -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh \ - ffmpeg \ - && \ - cleanup.sh +# syntax=docker/dockerfile:1.5.1 +FROM crayfish + +ARG TARGETARCH + +EXPOSE 8000 + +WORKDIR /var/www/crayfish/Homarus -RUN --mount=type=cache,target=/root/.composer/cache \ +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=homarus-composer-${TARGETARCH},sharing=locked,target=/root/.composer/cache \ composer install -d /var/www/crayfish/Homarus && \ - ln -s /var/www/crayfish/Homarus/src /var/www/html && \ + ln -s /var/www/crayfish/Homarus/public /var/www/html && \ cleanup.sh -COPY /rootfs / +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=homarus-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add ffmpeg && \ + addgroup nginx jwt && \ + cleanup.sh -RUN chown -R nginx:nginx /var/www +ENV \ + HOMARUS_FCREPO_URL=http://fcrepo:8080/fcrepo/rest \ + HOMARUS_LOG_LEVEL=info -WORKDIR /var/www/crayfish/Homarus/ +COPY --link rootfs / + +RUN chown -R nginx:nginx /var/www diff --git a/homarus/README.md b/homarus/README.md index 482fa11b..5e27aa7d 100644 --- a/homarus/README.md +++ b/homarus/README.md @@ -10,8 +10,9 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :----------------- | :------ | :------------------------------------------------------------------------------------------------ | -| HOMARUS_LOG_LEVEL | /homarus/log/level | debug | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | +| Environment Variable | Default | Description | +| :------------------- | :----------------------------- | :------------------------------------------------------------------------------------------------ | +| HOMARUS_FCREPO_URL | http://fcrepo:8080/fcrepo/rest | Fcrepo Rest API URL | +| HOMARUS_LOG_LEVEL | info | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | [Homarus]: https://github.com/Islandora/Crayfish/tree/main/Homarus diff --git a/homarus/rootfs/etc/confd/conf.d/config.yaml.toml b/homarus/rootfs/etc/confd/conf.d/config.yaml.toml deleted file mode 100644 index 73251e38..00000000 --- a/homarus/rootfs/etc/confd/conf.d/config.yaml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "config.yaml.tmpl" -dest = "/var/www/crayfish/Homarus/cfg/config.yaml" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/log/level" ] diff --git a/homarus/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml b/homarus/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml new file mode 100644 index 00000000..3ff0db73 --- /dev/null +++ b/homarus/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "crayfish_commons.yaml.tmpl" +dest = "/var/www/crayfish/Homarus/config/packages/crayfish_commons.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/homarus/rootfs/etc/confd/conf.d/monolog.yaml.toml b/homarus/rootfs/etc/confd/conf.d/monolog.yaml.toml new file mode 100644 index 00000000..43cec50c --- /dev/null +++ b/homarus/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "monolog.yaml.tmpl" +dest = "/var/www/crayfish/Homarus/config/packages/monolog.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/homarus/rootfs/etc/confd/conf.d/security.yaml.toml b/homarus/rootfs/etc/confd/conf.d/security.yaml.toml new file mode 100644 index 00000000..57bd4ff1 --- /dev/null +++ b/homarus/rootfs/etc/confd/conf.d/security.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "security.yaml.tmpl" +dest = "/var/www/crayfish/Homarus/config/packages/security.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/homarus/rootfs/etc/confd/confd.toml b/homarus/rootfs/etc/confd/confd.toml deleted file mode 100644 index a1478f64..00000000 --- a/homarus/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/homarus" diff --git a/homarus/rootfs/etc/confd/templates/config.yaml.tmpl b/homarus/rootfs/etc/confd/templates/config.yaml.tmpl deleted file mode 100644 index 0cddfdd6..00000000 --- a/homarus/rootfs/etc/confd/templates/config.yaml.tmpl +++ /dev/null @@ -1,40 +0,0 @@ ---- -homarus: - # path to the ffmpeg executable - executable: ffmpeg - mime_types: - valid: - - video/mp4 - - video/x-msvideo - - video/ogg - - audio/x-wav - - audio/mpeg - - audio/aac - - image/jpeg - - image/png - default: video/mp4 - mime_to_format: - valid: - - video/mp4_mp4 - - video/x-msvideo_avi - - video/ogg_ogg - - audio/x-wav_wav - - audio/mpeg_mp3 - - audio/aac_m4a - - image/jpeg_image2pipe - - image/png_image2pipe - default: mp4 - -log: - # Valid log levels are: - # debug, info, notice, warning, error, critical, alert, emergency, none - file: "php://stderr" - level: {{ getv "/log/level" "debug" }} - -syn: - # toggles JWT security for service - enable: True - # Path to the syn config file for authentication. - # example can be found here: - # https://github.com/Islandora/Syn/blob/main/conf/syn-settings.example$ - config: /var/www/crayfish/syn-settings.xml diff --git a/homarus/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl b/homarus/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl new file mode 100644 index 00000000..a35df776 --- /dev/null +++ b/homarus/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl @@ -0,0 +1,3 @@ +crayfish_commons: + fedora_base_uri: '{{ getenv "HOMARUS_FCREPO_URL" }}' + syn_config: '/opt/keys/jwt/syn-settings.xml' diff --git a/homarus/rootfs/etc/confd/templates/monolog.yaml.tmpl b/homarus/rootfs/etc/confd/templates/monolog.yaml.tmpl new file mode 100644 index 00000000..6601077d --- /dev/null +++ b/homarus/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -0,0 +1,8 @@ +monolog: + handlers: + homarus: + type: stream + path: "php://stderr" + # Valid log levels are: + # debug, info, notice, warning, error, critical, alert, emergency, none + level: {{ getenv "HOMARUS_LOG_LEVEL" }} diff --git a/homarus/rootfs/etc/confd/templates/security.yaml.tmpl b/homarus/rootfs/etc/confd/templates/security.yaml.tmpl new file mode 100644 index 00000000..83034da4 --- /dev/null +++ b/homarus/rootfs/etc/confd/templates/security.yaml.tmpl @@ -0,0 +1,35 @@ +security: + + # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers + providers: + jwt_user_provider: + id: Islandora\Crayfish\Commons\Syn\JwtUserProvider + + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + # To enable Syn, change anonymous to false and uncomment the lines further below + anonymous: false + # Need stateless or it reloads the User based on a token. + stateless: true + + # To enable Syn, uncomment the below 4 lines and change anonymous to false above. + provider: jwt_user_provider + guard: + authenticators: + - Islandora\Crayfish\Commons\Syn\JwtAuthenticator + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#firewalls-authentication + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } diff --git a/homarus/tests/ServiceStartsWithDefaults/docker-compose.yml b/homarus/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..e0da3357 --- /dev/null +++ b/homarus/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: homarus-servicestartswithdefaults +services: + homarus: + <<: *common + image: ${HOMARUS:-islandora/homarus:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/homarus/tests/ServiceStartsWithDefaults/test.sh b/homarus/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..ea2829b5 --- /dev/null +++ b/homarus/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,8 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# Wait for service to start. +wait_20x http://localhost:8000/ + +# Service must start for us to get to this point. +exit 0 diff --git a/houdini/.dockerignore b/houdini/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/houdini/.dockerignore +++ b/houdini/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/houdini/Dockerfile b/houdini/Dockerfile index 2f9d8681..803c4d05 100644 --- a/houdini/Dockerfile +++ b/houdini/Dockerfile @@ -1,21 +1,31 @@ -# syntax=docker/dockerfile:experimental -FROM local/imagemagick:latest as imagemagick +# syntax=docker/dockerfile:1.5.1 +FROM imagemagick +FROM crayfish -FROM local/crayfish:latest +ARG TARGETARCH -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - --mount=type=bind,from=imagemagick,source=/home/builder/packages/x86_64,target=/packages \ - --mount=type=bind,from=imagemagick,source=/etc/apk/keys,target=/etc/apk/keys \ - --mount=type=cache,target=/root/.composer/cache \ - apk add /packages/imagemagick-*.apk && \ +EXPOSE 8000 + +WORKDIR /var/www/crayfish/Houdini + +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=houdini-composer-${TARGETARCH},sharing=locked,target=/root/.composer/cache \ composer install -d /var/www/crayfish/Houdini && \ - php /var/www/crayfish/Houdini/bin/console cache:clear && \ ln -s /var/www/crayfish/Houdini/public /var/www/html && \ cleanup.sh -COPY /rootfs / +# Platform specific does require arch specific identifier. +# Though platform information is included via the FROM imagemagick. +RUN --mount=type=bind,from=imagemagick,source=/packages,target=/packages \ + --mount=type=bind,from=imagemagick,source=/etc/apk/keys,target=/etc/apk/keys \ + apk add /packages/imagemagick-*.apk && \ + addgroup nginx jwt && \ + cleanup.sh + +ENV \ + HOUDINI_FCREPO_URL=http://fcrepo:8080/fcrepo/rest \ + HOUDINI_LOG_LEVEL=info -RUN chown -R nginx:nginx /var/www +COPY --link rootfs / -WORKDIR /var/www/crayfish/Houdini/ +RUN chown -R nginx:nginx /var/www diff --git a/houdini/README.md b/houdini/README.md index 4fd9d611..891bb7f5 100644 --- a/houdini/README.md +++ b/houdini/README.md @@ -10,8 +10,9 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :----------------- | :------ | :------------------------------------------------------------------------------------------------ | -| HOUDINI_LOG_LEVEL | /houdini/log/level | debug | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | +| Environment Variable | Default | Description | +| :------------------- | :----------------------------- | :------------------------------------------------------------------------------------------------ | +| HOUDINI_FCREPO_URL | http://fcrepo:8080/fcrepo/rest | Fcrepo Rest API URL | +| HOUDINI_LOG_LEVEL | info | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | [Houdini]: https://github.com/Islandora/Crayfish/tree/main/Houdini diff --git a/houdini/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml b/houdini/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml new file mode 100644 index 00000000..32664e61 --- /dev/null +++ b/houdini/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "crayfish_commons.yaml.tmpl" +dest = "/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml b/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml index 3ceebd7d..42f0a312 100644 --- a/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml +++ b/houdini/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -4,4 +4,4 @@ dest = "/var/www/crayfish/Houdini/config/packages/monolog.yaml" uid = 100 gid = 101 mode = "0644" -keys = [ "/log/level" ] +keys = [ "/" ] diff --git a/houdini/rootfs/etc/confd/conf.d/security.yaml.toml b/houdini/rootfs/etc/confd/conf.d/security.yaml.toml new file mode 100644 index 00000000..1043a698 --- /dev/null +++ b/houdini/rootfs/etc/confd/conf.d/security.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "security.yaml.tmpl" +dest = "/var/www/crayfish/Houdini/config/packages/security.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/houdini/rootfs/etc/confd/confd.toml b/houdini/rootfs/etc/confd/confd.toml deleted file mode 100644 index b23e63e9..00000000 --- a/houdini/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/houdini" diff --git a/houdini/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl b/houdini/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl new file mode 100644 index 00000000..8b136559 --- /dev/null +++ b/houdini/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl @@ -0,0 +1,3 @@ +crayfish_commons: + fedora_base_uri: '{{ getenv "HOUDINI_FCREPO_URL" }}' + syn_config: '/opt/keys/jwt/syn-settings.xml' diff --git a/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl b/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl index 3c05eb78..ffdf4fa3 100644 --- a/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl +++ b/houdini/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -5,4 +5,4 @@ monolog: path: "php://stderr" # Valid log levels are: # debug, info, notice, warning, error, critical, alert, emergency, none - level: {{ getv "/log/level" "debug" }} + level: {{ getenv "HOUDINI_LOG_LEVEL" }} diff --git a/houdini/rootfs/etc/confd/templates/security.yaml.tmpl b/houdini/rootfs/etc/confd/templates/security.yaml.tmpl new file mode 100644 index 00000000..7a727977 --- /dev/null +++ b/houdini/rootfs/etc/confd/templates/security.yaml.tmpl @@ -0,0 +1,36 @@ +# To disable Syn checking, set syn_enabled=false in crayfish_commons.yaml and remove this configuration file. +security: + + # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers + providers: + jwt_user_provider: + id: Islandora\Crayfish\Commons\Syn\JwtUserProvider + + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + # To enable Syn, change anonymous to false and uncomment the lines further below + anonymous: false + # Need stateless or it reloads the User based on a token. + stateless: true + + # To enable Syn, uncomment the below 4 lines and change anonymous to false above. + provider: jwt_user_provider + guard: + authenticators: + - Islandora\Crayfish\Commons\Syn\JwtAuthenticator + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#firewalls-authentication + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } diff --git a/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml b/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml index 67e492b1..c756429d 100644 --- a/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml +++ b/houdini/rootfs/var/www/crayfish/Houdini/config/packages/crayfish_commons.yaml @@ -1,3 +1,3 @@ crayfish_commons: - syn_config: /var/www/crayfish/syn-settings.xml + syn_config: /opt/keys/jwt/syn-settings.xml syn_enabled: True diff --git a/houdini/tests/ServiceStartsWithDefaults/docker-compose.yml b/houdini/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..c9461b44 --- /dev/null +++ b/houdini/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: houdini-servicestartswithdefaults +services: + houdini: + <<: *common + image: ${HOUDINI:-islandora/houdini:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/houdini/tests/ServiceStartsWithDefaults/test.sh b/houdini/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..ea2829b5 --- /dev/null +++ b/houdini/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,8 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# Wait for service to start. +wait_20x http://localhost:8000/ + +# Service must start for us to get to this point. +exit 0 diff --git a/hypercube/.dockerignore b/hypercube/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/hypercube/.dockerignore +++ b/hypercube/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/hypercube/Dockerfile b/hypercube/Dockerfile index 76c737e6..552bc555 100644 --- a/hypercube/Dockerfile +++ b/hypercube/Dockerfile @@ -1,12 +1,29 @@ -# syntax=docker/dockerfile:experimental -FROM local/crayfish:latest +# syntax=docker/dockerfile:1.5.1 +FROM leptonica +FROM crayfish AS hypercube -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - --mount=type=cache,target=/root/.composer/cache \ - apk-install.sh \ +ARG TARGETARCH + +EXPOSE 8000 + +WORKDIR /var/www/crayfish/Hypercube + +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=hypercube-composer-${TARGETARCH},sharing=locked,target=/root/.composer/cache \ + composer install -d /var/www/crayfish/Hypercube && \ + ln -s /var/www/crayfish/Hypercube/public /var/www/html && \ + cleanup.sh + +# Platform specific does require arch specific identifier. +# Though platform information is included via the FROM leptonica. +RUN --mount=type=cache,id=hypercube-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + --mount=type=bind,from=leptonica,source=/packages,target=/packages \ + --mount=type=bind,from=leptonica,source=/etc/apk/keys,target=/etc/apk/keys \ + apk add \ + /packages/leptonica-*.apk \ poppler-utils \ tesseract-ocr \ + tesseract-ocr-data-eng \ tesseract-ocr-data-fra \ tesseract-ocr-data-spa \ tesseract-ocr-data-ita \ @@ -16,10 +33,12 @@ RUN --mount=type=cache,target=/var/cache/apk \ tesseract-ocr-data-jpn \ tesseract-ocr-data-rus \ && \ - composer install -d /var/www/crayfish/Hypercube && \ - ln -s /var/www/crayfish/Hypercube/src /var/www/html && \ + addgroup nginx jwt && \ cleanup.sh -COPY /rootfs / +ENV HYPERCUBE_FCREPO_URL=fcrepo:8080/fcrepo/rest \ + HYPERCUBE_LOG_LEVEL=info + +COPY --link rootfs / -WORKDIR /var/www/crayfish/Hypercube/ +RUN chown -R nginx:nginx /var/www diff --git a/hypercube/README.md b/hypercube/README.md index 835a9f9b..0aeabeb4 100644 --- a/hypercube/README.md +++ b/hypercube/README.md @@ -10,9 +10,9 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :-------------------- | :----------------- | :------------------------------------------------------------------------------------------------ | -| HYPERCUBE_FCREPO_URL | /hypercube/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | -| HYPERCUBE_LOG_LEVEL | /hypercube/log/level | debug | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | +| Environment Variable | Default | Description | +| :------------------- | :----------------------------- | :------------------------------------------------------------------------------------------------ | +| HYPERCUBE_FCREPO_URL | http://fcrepo:8080/fcrepo/rest | Fcrepo Rest API URL | +| HYPERCUBE_LOG_LEVEL | info | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | [Hypercube]: https://github.com/Islandora/Crayfish/tree/main/Hypercube diff --git a/hypercube/rootfs/etc/confd/conf.d/config.yaml.toml b/hypercube/rootfs/etc/confd/conf.d/config.yaml.toml deleted file mode 100644 index 82bc8a80..00000000 --- a/hypercube/rootfs/etc/confd/conf.d/config.yaml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "config.yaml.tmpl" -dest = "/var/www/crayfish/Hypercube/cfg/config.yaml" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/log/level", "/fcrepo/url" ] diff --git a/hypercube/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml b/hypercube/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml new file mode 100644 index 00000000..54d71fd9 --- /dev/null +++ b/hypercube/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "crayfish_commons.yaml.tmpl" +dest = "/var/www/crayfish/Hypercube/config/packages/crayfish_commons.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/hypercube/rootfs/etc/confd/conf.d/monolog.yaml.toml b/hypercube/rootfs/etc/confd/conf.d/monolog.yaml.toml new file mode 100644 index 00000000..d9a5c800 --- /dev/null +++ b/hypercube/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "monolog.yaml.tmpl" +dest = "/var/www/crayfish/Hypercube/config/packages/monolog.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/hypercube/rootfs/etc/confd/conf.d/security.yaml.toml b/hypercube/rootfs/etc/confd/conf.d/security.yaml.toml new file mode 100644 index 00000000..efa47903 --- /dev/null +++ b/hypercube/rootfs/etc/confd/conf.d/security.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "security.yaml.tmpl" +dest = "/var/www/crayfish/Hypercube/config/packages/security.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/hypercube/rootfs/etc/confd/confd.toml b/hypercube/rootfs/etc/confd/confd.toml deleted file mode 100644 index 54a65ee1..00000000 --- a/hypercube/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/hypercube" diff --git a/hypercube/rootfs/etc/confd/templates/config.yaml.tmpl b/hypercube/rootfs/etc/confd/templates/config.yaml.tmpl deleted file mode 100644 index 50446100..00000000 --- a/hypercube/rootfs/etc/confd/templates/config.yaml.tmpl +++ /dev/null @@ -1,19 +0,0 @@ ---- -hypercube: - # path to the convert executable - tesseract_executable: tesseract - pdftotext_executable: pdftotext -fedora_resource: - base_url: {{ getv "/fcrepo/url" "fcrepo/fcrepo/rest" }} -log: - # Valid log levels are: - # debug, info, notice, warning, error, critical, alert, emergency, none - file: "php://stderr" - level: {{ getv "/log/level" "debug" }} -syn: - # toggles JWT security for service - enable: true - # Path to the syn config file for authentication. - # example can be found here: - # https://github.com/Islandora/Syn/blob/main/conf/syn-settings.example.xml - config: /var/www/crayfish/syn-settings.xml diff --git a/hypercube/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl b/hypercube/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl new file mode 100644 index 00000000..e39ccf41 --- /dev/null +++ b/hypercube/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl @@ -0,0 +1,3 @@ +crayfish_commons: + fedora_base_uri: '{{ getenv "HYPERCUBE_FCREPO_URL" }}' + syn_config: '/opt/keys/jwt/syn-settings.xml' diff --git a/hypercube/rootfs/etc/confd/templates/monolog.yaml.tmpl b/hypercube/rootfs/etc/confd/templates/monolog.yaml.tmpl new file mode 100644 index 00000000..392eee90 --- /dev/null +++ b/hypercube/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -0,0 +1,8 @@ +monolog: + handlers: + hypercube: + type: stream + path: "php://stderr" + # Valid log levels are: + # debug, info, notice, warning, error, critical, alert, emergency, none + level: {{ getenv "HYPERCUBE_LOG_LEVEL" }} diff --git a/hypercube/rootfs/etc/confd/templates/security.yaml.tmpl b/hypercube/rootfs/etc/confd/templates/security.yaml.tmpl new file mode 100644 index 00000000..79fd27e2 --- /dev/null +++ b/hypercube/rootfs/etc/confd/templates/security.yaml.tmpl @@ -0,0 +1,33 @@ +security: + # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers + providers: + users_in_memory: { memory: null } + jwt_user_provider: + id: Islandora\Crayfish\Commons\Syn\JwtUserProvider + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + # To enable Syn, change anonymous to false and uncomment the lines further below + anonymous: false + # Need stateless or it reloads the User based on a token. + stateless: true + + # To enable Syn, uncomment the below 4 lines and change anonymous to false above. + provider: jwt_user_provider + guard: + authenticators: + - Islandora\Crayfish\Commons\Syn\JwtAuthenticator + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#firewalls-authentication + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } diff --git a/hypercube/tests/ServiceStartsWithDefaults/docker-compose.yml b/hypercube/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..84ee3177 --- /dev/null +++ b/hypercube/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: hypercube-servicestartswithdefaults +services: + hypercube: + <<: *common + image: ${HYPERCUBE:-islandora/hypercube:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/hypercube/tests/ServiceStartsWithDefaults/test.sh b/hypercube/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..ea2829b5 --- /dev/null +++ b/hypercube/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,8 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# Wait for service to start. +wait_20x http://localhost:8000/ + +# Service must start for us to get to this point. +exit 0 diff --git a/imagemagick/.dockerignore b/imagemagick/.dockerignore deleted file mode 100644 index b43bf86b..00000000 --- a/imagemagick/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -README.md diff --git a/imagemagick/Dockerfile b/imagemagick/Dockerfile deleted file mode 100644 index fb551073..00000000 --- a/imagemagick/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM local/abuild:latest - -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk --update add \ - libheif-dev \ - libwebp-dev \ - chrpath \ - fftw-dev \ - fontconfig-dev \ - freetype-dev \ - ghostscript-dev \ - ghostscript-fonts \ - graphviz \ - lcms2-dev \ - libjpeg-turbo-dev \ - libpng-dev \ - librsvg-dev \ - libtool \ - libwmf-dev \ - libx11-dev \ - libxext-dev \ - libxml2-dev \ - openexr-dev \ - openjpeg-dev \ - pango-dev \ - perl-dev \ - tiff-dev \ - zlib-dev - -COPY /build /build - -WORKDIR /build - -RUN chown -R builder /build - -ARG PACKAGER="Nigel Banks " - -USER builder - -RUN export PACKAGER="${PACKAGER}" && \ - abuild-keygen -ain && \ - abuild-apk update && \ - abuild diff --git a/imagemagick/README.md b/imagemagick/README.md deleted file mode 100644 index 4ed14157..00000000 --- a/imagemagick/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Imagemagick - -Docker image for `imagemagick` package. - -It is not meant to be deployed as a service, but rather as base to import our -custom imagemagick build into containers like `islandora/houdini`. - -Consumers are expected to follow this pattern: - -```dockerfile -FROM islandora/imagemagick:latest as imagemagick - -FROM some_image:latest - -RUN --mount=type=bind,from=imagemagick,source=/home/builder/packages/x86_64,target=/packages \ - --mount=type=bind,from=imagemagick,source=/etc/apk/keys,target=/etc/apk/keys \ - apk add /packages/imagemagick-*.apk && \ - ... other build steps ... && \ - cleanup.sh -``` - -## Dependencies - -Requires `islandora/abuild` docker image to build. Please refer to the -[ABuild Image README](../abuild/README.md) for additional information. diff --git a/imagemagick/build/APKBUILD b/imagemagick/build/APKBUILD deleted file mode 100644 index b9208b60..00000000 --- a/imagemagick/build/APKBUILD +++ /dev/null @@ -1,200 +0,0 @@ -# Adapted from: https://git.alpinelinux.org/aports/commit/?id=f0a480dcf122a955d24fffe94517875a4e32061e -# Contributor: Nigel Banks -# Contributor: Łukasz Jendrysik -# Contributor: Carlo Landmeter -# Maintainer: Natanael Copa -pkgname=imagemagick -_pkgname=ImageMagick -pkgver=7.0.10.10 -pkgrel=0 -_pkgver=${pkgver%.*}-${pkgver##*.} -_abiver=7 -pkgdesc="Collection of tools and libraries for many image formats" -url="https://www.imagemagick.org/" -arch="all" -license="ImageMagick" -options="libtool" -makedepends=" - chrpath - fftw-dev - fontconfig-dev - freetype-dev - ghostscript-dev - lcms2-dev - libheif-dev - libjpeg-turbo-dev - libpng-dev - libtool - libwebp-dev - libwmf-dev - libx11-dev - libxext-dev - libxml2-dev - openexr-dev - openjpeg-dev - pango-dev - perl-dev - tiff-dev - zlib-dev" - -case "$CARCH" in - s390x) ;; - mips*) options="!check" ;; - *) makedepends="$makedepends librsvg-dev" ;; -esac - -checkdepends="freetype fontconfig ghostscript ghostscript-fonts lcms2 graphviz" -subpackages=" - $pkgname-doc - $pkgname-static - $pkgname-dev - $pkgname-c++:_cxx - $pkgname-libs - $pkgname-perlmagick:_perlmagick - $pkgname-perlmagick-doc:_perlmagick_doc - " -source="$_pkgname-$_pkgver.tar.gz::https://github.com/ImageMagick/ImageMagick/archive/$_pkgver.tar.gz - disable-avaraging-tests.patch" -builddir="$srcdir/$_pkgname-$_pkgver" - -# secfixes: -# 7.0.9.7-r0: -# - CVE-2019-19952 -# 7.0.8.62-r0: -# - CVE-2019-17547 -# 7.0.8.56-r0: -# - CVE-2019-17541 -# - CVE-2019-17540 -# - CVE-2019-14981 -# - CVE-2019-13454 -# 7.0.8.53-r0: -# - CVE-2019-13391 -# - CVE-2019-13311 -# - CVE-2019-13310 -# - CVE-2019-13309 -# - CVE-2019-13308 -# - CVE-2019-13307 -# - CVE-2019-13306 -# - CVE-2019-13305 -# - CVE-2019-13304 -# - CVE-2019-13303 -# - CVE-2019-13302 -# - CVE-2019-13301 -# - CVE-2019-13300 -# - CVE-2019-13299 -# - CVE-2019-13298 -# - CVE-2019-13297 -# - CVE-2019-13296 -# - CVE-2019-13295 -# - CVE-2019-13137 -# - CVE-2019-13136 -# - CVE-2019-13135 -# - CVE-2019-13134 -# - CVE-2019-13133 -# 7.0.8.44-r0: -# - CVE-2019-19949 -# - CVE-2019-19948 -# - CVE-2019-16713 -# - CVE-2019-16712 -# - CVE-2019-16711 -# - CVE-2019-15141 -# - CVE-2019-15140 -# - CVE-2019-15139 -# - CVE-2019-14980 -# - CVE-2019-11598 -# - CVE-2019-11597 -# - CVE-2019-11472 -# 7.0.8.38-r0: -# - CVE-2019-9956 -# - CVE-2019-16710 -# - CVE-2019-16709 -# - CVE-2019-16708 -# - CVE-2019-10650 -# - CVE-2019-10649 - -build() { - case "$CARCH" in - s390x) ;; - *) _conf_args="--with-rsvg" ;; - esac - - # fix doc dir, Gentoo bug 91911 - sed -i -e \ - 's:DOCUMENTATION_PATH="$DATA_DIR/doc/$DOCUMENTATION_RELATIVE_PATH":DOCUMENTATION_PATH="/usr/share/doc/imagemagick":g' \ - configure - ./configure -C \ - --build=$CBUILD \ - --host=$CHOST \ - --prefix=/usr \ - --sysconfdir=/etc \ - --mandir=/usr/share/man \ - --infodir=/usr/share/info \ - --enable-static \ - --disable-openmp \ - --with-threads \ - --with-x \ - --with-tiff \ - --with-png \ - --with-webp \ - --with-gslib \ - --with-gs-font-dir=/usr/share/fonts/Type1 \ - --with-heic \ - --with-modules \ - --with-xml \ - --with-perl \ - --with-perl-options="PREFIX=/usr INSTALLDIRS=vendor" \ - --with-dps=no \ - --with-fpx=no \ - --with-gslib=no \ - --with-gvc=no \ - --with-rsvg=no \ - $_conf_args - make -j $(nproc) -} - -check() { - # Test disabled to reduce build time, manually check if you are modifing this package script. - # make check -j $(nproc) - return 0 -} - -package() { - make -j1 DESTDIR="$pkgdir" install - if ! [ -e "$pkgdir"/usr/lib/libMagickCore-$_abiver.Q16HDRI.so ]; then - error "Has ABI verision changed? (current is $_abiver)" - return 1 - fi - - # we cannot let abuild delete the *.la files due to we need *.la - # for the modules - rm "$pkgdir"/usr/lib/*.la - - find "$pkgdir" \( -name '.packlist' -o -name 'perllocal.pod' \ - -o -name '*.bs' \) -delete -} - -_cxx() { - pkgdesc="ImageMagick Magick++ library (C++ bindings)" - mkdir -p "$subpkgdir"/usr/lib - mv "$pkgdir"/usr/lib/libMagick++*.so.* "$subpkgdir"/usr/lib/ -} - -_perlmagick() { - pkgdesc="PerlMagick Perl Modules for ImageMagick" - mkdir -p "$subpkgdir"/usr/lib - mv "$pkgdir"/usr/lib/perl5 "$subpkgdir"/usr/lib/ - # Strip all the rpath that include /home - scanelf --recursive --rpath "$subpkgdir" | awk '/home/{print $3;}' | xargs chrpath -d -# chrpath -d "$subpkgdir"/usr/lib/perl5/vendor_perl/auto/Image/Magick/Q16HDRI/Q16HDRI.so -# chrpath -d "$subpkgdir"/usr/lib/perl5/vendor_perl/auto/Image/Magick/Magick.so -} - -_perlmagick_doc() { - pkgdesc="PerlMagick Perl Module Documentation for ImageMagick" - mkdir -p "$subpkgdir" - cd "$builddir"/PerlMagick - make -j1 DESTDIR="$subpkgdir" doc_vendor_install -} - -sha512sums="2c9e0f0f172572473078651d11ee1a173ec8a0965310c04c9e96f2bfa1249362fb775f23681d5d866ec6b8847125a001814ddd91dda44ae613602127819b2894 ImageMagick-7.0.10-10.tar.gz -58afb2da075a6208b6a990ff297b3a827d260687c3355198a8b4d987e1596c0b0cd78aff6f0be0e1896e537fbe44a3d467473183f5f149664ea6e6fb3d3291a9 disable-avaraging-tests.patch" diff --git a/imagemagick/build/disable-avaraging-tests.patch b/imagemagick/build/disable-avaraging-tests.patch deleted file mode 100644 index 8e715f81..00000000 --- a/imagemagick/build/disable-avaraging-tests.patch +++ /dev/null @@ -1,26 +0,0 @@ -The avaraging tests seems to be flaky due to rounding errors. Test fails on -x86 and s390x - -https://github.com/ImageMagick/ImageMagick/issues/1576#issuecomment-494595404 - -diff --git a/Magick++/tests/tests.tap b/Magick++/tests/tests.tap -index b5c15ff..bb83980 100755 ---- a/Magick++/tests/tests.tap -+++ b/Magick++/tests/tests.tap -@@ -8,14 +8,14 @@ - # - subdir=Magick++/tests - . ./common.shi --echo "1..13" -+echo "1..12" - - SRCDIR=${top_srcdir}/${subdir}/ - export SRCDIR - - cd ${subdir} || exit 1 - --for mytest in appendImages attributes averageImages coalesceImages coderInfo color colorHistogram exceptions geometry montageImages morphImages readWriteBlob readWriteImages -+for mytest in appendImages attributes coalesceImages coderInfo color colorHistogram exceptions geometry montageImages morphImages readWriteBlob readWriteImages - do - ./${mytest} && echo "ok" || echo "not ok" - done diff --git a/java/.dockerignore b/java/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/java/.dockerignore +++ b/java/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/java/Dockerfile b/java/Dockerfile index d7423098..51ba7add 100644 --- a/java/Dockerfile +++ b/java/Dockerfile @@ -1,15 +1,16 @@ -# syntax=docker/dockerfile:experimental -FROM local/base:latest +# syntax=docker/dockerfile:1.5.1 +FROM base + +ARG TARGETARCH # Install packages and tools required by all downstream images. -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh \ - openjdk8 \ +# +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=java-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ + openjdk17 \ maven \ && \ cleanup.sh ENV JAVA_HOME=/usr/lib/jvm/default-jvm - -COPY rootfs / diff --git a/java/README.md b/java/README.md index 0816133a..494da9e2 100644 --- a/java/README.md +++ b/java/README.md @@ -1,6 +1,6 @@ # Java -Docker image for [Java] OpenJDK version 8. +Docker image for [Java] OpenJDK version 17. Please refer to the [Java Documentation] for more in-depth information. diff --git a/java/rootfs/usr/local/bin/install-apache-service.sh b/java/rootfs/usr/local/bin/install-apache-service.sh deleted file mode 100755 index 7a23ae0e..00000000 --- a/java/rootfs/usr/local/bin/install-apache-service.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env bash -set -e - -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" - -function usage() { - cat <<- EOF - usage: $PROGNAME options [FILE]... - - Installs the given apache service in /opt. Creates a user/group for the - service and ensuring that all files are owned by that user/group. - - Additional parameters are files to be removed from the installation to save - on space. Things like "examples", and "docs". - - OPTIONS: - -n --name The name of the services to install (used to create user/group and install directory). - -k --key GPG Key used to verify the downloaded file. - -f --file The name of the file to download. - -h --help Show this help. - -x --debug Debug this script. - - Examples: - Install ActiveMQ: - $PROGNAME \\ - --name "activemq" \\ - --key "62ED4DF0BACB8793" \\ - --file "apache-activemq-5.14.5-bin.tar.gz" \\ - examples webapps-demo docs -EOF -} - -function cmdline() { - local arg= - for arg - do - local delim="" - case "$arg" in - # Translate --gnu-long-options to -g (short options) - --name) args="${args}-n ";; - --key) args="${args}-k ";; - --file) args="${args}-f ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; - esac - done - - # Reset the positional parameters to the short options - eval set -- $args - - while getopts "n:k:f:hx" OPTION - do - case $OPTION in - n) - readonly NAME=${OPTARG} - ;; - k) - readonly KEY=${OPTARG} - ;; - f) - readonly FILE="${OPTARG}" - ;; - h) - usage - exit 0 - ;; - x) - readonly DEBUG='-x' - set -x - ;; - esac - done - - if [[ -z $NAME || -z $KEY || -z $FILE ]]; then - echo "Missing one or more required options: --name --key --file" - exit 1 - fi - - # All remaning parameters are files to be removed from the installation. - shift $((OPTIND-1)) - readonly REMOVE=("$@") - - return 0 -} - -function main { - cmdline ${ARGS} - local install_directory=/opt/${NAME} - local user=${NAME} - local group=${NAME} - gpg --keyserver hkp://pool.sks-keyservers.net --recv-key ${KEY} - gpg --verify ${FILE}.asc ${FILE} - mkdir ${install_directory} - addgroup ${group} && \ - adduser --system --disabled-password --no-create-home --ingroup ${group} --shell /sbin/nologin --home ${install_directory} ${user} - chown ${user}:${group} ${install_directory} - s6-setuidgid ${user} tar -xzf ${FILE} -C ${install_directory} --strip-components 1 - for i in "${REMOVE[@]}"; do - rm -fr "${install_directory}/${i}" - done - cleanup.sh -} -main diff --git a/karaf/.dockerignore b/karaf/.dockerignore deleted file mode 100644 index 42061c01..00000000 --- a/karaf/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -README.md \ No newline at end of file diff --git a/karaf/Dockerfile b/karaf/Dockerfile deleted file mode 100644 index 9f73536a..00000000 --- a/karaf/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# syntax=docker/dockerfile:experimental -FROM local/java:latest - -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - KARAF_VERSION="4.0.8" && \ - KARAF_FILE="apache-karaf-${KARAF_VERSION}.tar.gz" && \ - KARAF_URL="https://archive.apache.org/dist/karaf/${KARAF_VERSION}/${KARAF_FILE}" && \ - KARAF_FILE_SHA256="67e555e3896fbe87d23ceec008898bb33133f36b48d7e5ede363c214a54e7d2a" && \ - KARAF_SIG_SHA256="bba601fdcef14e0ac970244c27c2e8af91c58f5f9fbbab1d1b05293f331dbaf4" && \ - download.sh --url "${KARAF_URL}" --sha256 "${KARAF_FILE_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - download.sh --url "${KARAF_URL}.asc" --sha256 "${KARAF_SIG_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-apache-service.sh \ - --name karaf \ - --key "BFF2EE42C8282E76" \ - --file "${DOWNLOAD_CACHE_DIRECTORY}/${KARAF_FILE}" \ - demos \ - && \ - sed -i 's@http://repo1@https://repo1@' /opt/karaf/etc/org.ops4j.pax.url.mvn.cfg && \ - chown -R karaf:karaf /opt/karaf && \ - rm -rf /opt/karaf/instances/* && \ - cleanup.sh - -WORKDIR /opt/karaf - -EXPOSE 8101 1099 44444 8181 - -COPY rootfs / diff --git a/karaf/README.md b/karaf/README.md deleted file mode 100644 index 509bf575..00000000 --- a/karaf/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# Karaf - -Docker image for [Karaf] version 4.0.8 - -Please refer to the [Karaf Documentation] for more in-depth information. - -As a quick example this will bring up an instance of karaf, and allow you to -log view the [WebConsole] on as the user `admin` with -the password `password`. - -```bash -docker run --rm -ti \ - -p 8181:8181 \ - -e "KARAF_ADMIN_NAME=admin" \ - -e "KARAF_ADMIN_PASSWORD=password" \ - islandora/karaf -``` - -## Dependencies - -Requires `islandora/karaf` docker image to build. - -## Ports - -| Port | Description | -| :---- | :----------- | -| 8101 | [SSH] | -| 1099 | [RMI] | -| 44444 | [JMX] | -| 8181 | [WebConsole] | - -## Volumes - -| Path | Description | -| :-------------- | :-------------------------- | -| /opt/karaf/data | [Karaf Directory Structure] | - -## Settings - -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :-------------------- | :------- | :------------------ | -| KARAF_ADMIN_NAME | /karaf/admin/name | admin | Admin user name | -| KARAF_ADMIN_PASSWORD | /karaf/admin/password | password | Admin user password | - -Additional users/groups/etc can be defined by adding more environment variables, -following the above conventions: - -| Environment Variable | Etcd Key | Description | -| :------------------------- | :-------------------------- | :------------------------------- | -| KARAF_USER_{USER}_NAME | /karaf/user/{USER}/name | See [Security]: users.properties | -| KARAF_USER_{USER}_PASSWORD | /karaf/user/{USER}/password | See [Security]: users.properties | -| KARAF_USER_{USER}_ROLES | /karaf/user/{USER}/roles | See [Security]: users.properties | -| KARAF_GROUP_{GROUP}_NAME | /karaf/group/{GROUP}/name | See [Security]: users.properties | -| KARAF_GROUP_{GROUP}_ROLES | /karaf/group/{GROUP}/roles | See [Security]: users.properties | - -*N.B. These do not have defaults.* - -## Logs - -| Path | Description | -| :---------------------------- | :---------- | -| /opt/karaf/data/log/karaf.log | [Karaf Log] | - -[JMX]: https://karaf.apache.org/manual/latest/#_monitoring_and_management_using_jmx -[Karaf Directory Structure]: https://karaf.apache.org/manual/latest/#_directory_structure -[Karaf Documentation]: https://islandora.github.io/documentation/ -[Karaf Log]: https://karaf.apache.org/manual/latest/#_log -[Karaf]: https://github.com/Islandora/karaf -[RMI]: https://karaf.apache.org/manual/latest/monitoring -[Security]: https://karaf.apache.org/manual/latest/security -[SSH]: https://karaf.apache.org/manual/latest/remote -[WebConsole]: https://karaf.apache.org/manual/latest/webconsole diff --git a/karaf/rootfs/etc/confd/conf.d/users.properties.toml b/karaf/rootfs/etc/confd/conf.d/users.properties.toml deleted file mode 100644 index 267cd2a2..00000000 --- a/karaf/rootfs/etc/confd/conf.d/users.properties.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "users.properties.tmpl" -dest = "/opt/karaf/etc/users.properties" -uid = 100 -gid = 1000 -mode = "0640" -keys = [ "/karaf" ] diff --git a/karaf/rootfs/etc/confd/templates/users.properties.tmpl b/karaf/rootfs/etc/confd/templates/users.properties.tmpl deleted file mode 100644 index a97612e9..00000000 --- a/karaf/rootfs/etc/confd/templates/users.properties.tmpl +++ /dev/null @@ -1,18 +0,0 @@ -# -# This file contains the users, groups, and roles. -# Each line has to be of the format: -# -# USER=PASSWORD,ROLE1,ROLE2,... -# USER=PASSWORD,_g_:GROUP,... -# _g_\:GROUP=ROLE1,ROLE2,... -# -# All users, groups, and roles entered in this file are available after Karaf startup -# and modifiable via the JAAS command group. These users reside in a JAAS domain -# with the name "karaf". -# -{{ getv "/karaf/admin/name" "admin" }} = {{ getv "/karaf/admin/password" "password" }}, _g_:admingroup -_g_\:admingroup = group,admin,manager,viewer,systembundles -{{ range $dir := lsdir "/karaf/user" }}{{ getv (printf "/karaf/user/%s/name" $dir) }} = {{ getv (printf "/karaf/user/%s/password" $dir) }} {{ getv (printf "/karaf/user/%s/roles" $dir) }} -{{ end }} -{{ range $dir := lsdir "/karaf/group" }}{{ getv (printf "/karaf/group/%s/name" $dir) }} = {{ getv (printf "/karaf/group/%s/roles" $dir) }} -{{ end }} diff --git a/karaf/rootfs/etc/cont-init.d/03-karaf-startup.sh b/karaf/rootfs/etc/cont-init.d/03-karaf-startup.sh deleted file mode 100755 index cb575c48..00000000 --- a/karaf/rootfs/etc/cont-init.d/03-karaf-startup.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e -# On startup if we exit with sigterm the pid file is left behind sometimes. -rm /opt/karaf/instances/instance.properties &> /dev/null || true - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /opt/karaf/data/log/karaf.log -chown karaf:karaf /opt/karaf/data/log/karaf.log diff --git a/karaf/rootfs/etc/services.d/karaf/finish b/karaf/rootfs/etc/services.d/karaf/finish deleted file mode 100644 index f8984dd3..00000000 --- a/karaf/rootfs/etc/services.d/karaf/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh : -s6-svscanctl -t /var/run/s6/services diff --git a/karaf/rootfs/etc/services.d/karaf/run b/karaf/rootfs/etc/services.d/karaf/run deleted file mode 100644 index d1607dc7..00000000 --- a/karaf/rootfs/etc/services.d/karaf/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh : -with-contenv -s6-setuidgid karaf -/opt/karaf/bin/karaf server diff --git a/mariadb/.dockerignore b/mariadb/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/mariadb/.dockerignore +++ b/mariadb/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/mariadb/Dockerfile b/mariadb/Dockerfile index 17767284..6007aed8 100644 --- a/mariadb/Dockerfile +++ b/mariadb/Dockerfile @@ -1,17 +1,26 @@ -# syntax=docker/dockerfile:experimental -FROM local/base:latest +# syntax=docker/dockerfile:1.5.1 +FROM base -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh \ +ARG TARGETARCH + +EXPOSE 3306 + +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=mariadb-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ mariadb \ mysql-client \ && \ mkdir -p /var/lib/mysql-files && \ - chown -R mysql:mysql /var/lib/mysql && \ - chown -R mysql:mysql /var/lib/mysql-files && \ + chown -R mysql:mysql \ + /var/lib/mysql \ + /var/lib/mysql-files \ + && \ cleanup.sh -EXPOSE 3306 +# Installation sometimes needs more than the default 30 seconds defined in the +# base image. Set to 10 minutes just incase it ran on very old or overallocated +# hardware. +ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=600000 -COPY rootfs / +COPY --link rootfs / diff --git a/mariadb/README.md b/mariadb/README.md index d510eea7..1937280e 100644 --- a/mariadb/README.md +++ b/mariadb/README.md @@ -1,6 +1,6 @@ # MariaDB -Docker image for [MariaDB] version 10.4.12 +Docker image for [MariaDB] version 10.6.12 Please refer to the [MariaDB Documentation] for more in-depth information. @@ -32,9 +32,15 @@ Requires `islandora/base` docker image to build. Please refer to the ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :------------------- | :------- | :------------------------------------- | -| MYSQL_ROOT_PASSWORD | /mysql/root/password | password | The password for the root user account | +### Database Settings + +Please see the documentation in the [base image] for more information about the +default database connection configuration. + +| Environment Variable | Default | Description | +| :------------------- | :------ | :------------------------------------------------------------------------------------ | +| MYSQL_ROOT_PASSWORD | | The database root user password. Defaults to `DB_ROOT_PASSWORD` | +| MYSQL_ROOT_USER | | The database root user (used to create the site database). Defaults to `DB_ROOT_USER` | ## Logs @@ -42,5 +48,6 @@ Requires `islandora/base` docker image to build. Please refer to the | :----- | :------------ | | STDOUT | [MariaDB Log] | +[base image]: ../base/README.md [MariaDB Documentation]: https://mariadb.org/documentation/ [MariaDB]: https://mariadb.org/ diff --git a/mariadb/rootfs/etc/confd/conf.d/mariadb-server.cnf.toml b/mariadb/rootfs/etc/confd/conf.d/mariadb-server.cnf.toml deleted file mode 100644 index 537f353e..00000000 --- a/mariadb/rootfs/etc/confd/conf.d/mariadb-server.cnf.toml +++ /dev/null @@ -1,5 +0,0 @@ -[template] -src = "mariadb-server.cnf.tmpl" -dest = "/etc/my.cnf.d/mariadb-server.cnf" -mode="0644" -keys = [ "/root" ] diff --git a/mariadb/rootfs/etc/confd/conf.d/my.cnf.toml b/mariadb/rootfs/etc/confd/conf.d/my.cnf.toml deleted file mode 100644 index d74e5e43..00000000 --- a/mariadb/rootfs/etc/confd/conf.d/my.cnf.toml +++ /dev/null @@ -1,5 +0,0 @@ -[template] -src = "my.cnf.tmpl" -dest = "/etc/my.cnf" -mode="0644" -keys = ["/root" ] diff --git a/mariadb/rootfs/etc/confd/conf.d/set-root-user-password.sql.toml b/mariadb/rootfs/etc/confd/conf.d/set-root-user-password.sql.toml deleted file mode 100644 index e4d261f7..00000000 --- a/mariadb/rootfs/etc/confd/conf.d/set-root-user-password.sql.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "set-root-user-password.sql.tmpl" -dest = "/var/run/islandora/set-root-user-password.sql" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/root/password" ] diff --git a/mariadb/rootfs/etc/confd/confd.toml b/mariadb/rootfs/etc/confd/confd.toml deleted file mode 100644 index a5717209..00000000 --- a/mariadb/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/mysql" diff --git a/mariadb/rootfs/etc/confd/templates/my.cnf.tmpl b/mariadb/rootfs/etc/confd/templates/my.cnf.tmpl deleted file mode 100644 index cec4bd05..00000000 --- a/mariadb/rootfs/etc/confd/templates/my.cnf.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -# This group is read both both by the client and the server -# use it for options that affect everything -[client-server] - -# This group is read by the server -[mysqld] - -# Disabling symbolic-links is recommended to prevent assorted security risks -symbolic-links=0 - -# include all files from the config directory -!includedir /etc/my.cnf.d diff --git a/mariadb/rootfs/etc/confd/templates/set-root-user-password.sql.tmpl b/mariadb/rootfs/etc/confd/templates/set-root-user-password.sql.tmpl deleted file mode 100644 index 51c1b823..00000000 --- a/mariadb/rootfs/etc/confd/templates/set-root-user-password.sql.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -CREATE USER IF NOT EXISTS 'root'@'%'; -SET PASSWORD FOR 'root'@'localhost' = PASSWORD('{{ getv "/root/password" "password" }}'); -SET PASSWORD FOR 'root'@'%' = PASSWORD('{{ getv "/root/password" "password" }}'); -GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; -FLUSH PRIVILEGES; diff --git a/mariadb/rootfs/etc/cont-init.d/03-mysql-setup.sh b/mariadb/rootfs/etc/cont-init.d/03-mysql-setup.sh deleted file mode 100755 index fb685abc..00000000 --- a/mariadb/rootfs/etc/cont-init.d/03-mysql-setup.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# Make run directory if it does not exist. -mkdir /run/mysqld &> /dev/null || true -chown mysql:mysql /run/mysqld - -# Create the database if it does not exist. -if [[ ! -d "/var/lib/mysql/mysql" ]]; then - s6-setuidgid mysql mysql_install_db --basedir=/usr --datadir=/var/lib/mysql --skip-test-db --user mysql -fi - -# Startup the database so we can change the root users password. -s6-setuidgid mysql mysqld --skip-networking & -MYSQLD_PID=$! - -# Wait for it to startup. -until mysql --no-defaults --protocol=socket --user=root -e "SELECT 1" &> /dev/null; -do -sleep 1 -done - -# Change the root users password. -echo "Changing the root users password." -mysql --no-defaults --protocol=socket --user=root < /var/run/islandora/set-root-user-password.sql - -# Stop the database. -kill -s TERM ${MYSQLD_PID} - -# Allow database to stop. -wait diff --git a/mariadb/rootfs/etc/confd/templates/mariadb-server.cnf.tmpl b/mariadb/rootfs/etc/my.cnf.d/mariadb-server.cnf similarity index 99% rename from mariadb/rootfs/etc/confd/templates/mariadb-server.cnf.tmpl rename to mariadb/rootfs/etc/my.cnf.d/mariadb-server.cnf index cbcad522..77569381 100644 --- a/mariadb/rootfs/etc/confd/templates/mariadb-server.cnf.tmpl +++ b/mariadb/rootfs/etc/my.cnf.d/mariadb-server.cnf @@ -39,4 +39,3 @@ # If you use the same .cnf file for MariaDB of different versions, # use this group for options that older servers don't understand [mariadb-10.3] - diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-root-user b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-root-user new file mode 100644 index 00000000..e69de29b diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/dependencies.d/ready b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/type b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/up b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/up new file mode 100755 index 00000000..b53080bf --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysql-setup/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/mysql-setup.sh diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/dependencies.d/mysql-setup b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/dependencies.d/mysql-setup new file mode 100644 index 00000000..e69de29b diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/finish b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/run b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/run new file mode 100755 index 00000000..692fc2f6 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/run @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +exec s6-setuidgid mysql mysqld --user mysql diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/type b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/mysqld/type @@ -0,0 +1 @@ +longrun diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/dependencies.d/container-environment b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/type b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/type @@ -0,0 +1 @@ +oneshot diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/up b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/up new file mode 100755 index 00000000..63b7d313 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/set-root-user.sh diff --git a/mariadb/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/mysqld b/mariadb/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/mysqld new file mode 100644 index 00000000..e69de29b diff --git a/mariadb/rootfs/etc/s6-overlay/scripts/mysql-setup.sh b/mariadb/rootfs/etc/s6-overlay/scripts/mysql-setup.sh new file mode 100755 index 00000000..bb5763a9 --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/scripts/mysql-setup.sh @@ -0,0 +1,37 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Make run directory if it does not exist. +mkdir /run/mysqld &>/dev/null || true +chown mysql:mysql /run/mysqld + +# Create the database if it does not exist. +if [[ ! -d "/var/lib/mysql/mysql" ]]; then + s6-setuidgid mysql mysql_install_db --basedir=/usr --datadir=/var/lib/mysql --skip-test-db --user mysql +fi + +# Startup the database so we can change the root users password. +s6-setuidgid mysql mysqld --skip-networking & +MYSQLD_PID=$! + +# Wait for it to startup. +until mysql --no-defaults --protocol=socket --user="${DB_ROOT_USER}" -e "SELECT 1" &>/dev/null; do + sleep 1 +done + +# Change the root users password. +echo "Changing the root users (${DB_ROOT_USER}) password." +cat <<-EOF | mysql --no-defaults --protocol=socket --user="${DB_ROOT_USER}" + CREATE USER IF NOT EXISTS '${DB_ROOT_USER}'@'%'; + GRANT ALL PRIVILEGES ON *.* TO '${DB_ROOT_USER}'@'%' WITH GRANT OPTION; + SET PASSWORD FOR '${DB_ROOT_USER}'@'localhost' = PASSWORD('${DB_ROOT_PASSWORD}'); + SET PASSWORD FOR '${DB_ROOT_USER}'@'%' = PASSWORD('${DB_ROOT_PASSWORD}'); + FLUSH PRIVILEGES; +EOF + +# Stop the database. +kill -s TERM "${MYSQLD_PID}" + +# Allow database to stop. +wait diff --git a/mariadb/rootfs/etc/s6-overlay/scripts/set-root-user.sh b/mariadb/rootfs/etc/s6-overlay/scripts/set-root-user.sh new file mode 100755 index 00000000..f8f72d6e --- /dev/null +++ b/mariadb/rootfs/etc/s6-overlay/scripts/set-root-user.sh @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Use what has been provided by the user or default to the derived values. +cat < | +| MATOMO_DEFAULT_HOST | https://islandora.traefik.me | The URL of the default site for which to gather metrics for | +| MATOMO_DEFAULT_NAME | Islandora | The name of the default site | +| MATOMO_DEFAULT_TIMEZONE | America/Halifax | The timezone where the default site is hosted | +| MATOMO_FORCE_SSL | 1 | | +| MATOMO_PROXY_CLIENT_HEADERS | HTTP_X_FORWARDED_FOR | | +| MATOMO_PROXY_HOST_HEADERS | HTTP_X_FORWARDED_HOST | | +| MATOMO_PROXY_URI_HEADER | 1 | | +| MATOMO_USER_EMAIL | admin@example.org | The matomo administrator email | +| MATOMO_USER_NAME | admin | The matomo administrator user | +| MATOMO_USER_PASS | password | The matomo administrator's password (See how to generate below) | + +To regenerate a the `MATOMO_USER_PASS` you must use the following snippet of +[PHP](https://matomo.org/faq/how-to/faq_191/). + +```bash php -r 'echo password_hash(md5("password"), PASSWORD_DEFAULT) . "\n";' ``` -[Matomo]: https://matomo.org/ +On production sites generate your own `MATOMO_SALT` with the following snippet +of **PHP** it is important you keep it secret along with your passwords. + +```bash +php -r 'echo md5(uniqid(rand(), true));' +``` + +### Database Settings + +[Matomo] unlike many of our services can only use `MySQL` as a backend. Please see +the documentation in the [base image] for more information about the default +database connection configuration. + +| Environment Variable | Default | Description | +| :------------------- | :------- | :------------------------------------------------------- | +| MATOMO_DB_NAME | matomo | The name of the database | +| MATOMO_DB_USER | matomo | The user to connect to the database | +| MATOMO_DB_PASSWORD | password | The password of the user used to connect to the database | + +Additionally the `DB_DRIVER` variable is hard-coded to be `mysql` as no other +value is supported. + +### Multi-site Settings + +Additional multi-sites can be defined by adding more environment variables, +following the above conventions, only the `MATOMO_SITE_{SITE}_HOST` is required +to create an additional site: + +| Environment Variable | Default | Description | +| :---------------------------- | :----------------------------------------------------------- | :------------------------------------------------------------ | +| MATOMO_SITE_{SITE}_HOST | | The URL of the site for which to gather metrics for | +| MATOMO_SITE_{SITE}_NAME | {SITE} | The name of the site | +| MATOMO_SITE_{SITE}_TIMEZONE | America/Halifax | The timezone the site is hosted in | +| MATOMO_SITE_{SITE}_TIMEZONE | America/Halifax | The timezone the site is hosted in | +| MATOMO_SITE_{SITE}_USER_EMAIL | admin@example.org | The site administrator email | +| MATOMO_SITE_{SITE}_USER_NAME | {SITE}_admin | The site administrator user | +| MATOMO_SITE_{SITE}_USER_PASS | $2y$10$S38e7HPM9LI3aOIvcnRsfuMCm4ipNP572QsvbCK60upoHVJ61hMrS | The site administrator's password (See how to generate above) | + +[base image]: ../base/README.md [Matomo Documentation]: https://matomo.org/docs/ +[Matomo]: https://matomo.org/ diff --git a/matomo/rootfs/etc/confd/conf.d/config.ini.php.toml b/matomo/rootfs/etc/confd/conf.d/config.ini.php.toml deleted file mode 100644 index 462a89bb..00000000 --- a/matomo/rootfs/etc/confd/conf.d/config.ini.php.toml +++ /dev/null @@ -1,10 +0,0 @@ -[template] -src = "config.ini.php.tmpl" -dest = "/var/www/matomo/config/config.ini.php" -uid = 100 -gid = 101 -mode = "0644" -keys = [ - "/db", - "/site", -] diff --git a/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sql.toml b/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sql.toml deleted file mode 100644 index 4ea6be95..00000000 --- a/matomo/rootfs/etc/confd/conf.d/create-matomo-database.sql.toml +++ /dev/null @@ -1,11 +0,0 @@ -[template] -src = "create-matomo-database.sql.tmpl" -dest = "/var/run/islandora/create-matomo-database.sql" -uid = 0 -gid = 0 -mode = "0600" -keys = [ - "/db", - "/site", - "/user", -] diff --git a/matomo/rootfs/etc/confd/conf.d/default.conf.toml b/matomo/rootfs/etc/confd/conf.d/default.conf.toml index 1df8dbe5..875fe94f 100644 --- a/matomo/rootfs/etc/confd/conf.d/default.conf.toml +++ b/matomo/rootfs/etc/confd/conf.d/default.conf.toml @@ -1,6 +1,6 @@ [template] src = "default.conf.tmpl" -dest = "/etc/nginx/conf.d/default.conf" +dest = "/etc/nginx/http.d/default.conf" uid = 100 gid = 101 mode = "0644" diff --git a/matomo/rootfs/etc/confd/conf.d/setup-environment.sh.toml b/matomo/rootfs/etc/confd/conf.d/setup-environment.sh.toml deleted file mode 100644 index d7fc515b..00000000 --- a/matomo/rootfs/etc/confd/conf.d/setup-environment.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setup-environment.sh.tmpl" -dest = "/var/run/islandora/setup-environment.sh" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/" ] diff --git a/matomo/rootfs/etc/confd/confd.toml b/matomo/rootfs/etc/confd/confd.toml deleted file mode 100644 index eda2d410..00000000 --- a/matomo/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/matomo" diff --git a/matomo/rootfs/etc/confd/templates/config.ini.php.tmpl b/matomo/rootfs/etc/confd/templates/config.ini.php.tmpl deleted file mode 100644 index a33e7847..00000000 --- a/matomo/rootfs/etc/confd/templates/config.ini.php.tmpl +++ /dev/null @@ -1,79 +0,0 @@ -; DO NOT REMOVE THIS LINE -; file automatically generated or modified by Matomo; you can manually override the default values in global.ini.php by redefining them in this file. -[database] -host = {{ getv "/db/host" "mariadb" }} -username = {{ getv "/db/user" "matomo" }} -password = {{ getv "/db/password" "password" }} -dbname = {{ getv "/db/name" "matomo" }} -tables_prefix = "matomo_" - -[General] -force_ssl = 1 -proxy_uri_header = 1 -proxy_client_headers[] = "HTTP_X_FORWARDED_FOR" -proxy_host_headers[] = "HTTP_X_FORWARDED_HOST" -salt = "5a472390550bd59e4428a41aa472137b" -trusted_hosts[] = {{ getv "/site/host" "islandora.isle-dc.localhost" }} - -[PluginsInstalled] -PluginsInstalled[] = "Diagnostics" -PluginsInstalled[] = "Login" -PluginsInstalled[] = "CoreAdminHome" -PluginsInstalled[] = "UsersManager" -PluginsInstalled[] = "SitesManager" -PluginsInstalled[] = "Installation" -PluginsInstalled[] = "Monolog" -PluginsInstalled[] = "Intl" -PluginsInstalled[] = "CorePluginsAdmin" -PluginsInstalled[] = "CoreHome" -PluginsInstalled[] = "WebsiteMeasurable" -PluginsInstalled[] = "IntranetMeasurable" -PluginsInstalled[] = "CoreVisualizations" -PluginsInstalled[] = "Proxy" -PluginsInstalled[] = "API" -PluginsInstalled[] = "Widgetize" -PluginsInstalled[] = "Transitions" -PluginsInstalled[] = "LanguagesManager" -PluginsInstalled[] = "Actions" -PluginsInstalled[] = "Dashboard" -PluginsInstalled[] = "MultiSites" -PluginsInstalled[] = "Referrers" -PluginsInstalled[] = "UserLanguage" -PluginsInstalled[] = "DevicesDetection" -PluginsInstalled[] = "Goals" -PluginsInstalled[] = "Ecommerce" -PluginsInstalled[] = "SEO" -PluginsInstalled[] = "Events" -PluginsInstalled[] = "UserCountry" -PluginsInstalled[] = "GeoIp2" -PluginsInstalled[] = "VisitsSummary" -PluginsInstalled[] = "VisitFrequency" -PluginsInstalled[] = "VisitTime" -PluginsInstalled[] = "VisitorInterest" -PluginsInstalled[] = "RssWidget" -PluginsInstalled[] = "Feedback" -PluginsInstalled[] = "TwoFactorAuth" -PluginsInstalled[] = "CoreUpdater" -PluginsInstalled[] = "CoreConsole" -PluginsInstalled[] = "ScheduledReports" -PluginsInstalled[] = "UserCountryMap" -PluginsInstalled[] = "Live" -PluginsInstalled[] = "CustomVariables" -PluginsInstalled[] = "PrivacyManager" -PluginsInstalled[] = "ImageGraph" -PluginsInstalled[] = "Annotations" -PluginsInstalled[] = "MobileMessaging" -PluginsInstalled[] = "Overlay" -PluginsInstalled[] = "SegmentEditor" -PluginsInstalled[] = "Insights" -PluginsInstalled[] = "Morpheus" -PluginsInstalled[] = "Contents" -PluginsInstalled[] = "BulkTracking" -PluginsInstalled[] = "Resolution" -PluginsInstalled[] = "DevicePlugins" -PluginsInstalled[] = "Heartbeat" -PluginsInstalled[] = "Marketplace" -PluginsInstalled[] = "ProfessionalServices" -PluginsInstalled[] = "UserId" -PluginsInstalled[] = "CustomPiwikJs" -PluginsInstalled[] = "Tour" diff --git a/matomo/rootfs/etc/confd/templates/create-matomo-database.sql.tmpl b/matomo/rootfs/etc/confd/templates/create-matomo-database.sql.tmpl deleted file mode 100644 index 922babc7..00000000 --- a/matomo/rootfs/etc/confd/templates/create-matomo-database.sql.tmpl +++ /dev/null @@ -1,1088 +0,0 @@ --- Create matomo database in mariadb or mysql. -CREATE DATABASE IF NOT EXISTS {{ getv "/db/name" "matomo" }} CHARACTER SET utf8 COLLATE utf8_general_ci; - --- Create matomo_user and grant rights. -CREATE USER IF NOT EXISTS '{{ getv "/db/user" "matomo" }}'@'%' IDENTIFIED BY '{{ getv "/db/password" "password" }}'; -GRANT ALL PRIVILEGES ON {{ getv "/db/name" "matomo" }}.* to '{{ getv "/db/user" "matomo" }}'@'%'; -FLUSH PRIVILEGES; - -USE {{ getv "/db/name" "matomo" }}; - --- MariaDB dump 10.17 Distrib 10.4.13-MariaDB, for Linux (x86_64) --- --- Host: database Database: matomo --- ------------------------------------------------------ --- Server version 10.4.13-MariaDB - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `matomo_access` --- - -DROP TABLE IF EXISTS `matomo_access`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `matomo_access` ( - `idaccess` int(10) unsigned NOT NULL AUTO_INCREMENT, - `login` varchar(100) NOT NULL, - `idsite` int(10) unsigned NOT NULL, - `access` varchar(50) DEFAULT NULL, - PRIMARY KEY (`idaccess`), - KEY `index_loginidsite` (`login`,`idsite`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `matomo_access` --- - -LOCK TABLES `matomo_access` WRITE; -/*!40000 ALTER TABLE `matomo_access` DISABLE KEYS */; -/*!40000 ALTER TABLE `matomo_access` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `matomo_archive_blob_2020_06` --- - -DROP TABLE IF EXISTS `matomo_archive_blob_2020_06`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `matomo_archive_blob_2020_06` ( - `idarchive` int(10) unsigned NOT NULL, - `name` varchar(255) NOT NULL, - `idsite` int(10) unsigned DEFAULT NULL, - `date1` date DEFAULT NULL, - `date2` date DEFAULT NULL, - `period` tinyint(3) unsigned DEFAULT NULL, - `ts_archived` datetime DEFAULT NULL, - `value` mediumblob DEFAULT NULL, - PRIMARY KEY (`idarchive`,`name`), - KEY `index_period_archived` (`period`,`ts_archived`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `matomo_archive_blob_2020_06` --- - -LOCK TABLES `matomo_archive_blob_2020_06` WRITE; -/*!40000 ALTER TABLE `matomo_archive_blob_2020_06` DISABLE KEYS */; -INSERT INTO `matomo_archive_blob_2020_06` VALUES (3,'Actions_actions',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�}P;\n�0 - ����e��Hk���Z����@�)��k�&� - �#��c\\*b4����o�K�Q�(������\"��l�� >��P��<;0�\ZE%O�Z��UI\0�P�>�� @_�kU�_�*DW45����V۝�ls�\")���O;�&��A��)�Ѕb�qt]�'),(3,'Actions_actions_url',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�]�Q\n� D����6Ҏw�l� M� �wo�&H>�������<�u���[D - \n���$����d=�>��\\��A-m��ƨ6�j�quu�E�Gu�d\r��dU9���Ǘ��jNH�v�s���:�z�\Z�e�ݼN.4a|�0�q%��Ӧ�w0O&'),(3,'Actions_downloads',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Actions_outlink',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Actions_sitesearch',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Contents_name_piece',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Contents_piece_name',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'CustomVariables_valueByName',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'DevicePlugins_plugin',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x����\r�0 - �]��K?&�C�7)��DL�d��^�x)�'),(3,'DevicesDetection_os',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2��δ2�N�2�1,����L��r�Rs����2J�N!J֙VF@��P��:L�Z��fZ�A�͡|CC�B�H-��he`U] - 2�Ϻ�\0@$G'),(3,'DevicesDetection_osVersions',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5L;� ��;O@c����\0��@��H��@`h�I[#Q�)v���|�$��������+�`\'og/m��|�yMOJs\n�\\��)��a/$�'),(3,'DevicesDetection_types',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2��δ2�N�2�1,����L��r�Rs��A��VF@��P��:L�B�͠��P��!L�X��K�2����g][ - \0z�\"�'),(3,'Events_action_category',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Events_action_name',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Events_category_action',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Events_category_name',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Events_name_action',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Events_name_category',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goals_ItemsCategory',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goals_ItemsCategory_Cart',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goals_ItemsName',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goals_ItemsName_Cart',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goals_ItemsSku',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goals_ItemsSku_Cart',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goal_-1_days_until_conv',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goal_-1_visits_until_conv',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goal_0_days_until_conv',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goal_0_visits_until_conv',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goal_days_until_conv',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Goal_visits_until_conv',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Referrers_keywordByCampaign',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Referrers_keywordBySearchEngine',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Referrers_searchEngineByKeyword',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Referrers_type',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2��δ2�N�2�1,����L��r�Rs��3� - �JCi�0mj\rҔie7��\r\ra\n\r�\"� ^���Uu-�?��Z\0z�\"�'),(3,'Referrers_urlBySocialNetwork',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Referrers_urlByWebsite',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'Resolution_configuration',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5�1� C�� �\"������\0� � ����i_�ԁ�<$;�V\r���T��N�w&e�g�\"�c*�\"�}槹���azo;��lM�� �r=98��\'i'),(3,'Resolution_resolution',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5LI� �˼�Y���?�� 7.&�� - M��U0j���ŁZ�@Y�\'�D[���#I���v�.�d\'c��W�g��f&m8�Am����>��%N'),(3,'UserCountry_city',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5L�\r� - �%�RZ�١;�j���Dٽ��a��m�\Z�(�jAe}�LR@$�����]��I��p����y�H�;mo���-�?��#Y'),(3,'UserCountry_country',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5L�\r� - �%(�������ď\'��ˇl+5��\",q�DP���$�(I�o��0y�wp��L�g~Lϼ�n$֝¡Z?���&O$'),(3,'UserCountry_region',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5L�\r� - �%�RZ�١;�j���Dٽ��a��m�\Z�(�jAe}�LR@$�����]��I��p����y�H�;mo���-�?��#Y'),(3,'UserId_users',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�K�2���\0O�'),(3,'UserLanguage_language',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x�5LI� � - wFDc��aP$ċG2�.i+ ��7ʼn���d 1�:��-��\n�p�7~:{n��}���D�h{�� ,����U�$%\"'),(3,'VisitorInterest_daysSinceLastVisit',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x���= - ! - ��\"t - ��5n]��صXp������^;th�ۋ� ����ZX�Ĵ�ke�jI���X�s��GZ�s~]J-Ϫba��d�*n���j^[�8��Qb�A)��b$e�$ŀ�+)$+NR,XY�����J�^V&I d��U,� p`1�/s�������~�wط-������O� �YS���Q����$i{��/�'),(3,'VisitorInterest_pageGap',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x���1\n�0 - :\n,�NRi�z:�e - �{�:�l_��r3IvtK�,_A�ح\Zm������!a!��QIT�g7��x)��:*������\"%s�JFJ႕���+)�X��J1ZXf�!Y��o�f�Ne�1�9*]�s~��ŀ'),(3,'VisitorInterest_timeGap',1,'2020-06-01','2020-06-30',3,'2020-06-08 12:56:51','x���1\n�0 - :\n$�q��-�R�Ȗ1������ھ����@�\ni - � - ǎ�-��FmG �P[a^*H��+ԛ}�Sj���?�Y�ӷ#��9I��t�P��,\0�[h��L�r@\Zz�+�#*=��R@\Z{�+��P��<;0�\ZE%O�Z��UI\0�P�>�� @_�kU�_�*DW45����V۝�ls�\")���O;�&��A��)�Ѕb�qt]�'),(6,'Actions_actions_url',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�]�Q\n� D����6Ҏw�l� M� �wo�&H>�������<�u���[D - \n���$����d=�>��\\��A-m��ƨ6�j�quu�E�Gu�d\r��dU9���Ǘ��jNH�v�s���:�z�\Z�e�ݼN.4a|�0�q%��Ӧ�w0O&'),(6,'Actions_downloads',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Actions_outlink',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Actions_sitesearch',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Contents_name_piece',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:51','x�K�2���\0O�'),(6,'Contents_piece_name',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:51','x�K�2���\0O�'),(6,'CustomVariables_valueByName',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'DevicePlugins_plugin',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:51','x����\r�0 - �]��K?&�C�7)��DL�d��^�x)�'),(6,'DevicesDetection_os',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs����2J�N!J֙VF@��P��:L�Z��fZ�A�͡|CC�B�H-��he`U] - 2�Ϻ�\0@$G'),(6,'DevicesDetection_osVersions',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�5L;� ��;O@c����\0��@��H��@`h�I[#Q�)v���|�$��������+�`\'og/m��|�yMOJs\n�\\��)��a/$�'),(6,'DevicesDetection_types',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs��A��VF@��P��:L�B�͠��P��!L�X��K�2����g][ - \0z�\"�'),(6,'Events_action_category',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Events_action_name',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Events_category_action',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Events_category_name',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Events_name_action',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Events_name_category',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goals_ItemsCategory',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goals_ItemsCategory_Cart',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goals_ItemsName',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goals_ItemsName_Cart',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goals_ItemsSku',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goals_ItemsSku_Cart',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goal_-1_days_until_conv',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goal_-1_visits_until_conv',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goal_0_days_until_conv',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goal_0_visits_until_conv',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goal_days_until_conv',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Goal_visits_until_conv',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Referrers_keywordByCampaign',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Referrers_keywordBySearchEngine',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Referrers_searchEngineByKeyword',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Referrers_type',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs��3� - �JCi�0mj\rҔie7��\r\ra\n\r�\"� ^���Uu-�?��Z\0z�\"�'),(6,'Referrers_urlBySocialNetwork',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Referrers_urlByWebsite',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�K�2���\0O�'),(6,'Resolution_configuration',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:51','x�5�1� C�� �\"������\0� � ����i_�ԁ�<$;�V\r���T��N�w&e�g�\"�c*�\"�}槹���azo;��lM�� �r=98��\'i'),(6,'Resolution_resolution',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:51','x�5LI� �˼�Y���?�� 7.&�� - M��U0j���ŁZ�@Y�\'�D[���#I���v�.�d\'c��W�g��f&m8�Am����>��%N'),(6,'UserCountry_city',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�5L�\r� - �%�RZ�١;�j���Dٽ��a��m�\Z�(�jAe}�LR@$�����]��I��p����y�H�;mo���-�?��#Y'),(6,'UserCountry_country',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�5L�\r� - �%(�������ď\'��ˇl+5��\",q�DP���$�(I�o��0y�wp��L�g~Lϼ�n$֝¡Z?���&O$'),(6,'UserCountry_region',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�5L�\r� - �%�RZ�١;�j���Dٽ��a��m�\Z�(�jAe}�LR@$�����]��I��p����y�H�;mo���-�?��#Y'),(6,'UserId_users',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:51','x�K�2���\0O�'),(6,'UserLanguage_language',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x�5LI� � - wFDc��aP$ċG2�.i+ ��7ʼn���d 1�:��-��\n�p�7~:{n��}���D�h{�� ,����U�$%\"'),(6,'VisitorInterest_daysSinceLastVisit',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x���= - ! - ��\"t - ��5n]��صXp������^;th�ۋ� ����ZX�Ĵ�ke�jI���X�s��GZ�s~]J-Ϫba��d�*n���j^[�8��Qb�A)��b$e�$ŀ�+)$+NR,XY�����J�^V&I d��U,� p`1�/s�������~�wط-������O� �YS���Q����$i{��/�'),(6,'VisitorInterest_pageGap',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x���1\n�0 - :\n,�NRi�z:�e - �{�:�l_��r3IvtK�,_A�ح\Zm������!a!��QIT�g7��x)��:*������\"%s�JFJ႕���+)�X��J1ZXf�!Y��o�f�Ne�1�9*]�s~��ŀ'),(6,'VisitorInterest_timeGap',1,'2020-06-08','2020-06-14',2,'2020-06-08 12:56:50','x���1\n�0 - :\n$�q��-�R�Ȗ1������ھ����@�\ni - � - ǎ�-��FmG �P[a^*H��+ԛ}�Sj���?�Y�ӷ#��9I��t�P��,\0�[h��L�r@\Zz�+�#*=��R@\Z{�+qs�ڋ��b��]����`JO]Bsžu)r<��:�t�\r�2A�n^\'�0�\\Ƹ�����}�U{N�'),(8,'Actions_downloads',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Actions_outlink',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Actions_sitesearch',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'CustomVariables_valueByName',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'DevicePlugins_plugin',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x����\r�0 - �]m��u@�C���E���$�'),(8,'DevicesDetection_models',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�5�Q\n� D��@3\rg��,%$���Ļ�bÛ�쮅@�d!�b�X������ݟ� ��|:��f z�N��P�0�k�]���y�b��K�]����)�'),(8,'DevicesDetection_os',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs����2J�N!J֙V�Pl��a��5Ho���u\nX��7�*0�kA�D+��Z�^?��Z\0�$'),(8,'DevicesDetection_osVersions',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs����L��B�B���3� - �J�hKk��L+���)�oU`�ׂ8�VVյ �~ֵ�\0>�$Z'),(8,'DevicesDetection_types',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs��A��V�Pl��a�%T��u\nX��7�*0�kA�D+��Z�^?��Z\0Y�\"�'),(8,'Goals_ItemsCategory',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goals_ItemsCategory_Cart',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goals_ItemsName',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goals_ItemsName_Cart',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goals_ItemsSku',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goals_ItemsSku_Cart',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goal_days_until_conv',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Goal_visits_until_conv',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Referrers_keywordByCampaign',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Referrers_keywordBySearchEngine',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Referrers_searchEngineByKeyword',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Referrers_type',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs��3� - ���6�і� ]�V&�)`S(� - ��̯q� - ��kAz��kkZ(\"�'),(8,'Referrers_urlBySocialNetwork',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Referrers_urlByWebsite',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'Resolution_configuration',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�5�1� - E�� @���������@��bB��B`�y�5m=r�d=�ENX ���(8A�rn;�J��V��g�ԃ�룀��6X�S_0�K�\\��Υ|�9\'@'),(8,'Resolution_resolution',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�5�A\n� - ��h�Q7�,�A��� ��(���NH�a� - �d�]z��|���!��c�G��9�n3�|Ppʳ^�u!,S2 - ��������%%'),(8,'UserCountry_city',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs���� - ����3� - �J�hKk��L+���)�oU`�ׂ8�@êkAz��kk��#0'),(8,'UserCountry_country',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�5��\r� - Cw�|J+��CJ{@��e�\n��,[�1* - ��#��<_#�\"�������Zq���d|��Z�C��f�R#�'),(8,'UserCountry_region',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs���� - ����3� - �J�hKk��L+���)�oU`�ׂ8�@êkAz��kk��#0'),(8,'UserId_users',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2���\0O�'),(8,'UserLanguage_language',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x�K�2��δ2�N�2�1,����L��r�Rs�����<��D%�L+C(6���0��\Z�;���:,`\n��A���� N���Uu-H��um-\0�$$�'),(8,'VisitorInterest_daysSinceLastVisit',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x���= - ! - ��\"t - ��5n]��صXp������^;th�ۋ� ����ZX�Ĵ�ke�jI���X�s��GZ�s~]J-Ϫba��d�*n���j^[�8��Qb�A)��b$e�$ŀ�+)$+NR,XY�����J�^V&I d��U,� p`1�/s�������~�wط-������O� �YS���Q����$i{��/�'),(8,'VisitorInterest_pageGap',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x���1\n�0 - :\n,�NRi�z:�e - �{�:�l_��r3IvtK�,_A�ح\Zm������!a!��QIT�g7��x)��:*������\"%s�JFJ႕���+)�X��J1ZXf�!Y��o�f�Ne�1�9*]�s~��ŀ'),(8,'VisitorInterest_timeGap',1,'2020-06-08','2020-06-08',1,'2020-06-08 12:56:50','x���1\n�0 - :\n$�q��-�R�Ȗ1������ھ����@�\ni - � - ǎ�-��FmG �P[a^*H��+ԛ}�Sj���?�Y�ӷ#��9I��t�P��,\0�[h��L�r@\Zz�+�#*=��R@\Z{�+/dev/null) || exit $? + [[ $count -ne 0 ]] +} + +function post { + local parameters="${1}" + local payload="${2}" + curl -s -c /tmp/cookies -L -X POST "http://localhost/index.php?${parameters}" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "${payload}" &>/dev/null +} + +function add_setting { + local section="${1}" + local key="${2}" + local value="${3}" + if [[ -n "${value}" ]]; then + s6-setuidgid nginx /var/www/matomo/console config:set --section="${section}" --key="${key}" --value="${value}" + fi +} + +function install { + # Simulate user performing install. + post "action=databaseSetup&clientProtocol=https" \ + "type=InnoDB&host=${DB_MYSQL_HOST}&username=${MATOMO_DB_USER}&password=${MATOMO_DB_PASSWORD}&dbname=${MATOMO_DB_NAME}&tables_prefix=&adapter=PDO\MYSQL&submit=Next »" + + post "action=setupSuperUser&clientProtocol=https&module=Installation" \ + "login=${MATOMO_USER_NAME}&password=${MATOMO_USER_PASS}&password_bis=${MATOMO_USER_PASS}&email=${MATOMO_USER_EMAIL}&submit=Next »" + + post "action=firstWebsiteSetup&clientProtocol=https&module=Installation" \ + "siteName=${MATOMO_DEFAULT_NAME}&url=${MATOMO_DEFAULT_HOST}&timezone=${MATOMO_DEFAULT_TIMEZONE}&ecommerce=0&submit=Next »" + + post "action=finished&clientProtocol=https&module=Installation&site_idSite=1&site_name=${MATOMO_DEFAULT_NAME}" \ + "setup_geoip2=1&do_not_track=1&anonymise_ip=1&submit=Continue to Matomo »" + + # Add extra tools plugin. + s6-setuidgid nginx /var/www/matomo/console plugin:activate ExtraTools + + # Add additional configurations. + add_setting General "assume_secure_protocol" "${MATOMO_ASSUME_SECURE_PROTOCOL}" + add_setting General "proxy_client_headers[]" "${MATOMO_PROXY_CLIENT_HEADERS}" + add_setting General "proxy_host_headers" "${MATOMO_PROXY_HOST_HEADERS}" + add_setting General "force_ssl" "${MATOMO_FORCE_SSL}" + add_setting General "proxy_uri_header" "${MATOMO_PROXY_URI_HEADER}" + + # Add subsites. + for site in $(env | grep "MATOMO_SITE_.*_HOST" | cut -f1 -d=); do + # shellcheck disable=SC2001 + name=$(echo "${site}" | sed -e 's/MATOMO_SITE_\(.*\)_HOST/\1/') + s6-setuidgid nginx /var/www/matomo/console site:add --name="${name}" --urls="${!site}" + done +} + +# External processes can look for `/installed` to check if installation is completed. +function finished { + touch /installed + cat <<-EOT + + +##################### +# Install Completed # +##################### +EOT +} + +function main { + # Wait for Nginx to be ready. + s6-svwait -U /run/service/nginx + + if installed; then + echo "Already Installed" + else + echo "Installing" + install + fi + finished +} +main diff --git a/matomo/rootfs/etc/s6-overlay/scripts/matomo-setup.sh b/matomo/rootfs/etc/s6-overlay/scripts/matomo-setup.sh new file mode 100755 index 00000000..43d783f7 --- /dev/null +++ b/matomo/rootfs/etc/s6-overlay/scripts/matomo-setup.sh @@ -0,0 +1,37 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Creates database / user if not already exists. This needs to be seperated as +# we cannot use 'User Defined' variables to select database/tables. +function create_database { + cat <<-EOF | create-database.sh +-- Create matomo database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS ${MATOMO_DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci; + +-- Create matomo_user and grant rights. +CREATE USER IF NOT EXISTS ${MATOMO_DB_USER}@'%' IDENTIFIED BY "${MATOMO_DB_PASSWORD}"; +GRANT ALL PRIVILEGES ON ${MATOMO_DB_NAME}.* to ${MATOMO_DB_USER}@'%'; +FLUSH PRIVILEGES; +EOF +} + +function database_exists { + cat <<-EOF | execute-sql-file.sh +USE '${MATOMO_DB_NAME}'; +EOF +} + +function created_database { + if ! database_exists; then + echo "Creating database: ${MATOMO_DB_NAME}" + create_database + else + echo "Database: ${MATOMO_DB_NAME} already exists" + fi +} + +function main { + created_database +} +main diff --git a/matomo/rootfs/etc/s6-overlay/scripts/set-subsite-defaults.sh b/matomo/rootfs/etc/s6-overlay/scripts/set-subsite-defaults.sh new file mode 100755 index 00000000..387a5804 --- /dev/null +++ b/matomo/rootfs/etc/s6-overlay/scripts/set-subsite-defaults.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -e + +# Update container environment with site specific environment variables: +# +# 1. Get the list of subsites from confd backend. +# 2. For each subsite set container variables if not already defined. +# +# At this point the 'default' site variables have already been updated to match +# the confd backend. As such for any subsite will use those values unless the +# subsite variable is explicitly overriden. + +# Import sites/subsites environment var so we can generate defaults for each site. +cat <("test") { + // This test requires more time that normal. + timeout.convention(ofMinutes(10)) +} diff --git a/matomo/tests/Installation/docker-compose.yml b/matomo/tests/Installation/docker-compose.yml new file mode 100644 index 00000000..694bc321 --- /dev/null +++ b/matomo/tests/Installation/docker-compose.yml @@ -0,0 +1,24 @@ +# file: docker-compose.yml +# +# Tests the following: +# - Site is installed correctly. +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: matomo-installation +services: + mariadb: + <<: *common + image: ${MARIADB:-islandora/mariadb:local} + matomo: + <<: *common + image: ${MATOMO:-islandora/matomo:local} + environment: + MATOMO_DEFAULT_HOST: "https://islandora.dev" + volumes: + - ./test.sh:/test.sh # Test to run. + command: /test.sh # Run test and exit. diff --git a/matomo/tests/Installation/test.sh b/matomo/tests/Installation/test.sh new file mode 100755 index 00000000..ea9c186a --- /dev/null +++ b/matomo/tests/Installation/test.sh @@ -0,0 +1,11 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Run diagnostics, ignore warnings. +echo "Running diagnostics." +cd /var/www/matomo +./console diagnostics:run --ignore-warn + +# All tests were successful +exit 0 diff --git a/matomo/tests/ServiceStartsWithDefaults/docker-compose.yml b/matomo/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..f09fb2aa --- /dev/null +++ b/matomo/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,22 @@ +# file: docker-compose.yml +# +# Tests that the base values for database environment variables can be +# overridden by prefixing them. +# +# `base/rootfs/etc/cont-init.d/00-container-environment-00-init.sh` +version: "3.8" + +name: matomo-servicestartswithdefaults +services: + mariadb: + image: ${MARIADB:-islandora/mariadb:local} + matomo: + image: ${MATOMO:-islandora/matomo:local} + environment: + # Testing without traefik, so we do not have SSL. + MATOMO_FORCE_SSL: 0 + MATOMO_ASSUME_SECURE_PROTOCOL: 0 + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/matomo/tests/ServiceStartsWithDefaults/test.sh b/matomo/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..84a8e0f1 --- /dev/null +++ b/matomo/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,16 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Exit non-zero if database does not exist. +cat <<-EOF | execute-sql-file.sh + use ${DB_NAME} +EOF + +# Wait for access +wait_20x http://localhost:80/index.php + +# All tests were successful +exit 0 diff --git a/milliner/.dockerignore b/milliner/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/milliner/.dockerignore +++ b/milliner/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/milliner/Dockerfile b/milliner/Dockerfile index 50369c33..1bfead93 100644 --- a/milliner/Dockerfile +++ b/milliner/Dockerfile @@ -1,13 +1,23 @@ -# syntax=docker/dockerfile:experimental -FROM local/crayfish:latest +# syntax=docker/dockerfile:1.5.1 +FROM crayfish -RUN --mount=type=cache,target=/root/.composer/cache \ +ARG TARGETARCH + +EXPOSE 8000 + +WORKDIR /var/www/crayfish/Milliner/ + +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=milliner-composer-${TARGETARCH},sharing=locked,target=/root/.composer/cache \ composer install -d /var/www/crayfish/Milliner && \ - ln -s /var/www/crayfish/Milliner/src /var/www/html && \ + ln -s /var/www/crayfish/Milliner/public /var/www/html && \ cleanup.sh -COPY /rootfs / +ENV \ + MILLINER_FCREPO_URL=http://fcrepo:8080/fcrepo/rest \ + MILLINER_FEDORA6=true \ + MILLINER_LOG_LEVEL=info -RUN chown -R nginx:nginx /var/www +COPY --link rootfs / -WORKDIR /var/www/crayfish/Milliner/ +RUN chown -R nginx:nginx /var/www diff --git a/milliner/README.md b/milliner/README.md index 04c024c1..018aff6b 100644 --- a/milliner/README.md +++ b/milliner/README.md @@ -10,11 +10,10 @@ additional settings, volumes, ports, etc. ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------- | :------------------- | :----------------- | :------------------------------------------------------------------------------------------------ | -| MILLINER_DRUPAL_URL | /milliner/drupal/url | drupal:80 | Drupal URL | -| MILLINER_FCREPO_URL | /milliner/fcrepo/url | fcrepo/fcrepo/rest | Fcrepo Rest API URL | -| MILLINER_GEMINI_URL | /milliner/gemini/url | gemini:8000 | Gemini URL | -| MILLINER_LOG_LEVEL | /milliner/log/level | debug | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | +| Environment Variable | Default | Description | +| :------------------- | :----------------------------- | :------------------------------------------------------------------------------------------------ | +| MILLINER_FCREPO_URL | http://fcrepo:8080/fcrepo/rest | Fcrepo Rest API URL | +| MILLINER_FCREPO6 | false | Set to "true" if using Fedora 6 and set to "false" if using Fedora 4 or 5 | +| MILLINER_LOG_LEVEL | info | Log level. Possible Values: debug, info, notice, warning, error, critical, alert, emergency, none | [Milliner]: https://github.com/Islandora/Crayfish/tree/main/Milliner diff --git a/milliner/rootfs/etc/confd/conf.d/config.yaml.toml b/milliner/rootfs/etc/confd/conf.d/config.yaml.toml deleted file mode 100644 index 27b906b8..00000000 --- a/milliner/rootfs/etc/confd/conf.d/config.yaml.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "config.yaml.tmpl" -dest = "/var/www/crayfish/Milliner/cfg/config.yaml" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/log/level", "/fcrepo", "/drupal", "/gemini" ] diff --git a/milliner/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml b/milliner/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml new file mode 100644 index 00000000..52b416d3 --- /dev/null +++ b/milliner/rootfs/etc/confd/conf.d/crayfish_commons.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "crayfish_commons.yaml.tmpl" +dest = "/var/www/crayfish/Milliner/config/packages/crayfish_commons.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/milliner/rootfs/etc/confd/conf.d/monolog.yaml.toml b/milliner/rootfs/etc/confd/conf.d/monolog.yaml.toml new file mode 100644 index 00000000..7be0505b --- /dev/null +++ b/milliner/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "monolog.yaml.tmpl" +dest = "/var/www/crayfish/Milliner/config/packages/monolog.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/milliner/rootfs/etc/confd/conf.d/security.yaml.toml b/milliner/rootfs/etc/confd/conf.d/security.yaml.toml new file mode 100644 index 00000000..30787fd9 --- /dev/null +++ b/milliner/rootfs/etc/confd/conf.d/security.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "security.yaml.tmpl" +dest = "/var/www/crayfish/Milliner/config/packages/security.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/milliner/rootfs/etc/confd/conf.d/services.yaml.toml b/milliner/rootfs/etc/confd/conf.d/services.yaml.toml new file mode 100644 index 00000000..a891ba25 --- /dev/null +++ b/milliner/rootfs/etc/confd/conf.d/services.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "services.yaml.tmpl" +dest = "/var/www/crayfish/Milliner/config/services.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/milliner/rootfs/etc/confd/confd.toml b/milliner/rootfs/etc/confd/confd.toml deleted file mode 100644 index 65d2057c..00000000 --- a/milliner/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/milliner" diff --git a/milliner/rootfs/etc/confd/templates/config.yaml.tmpl b/milliner/rootfs/etc/confd/templates/config.yaml.tmpl deleted file mode 100644 index 578e2e26..00000000 --- a/milliner/rootfs/etc/confd/templates/config.yaml.tmpl +++ /dev/null @@ -1,27 +0,0 @@ ---- - -fedora_base_url: {{ getv "/fcrepo/url" "http://fcrepo:8080/fcrepo/rest" }} -# if drupal_base_url contains a path, be sure to include trailing slash -# or relative paths will not resolve correctly. -drupal_base_url: {{ getv "/drupal/url" "http://drupal:80" }} -gemini_base_url: {{ getv "/gemini/url" "http://gemini:8000" }} - -modified_date_predicate: http://schema.org/dateModified - -strip_format_jsonld: true - -debug: true - -log: - # Valid log levels are: - # debug, info, notice, warning, error, critical, alert, emergency, none - file: "php://stderr" - level: {{ getv "/log/level" "debug" }} - -syn: - # toggles JWT security for service - enable: false - # Path to the syn config file for authentication. - # example can be found here: - # https://github.com/Islandora/Syn/blob/main/conf/syn-settings.example.xml - config: /var/www/crayfish/syn-settings.xml diff --git a/milliner/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl b/milliner/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl new file mode 100644 index 00000000..8df7bf13 --- /dev/null +++ b/milliner/rootfs/etc/confd/templates/crayfish_commons.yaml.tmpl @@ -0,0 +1,3 @@ +crayfish_commons: + fedora_base_uri: '{{ getenv "MILLINER_FCREPO_URL" }}' + syn_config: '/opt/keys/jwt/syn-settings.xml' diff --git a/milliner/rootfs/etc/confd/templates/monolog.yaml.tmpl b/milliner/rootfs/etc/confd/templates/monolog.yaml.tmpl new file mode 100644 index 00000000..30884f19 --- /dev/null +++ b/milliner/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -0,0 +1,8 @@ +monolog: + handlers: + milliner: + type: stream + path: "php://stderr" + # Valid log levels are: + # debug, info, notice, warning, error, critical, alert, emergency, none + level: {{ getenv "MILLINER_LOG_LEVEL" }} diff --git a/milliner/rootfs/etc/confd/templates/security.yaml.tmpl b/milliner/rootfs/etc/confd/templates/security.yaml.tmpl new file mode 100644 index 00000000..6d6ad05f --- /dev/null +++ b/milliner/rootfs/etc/confd/templates/security.yaml.tmpl @@ -0,0 +1,33 @@ +security: + # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers + providers: + users_in_memory: { memory: null } + jwt_user_provider: + id: Islandora\Crayfish\Commons\Syn\JwtUserProvider + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + # To enable Syn, change anonymous to false and uncomment the lines further below + anonymous: false + # Need stateless or it reloads the User based on a token. + stateless: true + + # To enable Syn, uncomment the below 4 lines and change anonymous to false above. + provider: jwt_user_provider + guard: + authenticators: + - Islandora\Crayfish\Commons\Syn\JwtAuthenticator + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#firewalls-authentication + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } diff --git a/milliner/rootfs/etc/confd/templates/services.yaml.tmpl b/milliner/rootfs/etc/confd/templates/services.yaml.tmpl new file mode 100644 index 00000000..17864b3c --- /dev/null +++ b/milliner/rootfs/etc/confd/templates/services.yaml.tmpl @@ -0,0 +1,45 @@ +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration +parameters: + app.fedora_base_url: "{{ getenv "MILLINER_FCREPO_URL" }}" + app.modified_date_predicate: "http://schema.org/dateModified" + app.strip_format_jsonld: true + app.isFedora6: {{ getenv "MILLINER_FEDORA6" }} + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + App\Islandora\Milliner\: + resource: '../src/' + exclude: + - '../src/DependencyInjection/' + - '../src/Entity/' + - '../src/Kernel.php' + - '../src/Tests/' + + App\Islandora\Milliner\Service\MillinerService: + arguments: + $modifiedDatePredicate: '%app.modified_date_predicate%' + $stripFormatJsonld: '%app.strip_format_jsonld%' + $isFedora6: '%app.isFedora6%' + + + # controllers are imported separately to make sure services can be injected + # as action arguments even if you don't extend any base controller class + App\Islandora\Milliner\Controller\MillinerController: + public: false + tags: [ 'controller.service_arguments' ] + + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones + + # A guzzle instance as a service + GuzzleHttp\Client: ~ diff --git a/milliner/tests/ServiceStartsWithDefaults/docker-compose.yml b/milliner/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..8735fc30 --- /dev/null +++ b/milliner/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: matomo-servicestartswithdefaults +services: + milliner: + <<: *common + image: ${MILLINER:-islandora/milliner:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/milliner/tests/ServiceStartsWithDefaults/test.sh b/milliner/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..ea2829b5 --- /dev/null +++ b/milliner/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,8 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# Wait for service to start. +wait_20x http://localhost:8000/ + +# Service must start for us to get to this point. +exit 0 diff --git a/nginx/.dockerignore b/nginx/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/nginx/.dockerignore +++ b/nginx/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/nginx/Dockerfile b/nginx/Dockerfile index b395d84d..695b7c1c 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,29 +1,87 @@ -# syntax=docker/dockerfile:experimental -FROM local/base:latest +# syntax=docker/dockerfile:1.5.1 +FROM base -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh \ - composer \ +ARG TARGETARCH +ARG COMPOSER_VERSION="2.4.4" +ARG COMPOSER_FILE="composer.phar" +ARG COMPOSER_URL="https://getcomposer.org/download/${COMPOSER_VERSION}/${COMPOSER_FILE}" +ARG COMPOSER_SHA256="c252c2a2219956f88089ffc242b42c8cb9300a368fd3890d63940e4fc9652345" + +WORKDIR /var/www + +# https://getcomposer.org/download/ +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=download-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${COMPOSER_URL}" \ + --sha256 "${COMPOSER_SHA256}" \ + && \ + cp "${DOWNLOAD_CACHE_DIRECTORY}/${COMPOSER_FILE}" /usr/bin/composer && \ + chmod a+x /usr/bin/composer && \ + cleanup.sh + +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=nginx-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ + icu-data-full \ nginx \ - php7-ctype \ - php7-curl \ - php7-dom \ - php7-fileinfo \ - php7-fpm \ - php7-gd \ - php7-opcache \ - php7-pdo \ - php7-pdo_mysql \ - php7-pdo_pgsql \ - php7-mysqli \ - php7-session \ - php7-simplexml \ - php7-tokenizer \ - php7-xml \ - php7-xmlwriter \ - php7-xsl \ + php81 \ + php81-ctype \ + php81-curl \ + php81-dom \ + php81-fileinfo \ + php81-fpm \ + php81-gd \ + php81-iconv \ + php81-intl \ + php81-json \ + php81-ldap \ + php81-mbstring \ + php81-mysqli \ + php81-opcache \ + php81-openssl \ + php81-pdo \ + php81-pdo_mysql \ + php81-pdo_pgsql \ + php81-phar \ + php81-session \ + php81-simplexml \ + php81-tokenizer \ + php81-xml \ + php81-xmlreader \ + php81-xmlwriter \ + php81-xsl \ + php81-zip \ && \ + addgroup nginx jwt && \ cleanup.sh -COPY rootfs / +ENV \ + NGINX_CLIENT_BODY_TIMEOUT=60s \ + NGINX_CLIENT_MAX_BODY_SIZE=0 \ + NGINX_ERROR_LOG_LEVEL=warn \ + NGINX_FASTCGI_CONNECT_TIMEOUT=60s \ + NGINX_FASTCGI_READ_TIMEOUT=60s \ + NGINX_FASTCGI_SEND_TIMEOUT=60s \ + NGINX_KEEPALIVE_TIMEOUT=75s \ + NGINX_LINGERING_TIMEOUT=5s \ + NGINX_PROXY_CONNECT_TIMEOUT=60s \ + NGINX_PROXY_READ_TIMEOUT=60s \ + NGINX_PROXY_SEND_TIMEOUT=60s \ + NGINX_SEND_TIMEOUT=60s \ + NGINX_WORKER_CONNECTIONS=1024 \ + NGINX_WORKER_PROCESSES=auto \ + PHP_DEFAULT_SOCKET_TIMEOUT=60 \ + PHP_LOG_LEVEL=notice \ + PHP_LOG_LIMIT=16384 \ + PHP_MAX_EXECUTION_TIME=30 \ + PHP_MAX_FILE_UPLOADS=20 \ + PHP_MAX_INPUT_TIME=60 \ + PHP_MAX_INPUT_VARS=3000 \ + PHP_MEMORY_LIMIT=256M \ + PHP_POST_MAX_SIZE=128M \ + PHP_PROCESS_CONTROL_TIMEOUT=60 \ + PHP_REQUEST_TERMINATE_TIMEOUT=60 \ + PHP_UPLOAD_MAX_FILESIZE=128M + +COPY --link rootfs / diff --git a/nginx/README.md b/nginx/README.md index 1786c045..4cdedbbe 100644 --- a/nginx/README.md +++ b/nginx/README.md @@ -1,6 +1,6 @@ # Nginx -Docker image for [Nginx] version 1.16.1 and [FPM] version 7.3.17. +Docker image for [Nginx] version 1.22.1 and [FPM] version 8.1.15. Please refer to the [Nginx Documentation] and [FPM Documentation] for more in-depth information. @@ -17,32 +17,43 @@ Requires `islandora/base` docker image to build. Please refer to the > N.B. For all of the settings below images that descend from > ``islandora/nginx`` will apply prefix to every setting. So for example -> `JWT_ADMIN_TOKEN` would become `GEMINI_JWT_ADMIN_TOKEN` this is to allow for +> `PHP_LOG_LEVEL` would become `HOUDINI_PHP_LOG_LEVEL` this is to allow for > different settings on a per-service basis. ### Nginx Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------------- | :-------------------------- | :------ | :------------------------------------------------------------------------------------ | -| NGINX_CLIENT_MAX_BODY_SIZE | /nginx/client/max/body/size | 1m | Specifies the maximum accepted body size of a client request | -| NGINX_ERROR_LOG_LEVEL | /nginx/error/log/level | warn | Log Level of Error log | -| NGINX_KEEPALIVE_TIMEOUT | /nginx/keepalive/timeout | 65 | Timeout for keep-alive connections | -| NGINX_WORKER_CONNECTIONS | /nginx/worker/connections | 1024 | The maximum number of simultaneous connections that can be opened by a worker process | -| NGINX_WORKER_PROCESSES | /nginx/worker/processes | auto | Set number of worker processes automatically based on number of CPU cores | +| Environment Variable | Default | Description | +| :---------------------------- | :------ | :------------------------------------------------------------------------------------ | +| NGINX_CLIENT_BODY_TIMEOUT | 60s | Timeout for reading client request body | +| NGINX_CLIENT_MAX_BODY_SIZE | 1m | Specifies the maximum accepted body size of a client request | +| NGINX_ERROR_LOG_LEVEL | warn | Log Level of Error log | +| NGINX_FASTCGI_CONNECT_TIMEOUT | 60s | Timeout for establishing a connection with a FastCGI server | +| NGINX_FASTCGI_READ_TIMEOUT | 60s | Timeout for reading a response from the FastCGI server | +| NGINX_FASTCGI_SEND_TIMEOUT | 60s | Timeout for transmitting a request to the FastCGI server. | +| NGINX_KEEPALIVE_TIMEOUT | 75s | Timeout for keep-alive connections | +| NGINX_LINGERING_TIMEOUT | 5s | The maximum waiting time for more client data to arrive | +| NGINX_PROXY_CONNECT_TIMEOUT | 60s | Timeout for establishing a connection with a proxied server | +| NGINX_PROXY_READ_TIMEOUT | 60s | Timeout for reading a response from the proxied server | +| NGINX_PROXY_SEND_TIMEOUT | 60s | Timeout for transmitting a request to the proxied server | +| NGINX_SEND_TIMEOUT | 60s | Timeout for transmitting a response to the client | +| NGINX_WORKER_CONNECTIONS | 1024 | The maximum number of simultaneous connections that can be opened by a worker process | +| NGINX_WORKER_PROCESSES | auto | Set number of worker processes automatically based on number of CPU cores | ### PHP Settings -| Environment Variable | Etcd Key | Default | Description | -| :------------------------- | :-------------------------- | :------ | :---------------------------------------------------------------- | -| PHP_DEFAULT_SOCKET_TIMEOUT | /php/default/socket/timeout | 60 | Default timeout for socket based streams (seconds) | -| PHP_LOG_LEVEL | /php/log/level | notice | Log level. Possible Values: alert, error, warning, notice, debug | -| PHP_LOG_LIMIT | /php/log/limit | 16384 | Log limit on number of characters in the single line | -| PHP_MAX_EXECUTION_TIME | /php/max/execution/time | 30 | Maximum execution time of each script, in seconds | -| PHP_MAX_FILE_UPLOADS | /php/max/file/uploads | 20 | Maximum number of files that can be uploaded via a single request | -| PHP_MAX_INPUT_TIME | /php/max/input/time | 60 | Maximum amount of time each script may spend parsing request data | -| PHP_MEMORY_LIMIT | /php/memory/limit | 128M | Maximum amount of memory a script may consume | -| PHP_POST_MAX_SIZE | /php/post/max/size | 8M | Maximum size of POST data that PHP will accept | -| PHP_UPLOAD_MAX_FILESIZE | /php/upload/max/filesize | 2M | Maximum allowed size for uploaded files | +| Environment Variable | Default | Description | +| :---------------------------- | :------ | :--------------------------------------------------------------------------------- | +| PHP_DEFAULT_SOCKET_TIMEOUT | 60 | Default timeout for socket based streams (seconds) | +| PHP_LOG_LEVEL | notice | Log level. Possible Values: alert, error, warning, notice, debug | +| PHP_LOG_LIMIT | 16384 | Log limit on number of characters in the single line | +| PHP_MAX_EXECUTION_TIME | 30 | Maximum execution time of each script, in seconds | +| PHP_MAX_FILE_UPLOADS | 20 | Maximum number of files that can be uploaded via a single request | +| PHP_MAX_INPUT_TIME | 60 | Maximum amount of time each script may spend parsing request data | +| PHP_MEMORY_LIMIT | 128M | Maximum amount of memory a script may consume | +| PHP_POST_MAX_SIZE | 128M | Maximum size of POST data that PHP will accept | +| PHP_PROCESS_CONTROL_TIMEOUT | 60 | Timeout for child processes to wait for a reaction on signals from master | +| PHP_REQUEST_TERMINATE_TIMEOUT | 60 | Timeout for serving a single request after which the worker process will be killed | +| PHP_UPLOAD_MAX_FILESIZE | 128M | Maximum allowed size for uploaded files | [FPM Documentation]: https://www.php.net/manual/en/install.fpm.configuration.php [FPM Logging]: https://www.php.net/manual/en/install.fpm.configuration.php diff --git a/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml b/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml index 70161db0..09296d8f 100644 --- a/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml +++ b/nginx/rootfs/etc/confd/conf.d/nginx.conf.toml @@ -4,4 +4,4 @@ dest = "/etc/nginx/nginx.conf" uid = 0 gid = 0 mode = "0644" -keys = [ "/nginx" ] +keys = [ "/" ] diff --git a/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml b/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml index b78e4cfa..bb6c52fd 100644 --- a/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml +++ b/nginx/rootfs/etc/confd/conf.d/php-fpm.conf.toml @@ -1,7 +1,7 @@ [template] src = "php-fpm.conf.tmpl" -dest = "/etc/php7/php-fpm.conf" +dest = "/etc/php81/php-fpm.conf" uid = 0 gid = 0 mode = "0644" -keys = [ "/php" ] +keys = [ "/" ] diff --git a/nginx/rootfs/etc/confd/conf.d/php.ini.toml b/nginx/rootfs/etc/confd/conf.d/php.ini.toml index 0b0bb90c..af932efa 100644 --- a/nginx/rootfs/etc/confd/conf.d/php.ini.toml +++ b/nginx/rootfs/etc/confd/conf.d/php.ini.toml @@ -1,7 +1,7 @@ [template] src = "php.ini.tmpl" -dest = "/etc/php7/php.ini" +dest = "/etc/php81/php.ini" uid = 0 gid = 0 mode = "0644" -keys = [ "/php" ] +keys = [ "/" ] diff --git a/nginx/rootfs/etc/confd/conf.d/www.conf.toml b/nginx/rootfs/etc/confd/conf.d/www.conf.toml index 60b953ea..315b57b9 100644 --- a/nginx/rootfs/etc/confd/conf.d/www.conf.toml +++ b/nginx/rootfs/etc/confd/conf.d/www.conf.toml @@ -1,7 +1,7 @@ [template] src = "www.conf.tmpl" -dest = "/etc/php7/php-fpm.d/www.conf" +dest = "/etc/php81/php-fpm.d/www.conf" uid = 0 gid = 0 mode = "0644" -keys = [ "/php" ] +keys = [ "/" ] diff --git a/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl b/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl index b73fb14c..4ede8774 100644 --- a/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl +++ b/nginx/rootfs/etc/confd/templates/nginx.conf.tmpl @@ -1,13 +1,15 @@ +# /etc/nginx/nginx.conf + user nginx; # Set number of worker processes automatically based on number of CPU cores. -worker_processes {{ getv "/nginx/worker/processes" "auto" }}; +worker_processes {{ getenv "NGINX_WORKER_PROCESSES" }}; # Enables the use of JIT for regular expressions to speed-up their processing. pcre_jit on; # Configures default error logger. -error_log /dev/stderr {{ getv "/nginx/error/log/level" "warn" }}; +error_log /dev/stderr {{ getenv "NGINX_ERROR_LOG_LEVEL" }}; # Includes files with directives to load dynamic modules. include /etc/nginx/modules/*.conf; @@ -16,7 +18,7 @@ include /etc/nginx/modules/*.conf; events { # The maximum number of simultaneous connections that can be opened by # a worker process. - worker_connections {{ getv "/nginx/worker/connections" "1024" }}; + worker_connections {{ getenv "NGINX_WORKER_CONNECTIONS" }}; } http { @@ -27,50 +29,121 @@ http { # Name servers used to resolve names of upstream servers into addresses. # It's also needed when using tcpsocket and udpsocket in Lua modules. - #resolver 208.67.222.222 208.67.220.220; + #resolver 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001; - # Don't tell nginx version to clients. + # Don't tell nginx version to the clients. Default is 'on'. server_tokens off; # Specifies the maximum accepted body size of a client request, as # indicated by the request header Content-Length. If the stated content # length is greater than this size, then the client receives the HTTP - # error code 413. Set to 0 to disable. - client_max_body_size {{ getv "/nginx/client/max/body/size" "0" }}; - - # Timeout for keep-alive connections. Server will close connections after - # this time. - keepalive_timeout {{ getv "/nginx/keepalive/timeout" "65" }}; + # error code 413. Set to 0 to disable. Default is '1m'. + client_max_body_size {{ getenv "NGINX_CLIENT_MAX_BODY_SIZE" }}; + + # Defines a timeout for reading client request body. The timeout is + # set only for a period between two successive read operations, not for + # the transmission of the whole request body. If a client does not + # transmit anything within this time, the request is terminated with the + # 408 (Request Time-out) error. + client_body_timeout {{ getenv "NGINX_CLIENT_BODY_TIMEOUT" }}; + + # Sets a timeout for transmitting a response to the client. The timeout + # is set only between two successive write operations, not for the + # transmission of the whole response. If the client does not receive + # anything within this time, the connection is closed. + send_timeout {{ getenv "NGINX_SEND_TIMEOUT" }}; + + # The first parameter sets a timeout during which a keep-alive client + # connection will stay open on the server side. The zero value disables + # keep-alive client connections. The optional second parameter sets a + # value in the “Keep-Alive: timeout=time” response header field. Two + # parameters may differ. + keepalive_timeout {{ getenv "NGINX_KEEPALIVE_TIMEOUT" }}; + + # When lingering_close is in effect, this directive specifies the maximum + # waiting time for more client data to arrive. If data are not received + # during this time, the connection is closed. Otherwise, the data are + # read and ignored, and nginx starts waiting for more data again. The + # “wait-read-ignore” cycle is repeated, but no longer than specified by + # the lingering_time directive. + lingering_timeout {{ getenv "NGINX_LINGERING_TIMEOUT" }}; # Sendfile copies data between one FD and other from within the kernel, - # which is more efficient than read() + write(). + # which is more efficient than read() + write(). Default is off. sendfile on; - # Don't buffer data-sends (disable Nagle algorithm). - # Good for sending frequent small bursts of data in real time. - tcp_nodelay on; - # Causes nginx to attempt to send its HTTP response head in one packet, - # instead of using partial frames. - #tcp_nopush on; + # instead of using partial frames. Default is 'off'. + tcp_nopush on; + + # Enables the specified protocols. Default is TLSv1 TLSv1.1 TLSv1.2. + # TIP: If you're not obligated to support ancient clients, remove TLSv1.1. + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; # Path of the file with Diffie-Hellman parameters for EDH ciphers. + # TIP: Generate with: `openssl dhparam -out /etc/ssl/nginx/dh2048.pem 2048` #ssl_dhparam /etc/ssl/nginx/dh2048.pem; # Specifies that our cipher suits should be preferred over client ciphers. + # Default is 'off'. ssl_prefer_server_ciphers on; # Enables a shared SSL cache with size that can hold around 8000 sessions. + # Default is 'none'. ssl_session_cache shared:SSL:2m; + # Specifies a time during which a client may reuse the session parameters. + # Default is '5m'. + ssl_session_timeout 1h; + + # Disable TLS session tickets (they are insecure). Default is 'on'. + ssl_session_tickets off; + # Enable gzipping of responses. #gzip on; - # Set the Vary HTTP header as defined in the RFC 2616. + # Set the Vary HTTP header as defined in the RFC 2616. Default is 'off'. gzip_vary on; - # Enable checking the existence of precompressed files. - #gzip_static on; + # Defines a timeout for establishing a connection with a FastCGI server. + # It should be noted that this timeout cannot usually exceed 75 seconds. + fastcgi_connect_timeout {{ getenv "NGINX_FASTCGI_CONNECT_TIMEOUT" }}; + + # Defines a timeout for reading a response from the FastCGI server. The + # timeout is set only between two successive read operations, not for the + # transmission of the whole response. If the FastCGI server does not + # transmit anything within this time, the connection is closed. + fastcgi_read_timeout {{ getenv "NGINX_FASTCGI_READ_TIMEOUT" }}; + + # Sets a timeout for transmitting a request to the FastCGI server. The + # timeout is set only between two successive write operations, not for + # the transmission of the whole request. If the FastCGI server does not + # receive anything within this time, the connection is closed. + fastcgi_send_timeout {{ getenv "NGINX_FASTCGI_SEND_TIMEOUT" }}; + + # Defines a timeout for establishing a connection with a proxied server. + # It should be noted that this timeout cannot usually exceed 75 seconds. + proxy_connect_timeout {{ getenv "NGINX_PROXY_CONNECT_TIMEOUT" }}; + + # Defines a timeout for reading a response from the proxied server. The + # timeout is set only between two successive read operations, not for the + # transmission of the whole response. If the proxied server does not + # transmit anything within this time, the connection is closed. + proxy_read_timeout {{ getenv "NGINX_PROXY_READ_TIMEOUT" }}; + + + # Sets a timeout for transmitting a request to the proxied server. The + # timeout is set only between two successive write operations, not for + # the transmission of the whole request. If the proxied server does not + # receive anything within this time, the connection is closed. + proxy_send_timeout {{ getenv "NGINX_PROXY_SEND_TIMEOUT" }}; + + # Helper variable for proxying websockets. + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + # Specifies the main log format. log_format main '$remote_addr - $remote_user [$time_local] "$request" ' @@ -80,6 +153,14 @@ http { # Sets the path, format, and configuration for a buffered log write. access_log /dev/stdout main; + # Includes virtual hosts configs. - include /etc/nginx/conf.d/*.conf; + include /etc/nginx/http.d/*.conf; + + # WARNING: Don't use this directory for virtual hosts anymore. + # This include will be moved to the root context in Alpine 3.14. + #include /etc/nginx/conf.d/*.conf; } + +# TIP: Uncomment if you use stream module. +#include /etc/nginx/stream.conf; diff --git a/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl b/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl index ab149386..f48f33b9 100644 --- a/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl +++ b/nginx/rootfs/etc/confd/templates/php-fpm.conf.tmpl @@ -14,13 +14,13 @@ ; Pid file ; Note: the default prefix is /var ; Default Value: none -pid = run/php-fpm7.pid +;pid = run/php-fpm81.pid ; Error log file ; If it's set to "syslog", log is sent to syslogd instead of being written ; into a local file. ; Note: the default prefix is /var -; Default Value: log/php7/error.log +; Default Value: log/php81/error.log error_log = /dev/stderr ; syslog_facility is used to specify what type of program is logging the @@ -33,13 +33,13 @@ error_log = /dev/stderr ; syslog_ident is prepended to every message. If you have multiple FPM ; instances running on the same server, you can change the default value ; which must suit common needs. -; Default Value: php-fpm7 -;syslog.ident = php-fpm7 +; Default Value: php-fpm81 +;syslog.ident = php-fpm81 ; Log level ; Possible Values: alert, error, warning, notice, debug ; Default Value: notice -log_level = {{ getv "php/log/level" "notice" }} +log_level = {{ getenv "PHP_LOG_LEVEL" }} ; Log limit on number of characters in the single line (log entry). If the ; line is over the limit, it is wrapped on multiple lines. The limit is for @@ -48,7 +48,7 @@ log_level = {{ getv "php/log/level" "notice" }} ; logging to a file descriptor. It means the new line character is not present ; when logging to syslog. ; Default Value: 1024 -log_limit = {{ getv "php/log/limit" "16384" }} +log_limit = {{ getenv "PHP_LOG_LIMIT" }} ; Log buffering specifies if the log line is buffered which means that the ; line is written in a single write operation. If the value is false, then the @@ -77,7 +77,7 @@ log_limit = {{ getv "php/log/limit" "16384" }} ; Available units: s(econds), m(inutes), h(ours), or d(ays) ; Default Unit: seconds ; Default Value: 0 -;process_control_timeout = 0 +process_control_timeout = {{ getenv "PHP_PROCESS_CONTROL_TIMEOUT" }} ; The maximum number of processes FPM will fork. This has been designed to control ; the global number of processes when using dynamic PM within a lot of pools. @@ -133,4 +133,11 @@ daemonize = no ; ports and different management options. The name of the pool will be ; used in logs and stats. There is no limitation on the number of pools which ; FPM can handle. Your system will tell you anyway :) -include=/etc/php7/php-fpm.d/*.conf + +; Include one or more files. If glob(3) exists, it is used to include a bunch of +; files from a glob(3) pattern. This directive can be used everywhere in the +; file. +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p argument) +; - /usr otherwise +include=/etc/php81/php-fpm.d/*.conf diff --git a/nginx/rootfs/etc/confd/templates/php.ini.tmpl b/nginx/rootfs/etc/confd/templates/php.ini.tmpl index 7afcde7b..3e391aa2 100644 --- a/nginx/rootfs/etc/confd/templates/php.ini.tmpl +++ b/nginx/rootfs/etc/confd/templates/php.ini.tmpl @@ -108,11 +108,6 @@ ; Development Value: E_ALL ; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT -; html_errors -; Default Value: On -; Development Value: On -; Production value: On - ; log_errors ; Default Value: Off ; Development Value: On @@ -290,6 +285,13 @@ implicit_flush = Off ; callback-function. unserialize_callback_func = +; The unserialize_max_depth specifies the default depth limit for unserialized +; structures. Setting the depth limit too high may result in stack overflows +; during unserialization. The unserialize_max_depth ini setting can be +; overridden by the max_depth option on individual unserialize() calls. +; A value of 0 disables the depth limit. +;unserialize_max_depth = 4096 + ; When floats & doubles are serialized, store serialize_precision significant ; digits after the floating point. The default value ensures that when floats ; are decoded with unserialize, the data will remain the same. @@ -305,12 +307,12 @@ serialize_precision = -1 ; http://php.net/open-basedir ;open_basedir = -; This directive allows you to disable certain functions for security reasons. +; This directive allows you to disable certain functions. ; It receives a comma-delimited list of function names. ; http://php.net/disable-functions disable_functions = -; This directive allows you to disable certain classes for security reasons. +; This directive allows you to disable certain classes. ; It receives a comma-delimited list of class names. ; http://php.net/disable-classes disable_classes = @@ -360,6 +362,12 @@ zend.enable_gc = On ; Default: "" ;zend.script_encoding = +; Allows to include or exclude arguments from stack traces generated for exceptions. +; In production, it is recommended to turn this setting on to prohibit the output +; of sensitive information in stack traces +; Default: Off +zend.exception_ignore_args = On + ;;;;;;;;;;;;;;;;; ; Miscellaneous ; ;;;;;;;;;;;;;;;;; @@ -378,7 +386,7 @@ expose_php = On ; Maximum execution time of each script, in seconds ; http://php.net/max-execution-time ; Note: This directive is hardcoded to 0 for the CLI SAPI -max_execution_time = {{ getv "/php/max/execution/time" "30" }} +max_execution_time = {{ getenv "PHP_MAX_EXECUTION_TIME" }} ; Maximum amount of time each script may spend parsing request data. It's a good ; idea to limit this time on productions servers in order to eliminate unexpectedly @@ -388,18 +396,18 @@ max_execution_time = {{ getv "/php/max/execution/time" "30" }} ; Development Value: 60 (60 seconds) ; Production Value: 60 (60 seconds) ; http://php.net/max-input-time -max_input_time = {{ getv "/php/max/input/time" "60" }} +max_input_time = {{ getenv "PHP_MAX_INPUT_TIME" }} ; Maximum input variable nesting level ; http://php.net/max-input-nesting-level ;max_input_nesting_level = 64 ; How many GET/POST/COOKIE input variables may be accepted -;max_input_vars = 1000 +max_input_vars = {{ getenv "PHP_MAX_INPUT_VARS" }} -; Maximum amount of memory a script may consume (128MB) +; Maximum amount of memory a script may consume ; http://php.net/memory-limit -memory_limit = {{ getv "/php/memory/limit" "256M" }} +memory_limit = {{ getenv "PHP_MEMORY_LIMIT" }} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Error handling and logging ; @@ -512,7 +520,7 @@ ignore_repeated_errors = Off ignore_repeated_source = Off ; If this parameter is set to Off, then memory leaks will not be shown (on -; stdout or in the log). This has only effect in a debug compile, and if +; stdout or in the log). This is only effective in a debug compile, and if ; error reporting includes E_WARNING in the allowed list ; http://php.net/report-memleaks report_memleaks = On @@ -541,9 +549,6 @@ report_memleaks = On ; error message as HTML for easier reading. This directive controls whether ; the error message is formatted as HTML or not. ; Note: This directive is hardcoded to Off for the CLI SAPI -; Default Value: On -; Development Value: On -; Production value: On ; http://php.net/html-errors html_errors = On @@ -668,7 +673,7 @@ register_argc_argv = Off ; first used (Just In Time) instead of when the script starts. If these ; variables are not used within a script, having this directive on will result ; in a performance gain. The PHP directive register_argc_argv must be disabled -; for this directive to have any affect. +; for this directive to have any effect. ; http://php.net/auto-globals-jit auto_globals_jit = On @@ -685,7 +690,7 @@ auto_globals_jit = On ; Its value may be 0 to disable the limit. It is ignored if POST data reading ; is disabled through enable_post_data_reading. ; http://php.net/post-max-size -post_max_size = {{ getv "/php/post/max/size" "0" }} +post_max_size = {{ getenv "PHP_POST_MAX_SIZE" }} ; Automatically add files before PHP document. ; http://php.net/auto-prepend-file @@ -727,7 +732,7 @@ default_charset = "UTF-8" ;;;;;;;;;;;;;;;;;;;;;;;;; ; UNIX: "/path1:/path2" -include_path = ".:/usr/share/php7" +include_path = ".:/usr/share/php81" ; ; Windows: "\path1;\path2" ;include_path = ".;c:\php\includes" @@ -837,10 +842,10 @@ file_uploads = On ; Maximum allowed size for uploaded files. ; http://php.net/upload-max-filesize -upload_max_filesize = {{ getv "/php/upload/max/filesize" "128M" }} +upload_max_filesize = {{ getenv "PHP_UPLOAD_MAX_FILESIZE" }} ; Maximum number of files that can be uploaded via a single request -max_file_uploads = {{ getv "/php/max/file/uploads" "20" }} +max_file_uploads = {{ getenv "PHP_MAX_FILE_UPLOADS" }} ;;;;;;;;;;;;;;;;;; ; Fopen wrappers ; @@ -865,7 +870,7 @@ allow_url_include = Off ; Default timeout for socket based streams (seconds) ; http://php.net/default-socket-timeout -default_socket_timeout = {{ getv "/php/default/socket/timeout" "60" }} +default_socket_timeout = {{ getenv "PHP_DEFAULT_SOCKET_TIMEOUT" }} ; If your scripts have to deal with files from Macintosh systems, ; or you are running on a Mac and need to deal with files from @@ -906,13 +911,14 @@ default_socket_timeout = {{ getv "/php/default/socket/timeout" "60" }} ; ;extension=bz2 ;extension=curl +;extension=ffi +;extension=ftp ;extension=fileinfo ;extension=gd2 ;extension=gettext ;extension=gmp ;extension=intl ;extension=imap -;extension=interbase ;extension=ldap ;extension=mbstring ;extension=exif ; Must be after mbstring as it depends on it @@ -1127,37 +1133,6 @@ odbc.defaultlrl = 4096 ; http://php.net/odbc.defaultbinmode odbc.defaultbinmode = 1 -[Interbase] -; Allow or prevent persistent links. -ibase.allow_persistent = 1 - -; Maximum number of persistent links. -1 means no limit. -ibase.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -ibase.max_links = -1 - -; Default database name for ibase_connect(). -;ibase.default_db = - -; Default username for ibase_connect(). -;ibase.default_user = - -; Default password for ibase_connect(). -;ibase.default_password = - -; Default charset for ibase_connect(). -;ibase.default_charset = - -; Default timestamp format. -ibase.timestampformat = "%Y-%m-%d %H:%M:%S" - -; Default date format. -ibase.dateformat = "%Y-%m-%d" - -; Default time format. -ibase.timeformat = "%H:%M:%S" - [MySQLi] ; Maximum number of persistent links. -1 means no limit. @@ -1188,11 +1163,11 @@ mysqli.default_port = 3306 ; http://php.net/mysqli.default-socket mysqli.default_socket = -; Default host for mysql_connect() (doesn't apply in safe mode). +; Default host for mysqli_connect() (doesn't apply in safe mode). ; http://php.net/mysqli.default-host mysqli.default_host = -; Default user for mysql_connect() (doesn't apply in safe mode). +; Default user for mysqli_connect() (doesn't apply in safe mode). ; http://php.net/mysqli.default-user mysqli.default_user = @@ -1656,7 +1631,7 @@ zend.assertions = -1 ; http input encoding. ; mbstring.encoding_translation = On is needed to use this setting. ; If empty, default_charset or input_encoding or mbstring.input is used. -; The precedence is: default_charset < input_encoding < mbsting.http_input +; The precedence is: default_charset < input_encoding < mbstring.http_input ; http://php.net/mbstring.http-input ;mbstring.http_input = @@ -1709,10 +1684,15 @@ zend.assertions = -1 ;mbstring.http_output_conv_mimetype= ; This directive specifies maximum stack depth for mbstring regular expressions. It is similar -; to the pcre.recursion_limit for PCRE. +; to the pcre.recursion_limit for PCRE. ; Default: 100000 ;mbstring.regex_stack_limit=100000 +; This directive specifies maximum retry count for mbstring regular expressions. It is similar +; to the pcre.backtrack_limit for PCRE. +; Default: 1000000 +;mbstring.regex_retry_limit=1000000 + [gd] ; Tell the jpeg decode to ignore warnings and try to create ; a gd image. The warning will then be displayed as notices @@ -1880,6 +1860,10 @@ ldap.max_links = -1 ; errors. ;opcache.mmap_base= +; Facilitates multiple OPcache instances per user (for Windows only). All PHP +; processes with the same cache ID and user share an OPcache instance. +;opcache.cache_id= + ; Enables and sets the second level cache directory. ; It should improve performance when SHM memory is full, at server restart or ; SHM reset. The default "" disables file based caching. @@ -1910,6 +1894,24 @@ ldap.max_links = -1 ; optimizations. ;opcache.opt_debug_level=0 +; Specifies a PHP script that is going to be compiled and executed at server +; start-up. +; http://php.net/opcache.preload +;opcache.preload= + +; Preloading code as root is not allowed for security reasons. This directive +; facilitates to let the preloading to be run as another user. +; http://php.net/opcache.preload_user +;opcache.preload_user= + +; Prevents caching files that are less than this number of seconds old. It +; protects from caching of incompletely updated files. In case all file updates +; on your site are atomic, you may increase performance by setting it to "0". +;opcache.file_update_protection=2 + +; Absolute path used to store shared lockfiles (for *nix only). +;opcache.lockfile_path=/tmp + [curl] ; A default value for the CURLOPT_CAINFO option. This is required to be an ; absolute path. @@ -1933,6 +1935,12 @@ ldap.max_links = -1 ; SSL stream context option. ;openssl.capath= -; Local Variables: -; tab-width: 4 -; End: +[ffi] +; FFI API restriction. Possible values: +; "preload" - enabled in CLI scripts and preloaded files (default) +; "false" - always disabled +; "true" - always enabled +;ffi.enable=preload + +; List of headers files to preload, wildcard patterns allowed. +;ffi.preload= diff --git a/nginx/rootfs/etc/confd/templates/www.conf.tmpl b/nginx/rootfs/etc/confd/templates/www.conf.tmpl index 751aaaf4..682fb32a 100644 --- a/nginx/rootfs/etc/confd/templates/www.conf.tmpl +++ b/nginx/rootfs/etc/confd/templates/www.conf.tmpl @@ -33,7 +33,7 @@ group = nginx ; (IPv6 and IPv4-mapped) on a specific port; ; '/path/to/unix/socket' - to listen on a unix socket. ; Note: This value is mandatory. -listen = /var/run/php-fpm7/php-fpm7.sock +listen = php-fpm81.sock ; Set listen(2) backlog. ; Default Value: 511 (-1 on FreeBSD and OpenBSD) @@ -114,7 +114,7 @@ pm.max_children = 5 ; The number of child processes created on startup. ; Note: Used only when pm is set to 'dynamic' -; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +; Default Value: (min_spare_servers + max_spare_servers) / 2 pm.start_servers = 2 ; The desired minimum number of idle server processes. @@ -229,13 +229,13 @@ pm.max_spare_servers = 3 ; last request memory: 0 ; ; Note: There is a real-time FPM status monitoring sample web page available -; It's available in: /usr/share/php7/fpm/status.html +; It's available in: /usr/share/php81/fpm/status.html ; ; Note: The value must start with a leading slash (/). The value can be ; anything, but it may not be a good idea to use the .php extension or it ; may conflict with a real PHP file. ; Default Value: not set -;pm.status_path = /status +pm.status_path = /status ; The ping URI to call the monitoring page of FPM. If this value is not set, no ; URI will be recognized as a ping page. This could be used to test from outside @@ -256,7 +256,7 @@ pm.max_spare_servers = 3 ; The access log file ; Default: not set -;access.log = log/php7/$pool.access.log +;access.log = log/php81/$pool.access.log ; The access log format. ; The following syntax is allowed @@ -320,7 +320,7 @@ pm.max_spare_servers = 3 ; The log file for slow requests ; Default Value: not set ; Note: slowlog is mandatory if request_slowlog_timeout is set -;slowlog = log/php7/$pool.slow.log +;slowlog = log/php81/$pool.slow.log ; The timeout for serving a single request after which a PHP backtrace will be ; dumped to the 'slowlog' file. A value of '0s' means 'off'. @@ -337,7 +337,7 @@ pm.max_spare_servers = 3 ; does not stop script execution for some reason. A value of '0' means 'off'. ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) ; Default Value: 0 -;request_terminate_timeout = 0 +request_terminate_timeout = {{ getenv "PHP_REQUEST_TERMINATE_TIMEOUT" }} ; The timeout set by 'request_terminate_timeout' ini option is not engaged after ; application calls 'fastcgi_finish_request' or when application has finished and @@ -401,7 +401,7 @@ clear_env = yes ; execute php code. ; Note: set an empty value to allow all extensions. ; Default Value: .php -;security.limit_extensions = .php .php3 .php4 .php5 .php7 +;security.limit_extensions = .php .php3 .php4 .php5 .php81 ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from ; the current environment. @@ -433,6 +433,6 @@ clear_env = yes ; specified at startup with the -d argument ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com ;php_flag[display_errors] = off -;php_admin_value[error_log] = /var/log/php7/$pool.error.log +;php_admin_value[error_log] = /var/log/php81/$pool.error.log ;php_admin_flag[log_errors] = on ;php_admin_value[memory_limit] = 32M diff --git a/nginx/rootfs/etc/cont-init.d/02-fpm-install.sh b/nginx/rootfs/etc/cont-init.d/02-fpm-install.sh deleted file mode 100755 index 1b8b2c5a..00000000 --- a/nginx/rootfs/etc/cont-init.d/02-fpm-install.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -e - -mkdir /run/php-fpm7 &> /dev/null || true diff --git a/nginx/rootfs/etc/cont-init.d/02-ngnix-install.sh b/nginx/rootfs/etc/cont-init.d/02-ngnix-install.sh deleted file mode 100755 index b952b50f..00000000 --- a/nginx/rootfs/etc/cont-init.d/02-ngnix-install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -e - -mkdir /run/nginx &> /dev/null || true - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /var/log/nginx/access.log -chown nginx:nginx /var/log/nginx/access.log - -ln -sf /dev/stderr /var/log/nginx/error.log -chown nginx:nginx /var/log/nginx/error.log diff --git a/nginx/rootfs/etc/nginx/http.d/default.conf b/nginx/rootfs/etc/nginx/http.d/default.conf new file mode 100644 index 00000000..23ee964e --- /dev/null +++ b/nginx/rootfs/etc/nginx/http.d/default.conf @@ -0,0 +1,17 @@ +# This is a default site configuration which will simply return 404, preventing +# chance access to any other virtualhost. +server { + listen 80 default_server; + listen [::]:80 default_server; + + # Everything is a 404 + location / { + return 404; + } + + # You may need this to prevent return 404 recursion. + location = /404.html { + internal; + } + include /etc/nginx/shared/fpm.conf; +} diff --git a/nginx/rootfs/etc/nginx/shared/fpm.conf b/nginx/rootfs/etc/nginx/shared/fpm.conf new file mode 100644 index 00000000..d191bc7c --- /dev/null +++ b/nginx/rootfs/etc/nginx/shared/fpm.conf @@ -0,0 +1,10 @@ +# Used to validate that PHP-FPM is in a ready state. +# Not accessible outside of the container. +location ~ ^/(status|ping)$ { + allow 127.0.0.1; + deny all; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_pass unix:/var/run/php-fpm81/php-fpm81.sock; +} diff --git a/nginx/rootfs/etc/nginx/shared/fpm.server.conf b/nginx/rootfs/etc/nginx/shared/fpm.server.conf new file mode 100644 index 00000000..a1fb24cd --- /dev/null +++ b/nginx/rootfs/etc/nginx/shared/fpm.server.conf @@ -0,0 +1,4 @@ +server { + listen 80; + include /etc/nginx/shared/fpm.conf; +} diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/environment-override-nginx b/nginx/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/environment-override-nginx new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/environment-override-php b/nginx/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/environment-override-php new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/dependencies.d/container-environment b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/type b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/type @@ -0,0 +1 @@ +oneshot diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/up b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/up new file mode 100755 index 00000000..df6c78af --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-nginx/up @@ -0,0 +1,2 @@ +# Allow NGINX_ERROR_LOG_LEVEL to be overridden by DRUPAL_NGINX_ERROR_LOG_LEVEL, etc. +/usr/local/bin/confd-override-environment.sh --prefix NGINX diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/dependencies.d/container-environment b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/type b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/type @@ -0,0 +1 @@ +oneshot diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/up b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/up new file mode 100755 index 00000000..5072ab53 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/environment-override-php/up @@ -0,0 +1,2 @@ +# Allow PHP_LOG_LEVEL to be overriden by DRUPAL_PHP_LOG_LEVEL, etc. +/usr/local/bin/confd-override-environment.sh --prefix PHP diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/dependencies.d/base b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/dependencies.d/base new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/type b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/up b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/up new file mode 100755 index 00000000..3c6248db --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm-setup/up @@ -0,0 +1,2 @@ +# Create the folder to house the PID file and socket. +mkdir -p /run/php-fpm81 diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/data/check b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/data/check new file mode 100755 index 00000000..69d28f51 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/data/check @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e + +# Wait for Socket to exist. +while ! test -S /run/php-fpm81/php-fpm81.sock; do sleep 1; done + +# Wait for PID file to exist. +while ! test -f /run/php-fpm81/php-fpm81.pid; do sleep 1; done diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/data/notification-fd b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/data/notification-fd new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/data/notification-fd @@ -0,0 +1 @@ +3 diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/dependencies.d/fpm-setup b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/dependencies.d/fpm-setup new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/dependencies.d/ready b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/finish b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/notification-fd b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/notification-fd new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/notification-fd @@ -0,0 +1 @@ +3 diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/run b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/run new file mode 100755 index 00000000..4f5883df --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/run @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e +exec s6-notifyoncheck -d -t 30000 -n 1 /usr/sbin/php-fpm81 \ + --pid /var/run/php-fpm81/php-fpm81.pid \ + --prefix /var/run/php-fpm81 \ + --fpm-config /etc/php81/php-fpm.conf diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/type b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/fpm/type @@ -0,0 +1 @@ +longrun diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/dependencies.d/base b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/dependencies.d/base new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/type b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/up b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/up new file mode 100755 index 00000000..814890e3 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx-setup/up @@ -0,0 +1,2 @@ +# Create the folder to house the PID file. +mkdir -p /run/nginx diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check new file mode 100755 index 00000000..02fd7255 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -e + +# Wait for PID file to exist. +while ! test -f /run/nginx/nginx.pid; do sleep 1; done + +# Wait for PHP-FPM to report it has started. +s6-svwait -U /run/service/fpm + +# Block until PHP-FPM is confirmed to be working. +while ! curl -L --silent --output --fail 'http://localhost/status' --output /dev/null; do sleep 1; done diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/fpm b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/fpm new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/nginx-setup b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/nginx-setup new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/ready b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/notification-fd b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/notification-fd new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/notification-fd @@ -0,0 +1 @@ +3 diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/run new file mode 100755 index 00000000..65719fcb --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +exec s6-notifyoncheck -t 30000 -n 1 /usr/sbin/nginx diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/type b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/type @@ -0,0 +1 @@ +longrun diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/fpm b/nginx/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/fpm new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nginx b/nginx/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nginx new file mode 100644 index 00000000..e69de29b diff --git a/nginx/rootfs/etc/services.d/fpm/finish b/nginx/rootfs/etc/services.d/fpm/finish deleted file mode 100644 index 9030da41..00000000 --- a/nginx/rootfs/etc/services.d/fpm/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh: -s6-svscanctl -t /var/run/s6/services diff --git a/nginx/rootfs/etc/services.d/fpm/run b/nginx/rootfs/etc/services.d/fpm/run deleted file mode 100644 index 3d5b066c..00000000 --- a/nginx/rootfs/etc/services.d/fpm/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -/usr/sbin/php-fpm7 diff --git a/nginx/rootfs/etc/services.d/nginx/finish b/nginx/rootfs/etc/services.d/nginx/finish deleted file mode 100644 index 9030da41..00000000 --- a/nginx/rootfs/etc/services.d/nginx/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh: -s6-svscanctl -t /var/run/s6/services diff --git a/nginx/rootfs/etc/services.d/nginx/run b/nginx/rootfs/etc/services.d/nginx/run deleted file mode 100644 index 7503678e..00000000 --- a/nginx/rootfs/etc/services.d/nginx/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -/usr/sbin/nginx diff --git a/nginx/tests/ServiceStartsWithDefaults/docker-compose.yml b/nginx/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..d683addb --- /dev/null +++ b/nginx/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: nginx-servicestartswithdefaults +services: + nginx: + <<: *common + image: ${NGINX:-islandora/nginx:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/nginx/tests/ServiceStartsWithDefaults/test.sh b/nginx/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..0f620b9c --- /dev/null +++ b/nginx/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,8 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# Wait for Nginx to be ready. +s6-svwait -U /run/service/nginx + +# Service must start for us to get to this point. +exit 0 diff --git a/postgresql/.dockerignore b/postgresql/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/postgresql/.dockerignore +++ b/postgresql/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/postgresql/Dockerfile b/postgresql/Dockerfile index 65559a2f..15e5bb76 100644 --- a/postgresql/Dockerfile +++ b/postgresql/Dockerfile @@ -1,20 +1,22 @@ -# syntax=docker/dockerfile:experimental -FROM local/base:latest +# syntax=docker/dockerfile:1.5.1 +FROM base -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh \ +ARG TARGETARCH + +EXPOSE 5432 + +# Platform specific does require arch specific identifier. +RUN --mount=type=cache,id=postgresql-apk-${TARGETARCH},sharing=locked,target=/var/cache/apk \ + apk add \ postgresql \ postgresql-client \ && \ - mkdir -p /var/lib/postgresql/data && \ + mkdir -p /var/lib/postgresql/data /etc/postgresql && \ chown -R postgres:postgres /var/lib/postgresql && \ chmod 700 /var/lib/postgresql/data && \ - mkdir -p /etc/postgresql && \ cleanup.sh -ENV PGDATA /var/lib/postgresql/data - -EXPOSE 5432 +ENV \ + PGDATA=/var/lib/postgresql/data -COPY rootfs / +COPY --link rootfs / diff --git a/postgresql/README.md b/postgresql/README.md index 71ff3cea..c334b272 100644 --- a/postgresql/README.md +++ b/postgresql/README.md @@ -1,6 +1,6 @@ # PostgreSQL -Docker image for [PostgreSQL] version 12.2 +Docker image for [PostgreSQL] version 15.1 Please refer to the [PostgreSQL Documentation] for more in-depth information. @@ -25,10 +25,16 @@ Requires `islandora/base` docker image to build. Please refer to the ## Settings -| Environment Variable | Etcd Key | Default | Description | -| :----------------------- | :------------------------ | :------- | :------------------------------------- | -| POSTGRESQL_ROOT_USER | /postgresql/root/user | root | The name of root user account | -| POSTGRESQL_ROOT_PASSWORD | /postgresql/root/password | password | The password for the root user account | +### Database Settings +Please see the documentation in the [base image] for more information about the +default database connection configuration. + +| Environment Variable | Default | Description | +| :----------------------- | :------ | :------------------------------------------------------------------------------------ | +| POSTGRESQL_ROOT_USER | | The database root user password. Defaults to `DB_ROOT_PASSWORD` | +| POSTGRESQL_ROOT_PASSWORD | | The database root user (used to create the site database). Defaults to `DB_ROOT_USER` | + +[base image]: ../base/README.md [PostgreSQL Documentation]: https://www.postgresql.org/docs/ [PostgreSQL]: https://www.postgresql.org/ diff --git a/postgresql/rootfs/etc/confd/conf.d/pg_hba.conf.toml b/postgresql/rootfs/etc/confd/conf.d/pg_hba.conf.toml index 6e0f761e..df5268bd 100644 --- a/postgresql/rootfs/etc/confd/conf.d/pg_hba.conf.toml +++ b/postgresql/rootfs/etc/confd/conf.d/pg_hba.conf.toml @@ -4,4 +4,4 @@ dest = "/var/lib/postgresql/data/pg_hba.conf" uid = 70 gid = 70 mode="0644" -keys = [ "/root" ] +keys = [ "/" ] diff --git a/postgresql/rootfs/etc/confd/conf.d/postgresql.conf.toml b/postgresql/rootfs/etc/confd/conf.d/postgresql.conf.toml index ab9fa82e..9ca7e634 100644 --- a/postgresql/rootfs/etc/confd/conf.d/postgresql.conf.toml +++ b/postgresql/rootfs/etc/confd/conf.d/postgresql.conf.toml @@ -4,4 +4,4 @@ dest = "/var/lib/postgresql/data/postgresql.conf" uid = 70 gid = 70 mode="0644" -keys = [ "/root" ] +keys = [ "/" ] diff --git a/postgresql/rootfs/etc/confd/conf.d/setup-environment.sh.toml b/postgresql/rootfs/etc/confd/conf.d/setup-environment.sh.toml deleted file mode 100644 index d7fc515b..00000000 --- a/postgresql/rootfs/etc/confd/conf.d/setup-environment.sh.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "setup-environment.sh.tmpl" -dest = "/var/run/islandora/setup-environment.sh" -uid = 0 -gid = 0 -mode = "0700" -keys = [ "/" ] diff --git a/postgresql/rootfs/etc/confd/confd.toml b/postgresql/rootfs/etc/confd/confd.toml deleted file mode 100644 index ca7a5bb9..00000000 --- a/postgresql/rootfs/etc/confd/confd.toml +++ /dev/null @@ -1,6 +0,0 @@ -backend = "env" -confdir = "/etc/confd" -log-level = "debug" -interval = 600 -noop = false -prefix = "/postgresql" diff --git a/postgresql/rootfs/etc/confd/templates/setup-environment.sh.tmpl b/postgresql/rootfs/etc/confd/templates/setup-environment.sh.tmpl deleted file mode 100644 index 635a9ce7..00000000 --- a/postgresql/rootfs/etc/confd/templates/setup-environment.sh.tmpl +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -with-contenv -foreground { - # We add / update the environment defined for the container, - # this allows our other initialization and service scripts - # use these settings; but does not change the existing - # environment as seen by linked containers. - # Variables can only be seen when using '#!/usr/bin/with-contenv' - s6-env -i - POSTGRESQL_ROOT_USER="{{ getv "/root/user" "root" }}" - POSTGRESQL_ROOT_PASSWORD="{{ getv "/root/password" "password" }}" - s6-dumpenv -- /var/run/s6/container_environment -} diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-root-user b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/database-defaults/dependencies.d/set-root-user new file mode 100644 index 00000000..e69de29b diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/dependencies.d/postgresql-setup b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/dependencies.d/postgresql-setup new file mode 100644 index 00000000..e69de29b diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/finish b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/run b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/run new file mode 100755 index 00000000..7aaf58d8 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/run @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e +exec with-contenv \ + importas -i PGDATA PGDATA \ + s6-setuidgid \ + postgres postgres diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/type b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgres/type @@ -0,0 +1 @@ +longrun diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/dependencies.d/ready b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/type b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/up b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/up new file mode 100755 index 00000000..3814fba3 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/postgresql-setup/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/postgresql-setup.sh diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/dependencies.d/container-environment b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/type b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/type @@ -0,0 +1 @@ +oneshot diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/up b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/up new file mode 100755 index 00000000..63b7d313 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/set-root-user/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/set-root-user.sh diff --git a/postgresql/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/postgres b/postgresql/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/postgres new file mode 100644 index 00000000..e69de29b diff --git a/postgresql/rootfs/etc/cont-init.d/03-postgresql-setup.sh b/postgresql/rootfs/etc/s6-overlay/scripts/postgresql-setup.sh similarity index 52% rename from postgresql/rootfs/etc/cont-init.d/03-postgresql-setup.sh rename to postgresql/rootfs/etc/s6-overlay/scripts/postgresql-setup.sh index 3e87cbf3..1523bd14 100755 --- a/postgresql/rootfs/etc/cont-init.d/03-postgresql-setup.sh +++ b/postgresql/rootfs/etc/s6-overlay/scripts/postgresql-setup.sh @@ -1,15 +1,16 @@ -#!/usr/bin/with-contenv bash +#!/command/with-contenv bash +# shellcheck shell=bash set -e # Make run directory if it does not exist. -mkdir /run/postgresql &> /dev/null || true +mkdir /run/postgresql &>/dev/null || true chown postgres:postgres /run/postgresql # If no database has been created yet. if [[ ! -f "${PGDATA}/PG_VERSION" ]]; then - # Make sure the ${PGDATA} directory is empty so the init can run successfully. - rm -fr ${PGDATA}/* - s6-setuidgid postgres bash -c "initdb --username='${POSTGRESQL_ROOT_USER}' --pwfile=<(echo '${POSTGRESQL_ROOT_PASSWORD}')" + # Make sure the ${PGDATA} directory is empty so the init can run successfully. + rm -fr "${PGDATA:?}"/* + s6-setuidgid postgres bash -c "initdb --username='${DB_ROOT_USER}' --pwfile=<(echo '${DB_ROOT_PASSWORD}')" # Rerun the confd to restore any files that it would have written to the ${PGDATA} directory. - confd-render-templates.sh + confd-render-templates.sh -- -onetime -sync-only fi diff --git a/postgresql/rootfs/etc/s6-overlay/scripts/set-root-user.sh b/postgresql/rootfs/etc/s6-overlay/scripts/set-root-user.sh new file mode 100755 index 00000000..4b68ae60 --- /dev/null +++ b/postgresql/rootfs/etc/s6-overlay/scripts/set-root-user.sh @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Use what has been provided by the user or default to the derived values. +cat < N.B. Configuration list was generated by searching for all instances of +> `$this->settings['some_setting']` in the riprap repository. When upgrading +> riprap commit be sure to check that the options for configuration have been +> updated appropriately along with their defaults. + +### Database Settings + +[Riprap] can optionally make use of different database backends. Please see +the documentation in the [base image] for more information about the default +database connection configuration. + +Aside from `RIPRAP_DB_DRIVER`, the following settings are only used if +`RIPRAP_DB_DRIVER` is set to `mysql` or `postgresql`. + +| Environment Variable | Default | Description | +| :------------------- | :------- | :------------------------------------------------------------ | +| RIPRAP_DB_DRIVER | sqlite | The database driver either 'sqlite', 'mysql', or 'postgresql' | +| RIPRAP_DB_NAME | riprap | The name of the database | +| RIPRAP_DB_PASSWORD | password | The database users password | +| RIPRAP_DB_USER | riprap | The database user | + +## Updating + +You can change the commit used for riprap by modifying the build argument +`COMMIT` and `SHA256` in the `Dockerfile` shown as `XXXXXXXXXXXX` in the +following snippet: + +```Dockerfile +ARG COMMIT=XXXXXXXXXXXX +#... +ARG SHA256=XXXXXXXXXXXX +``` + +You can generate the `SHA256` with the following commands: + +```bash +COMMIT=$(cat riprap/Dockerfile | grep -o 'COMMIT=.*' | cut -f2 -d=) +FILE=$(cat riprap/Dockerfile | grep -o 'FILE=.*' | cut -f2 -d=) +URL=$(cat riprap/Dockerfile | grep -o 'URL=.*' | cut -f2 -d=) +FILE=$(eval "echo $FILE") +URL=$(eval "echo $URL") +wget --quiet "${URL}" +shasum -a 256 "${FILE}" | cut -f1 -d' ' +rm "${FILE}" +``` + +[base image]: ../base/README.md +[Riprap Documentation]: https://github.com/mjordan/riprap#riprap +[Riprap Plugin Documentation]: https://github.com/mjordan/riprap/blob/master/docs/plugins.md +[Riprap Plugin Overview]: https://github.com/mjordan/riprap#plugins +[Riprap Plugins]: https://github.com/mjordan/riprap/tree/master/src/Plugin +[Riprap]: https://github.com/mjordan/riprap diff --git a/riprap/rootfs/etc/confd/conf.d/.env.toml b/riprap/rootfs/etc/confd/conf.d/.env.toml new file mode 100644 index 00000000..a32ad9d8 --- /dev/null +++ b/riprap/rootfs/etc/confd/conf.d/.env.toml @@ -0,0 +1,7 @@ +[template] +src = ".env.tmpl" +dest = "/var/www/riprap/.env" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/riprap/rootfs/etc/confd/conf.d/cron_config.yml.toml b/riprap/rootfs/etc/confd/conf.d/cron_config.yml.toml new file mode 100644 index 00000000..4cf87818 --- /dev/null +++ b/riprap/rootfs/etc/confd/conf.d/cron_config.yml.toml @@ -0,0 +1,7 @@ +[template] +src = "cron_config.yml.tmpl" +dest = "/var/www/riprap/cron_config.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/riprap/rootfs/etc/confd/conf.d/doctrine.yaml.toml b/riprap/rootfs/etc/confd/conf.d/doctrine.yaml.toml new file mode 100644 index 00000000..7ac8dcbb --- /dev/null +++ b/riprap/rootfs/etc/confd/conf.d/doctrine.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "doctrine.yaml.tmpl" +dest = "/var/www/riprap/config/packages/doctrine.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/riprap/rootfs/etc/confd/conf.d/monolog.yaml.toml b/riprap/rootfs/etc/confd/conf.d/monolog.yaml.toml new file mode 100644 index 00000000..ddeb9511 --- /dev/null +++ b/riprap/rootfs/etc/confd/conf.d/monolog.yaml.toml @@ -0,0 +1,7 @@ +[template] +src = "monolog.yaml.tmpl" +dest = "/var/www/riprap/config/packages/dev/monolog.yaml" +uid = 100 +gid = 101 +mode = "0644" +keys = [ "/" ] diff --git a/riprap/rootfs/etc/confd/templates/.env.tmpl b/riprap/rootfs/etc/confd/templates/.env.tmpl new file mode 100644 index 00000000..1e9ecdd7 --- /dev/null +++ b/riprap/rootfs/etc/confd/templates/.env.tmpl @@ -0,0 +1,35 @@ +# This file is a "template" of which env vars need to be defined for your application +# Copy this file to .env file for development, create environment variables when deploying to production +# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration + +###> symfony/framework-bundle ### +APP_ENV={{ getenv "RIPRAP_APP_ENV" }} +APP_SECRET={{ getenv "RIPRAP_APP_SECRET" }} +{{ if ne (getenv "RIPRAP_TRUSTED_PROXIES") "" }} +TRUSTED_PROXIES={{ getenv "RIPRAP_TRUSTED_PROXIES" }} +{{ end }} +{{ if ne (getenv "RIPRAP_TRUSTED_HOSTS") "" }} +TRUSTED_HOSTS={{ getenv "RIPRAP_TRUSTED_HOSTS" }} +{{ end }} +###< symfony/framework-bundle ### + +###> doctrine/doctrine-bundle ### +# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url +# Configure your db driver and server_version in config/packages/doctrine.yaml +{{ if eq (getenv "DB_DRIVER") "sqlite" }} +DATABASE_URL=sqlite:///%kernel.project_dir%/var/data.db +{{ end }} +{{ if eq (getenv "DB_DRIVER") "mysql" }} +DATABASE_URL=mysql://{{ getenv "RIPRAP_DB_USER" }}:{{ getenv "RIPRAP_DB_PASSWORD" }}@{{ getenv "DB_MYSQL_HOST" }}:{{ getenv "DB_MYSQL_PORT" }}/{{ getenv "RIPRAP_DB_NAME" }} +{{ end }} +{{ if eq (getenv "DB_DRIVER") "postgresql" }} +DATABASE_URL=pgsql://{{ getenv "RIPRAP_DB_USER" }}:{{ getenv "RIPRAP_DB_PASSWORD" }}@{{ getenv "DB_POSTGRESQL_HOST" }}:{{ getenv "DB_POSTGRESQL_PORT" }}/{{ getenv "RIPRAP_DB_NAME" }} +{{ end }} +###< doctrine/doctrine-bundle ### + +###> symfony/swiftmailer-bundle ### +# For Gmail as a transport, use: "gmail://username:password@localhost" +# For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode=" +# Delivery is disabled by default via "null://localhost" +MAILER_URL={{ getenv "RIPRAP_MAILER_URL" }} +###< symfony/swiftmailer-bundle ### diff --git a/riprap/rootfs/etc/confd/templates/cron_config.yml.tmpl b/riprap/rootfs/etc/confd/templates/cron_config.yml.tmpl new file mode 100644 index 00000000..91aabb01 --- /dev/null +++ b/riprap/rootfs/etc/confd/templates/cron_config.yml.tmpl @@ -0,0 +1,40 @@ +# Riprap config file used by the crond service. +# +# Requires that the "Riprap resource list" View be enabled in +# the Islandora instance. This View is bundled with the Islandora Riprap +# module. +# +# This plugin is agnostic to which media have fixity event checks performed +# on them. The filters in the "Riprap resource list" View determine that. +# See the View's filter criteria GUI for examples. + +digest_command: '{{ getenv "RIPRAP_CONFIG_DIGEST_COMMAND" }}' +drupal_baseurl: '{{ getenv "RIPRAP_CONFIG_DRUPAL_BASEURL" }}' +drupal_content_types: {{ getenv "RIPRAP_CONFIG_DRUPAL_CONTENT_TYPES" }} +drupal_file_fieldnames: {{ getenv "RIPRAP_CONFIG_DRUPAL_FILE_FIELDNAMES" }} +drupal_media_auth: {{ getenv "RIPRAP_CONFIG_DRUPAL_MEDIA_AUTH" }} +drupal_media_tags: {{ getenv "RIPRAP_CONFIG_DRUPAL_MEDIA_TAGS" }} +drupal_password: '{{ getenv "RIPRAP_CONFIG_DRUPAL_PASSWORD" }}' +drupal_user: '{{ getenv "RIPRAP_CONFIG_DRUPAL_USER" }}' +email_from: '{{ getenv "RIPRAP_CONFIG_EMAIL_FROM" }}' +email_to: '{{ getenv "RIPRAP_CONFIG_EMAIL_TO" }}' +failures_log_path: '{{ getenv "RIPRAP_CONFIG_FAILURES_LOG_PATH" }}' +fedoraapi_digest_header_leader_pattern: '{{ getenv "RIPRAP_CONFIG_FEDORAAPI_DIGEST_HEADER_LEADER_PATTERN" }}' +fedoraapi_method: '{{ getenv "RIPRAP_CONFIG_FEDORAAPI_METHOD" }}' +fixity_algorithm: '{{ getenv "RIPRAP_CONFIG_FIXITY_ALGORITHM" }}' +gemini_auth_header: '{{ getenv "RIPRAP_CONFIG_GEMINI_AUTH_HEADER" }}' +gemini_endpoint: '{{ getenv "RIPRAP_CONFIG_GEMINI_ENDPOINT" }}' +jsonapi_authorization_headers: '{{ getenv "RIPRAP_CONFIG_JSONAPI_AUTHORIZATION_HEADERS" }}' +jsonapi_pager_data_file_path: '{{ getenv "RIPRAP_CONFIG_JSONAPI_PAGER_DATA_FILE_PATH" }}' +jsonapi_page_size: {{ getenv "RIPRAP_CONFIG_JSONAPI_PAGE_SIZE" }} +max_resources: {{ getenv "RIPRAP_CONFIG_MAX_RESOURCES" }} +output_csv_path: '{{ getenv "RIPRAP_CONFIG_OUTPUT_CSV_PATH" }}' +plugins.fetchdigest: '{{ getv "/config/plugins.fetchdigest" (getenv "RIPRAP_CONFIG_PLUGINS_FETCHDIGEST") }}' +plugins.fetchresourcelist: {{ getv "/config/plugins.fetchresourcelist" (getenv "RIPRAP_CONFIG_PLUGINS_FETCHRESOURCELIST") }} +plugins.persist: '{{ getv "/config/plugins.persist" (getenv "RIPRAP_CONFIG_PLUGINS_PERSIST") }}' +plugins.postcheck: {{ getv "/config/plugins.postcheck" (getenv "RIPRAP_CONFIG_PLUGINS_POSTCHECK") }} +resource_dir_paths: {{ getenv "RIPRAP_CONFIG_RESOURCE_DIR_PATHS" }} +resource_list_path: {{ getenv "RIPRAP_CONFIG_RESOURCE_LIST_PATH" }} +thin: {{ getenv "RIPRAP_CONFIG_THIN" }} +use_fedora_urls: {{ getenv "RIPRAP_CONFIG_USE_FEDORA_URLS" }} +views_pager_data_file_path: '{{ getenv "RIPRAP_CONFIG_VIEWS_PAGER_DATA_FILE_PATH" }}' diff --git a/riprap/rootfs/etc/confd/templates/doctrine.yaml.tmpl b/riprap/rootfs/etc/confd/templates/doctrine.yaml.tmpl new file mode 100644 index 00000000..928811ac --- /dev/null +++ b/riprap/rootfs/etc/confd/templates/doctrine.yaml.tmpl @@ -0,0 +1,32 @@ +parameters: + # Adds a fallback DATABASE_URL if the env var is not set. + # This allows you to run cache:warmup even if your + # environment variables are not available yet. + # You should not need to change this value. + env(DATABASE_URL): '' + +doctrine: + dbal: +{{ if eq (getenv "DB_DRIVER") "mysql" }} + driver: 'pdo_mysql' + charset: utf8mb4 + default_table_options: + charset: utf8mb4 + collate: utf8mb4_unicode_ci +{{ end }} +{{ if eq (getenv "DB_DRIVER") "postgresql" }} + driver: 'pdo_pgsql' + charset: utf8 +{{ end }} + url: '%env(resolve:DATABASE_URL)%' + orm: + auto_generate_proxy_classes: '%kernel.debug%' + naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware + auto_mapping: true + mappings: + App: + is_bundle: false + type: annotation + dir: '%kernel.project_dir%/src/Entity' + prefix: 'App\Entity' + alias: App diff --git a/riprap/rootfs/etc/confd/templates/monolog.yaml.tmpl b/riprap/rootfs/etc/confd/templates/monolog.yaml.tmpl new file mode 100644 index 00000000..232cf32d --- /dev/null +++ b/riprap/rootfs/etc/confd/templates/monolog.yaml.tmpl @@ -0,0 +1,20 @@ +monolog: + handlers: + main: + type: stream + # path: "%kernel.logs_dir%/%kernel.environment%.log" + path: "php://stderr" + level: {{ getenv "RIPRAP_LOG_LEVEL" }} + channels: ["!event"] + # uncomment to get logging in your browser + # you may have to allow bigger header sizes in your Web server configuration + #firephp: + # type: firephp + # level: info + #chromephp: + # type: chromephp + # level: info + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine", "!console"] diff --git a/riprap/rootfs/etc/nginx/http.d/default.conf b/riprap/rootfs/etc/nginx/http.d/default.conf new file mode 100644 index 00000000..86bd0426 --- /dev/null +++ b/riprap/rootfs/etc/nginx/http.d/default.conf @@ -0,0 +1,32 @@ +# From: https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ +server { + listen 8000; + root /var/www/riprap/public; + + location / { + # try to serve file directly, fallback to index.php + try_files $uri /index.php$is_args$args; + } + + location ~ ^/index\.php(/|$) { + fastcgi_pass unix:/var/run/php-fpm81/php-fpm81.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/index.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + # return 404 for all other php files not matching the front controller + # this prevents access to other php files you don't want to be accessible. + location ~ \.php$ { + return 404; + } +} +# Required for Nginx service to validate that fpm is working. +# @see nginx/rootfs/etc/s6-overlay/s6-rc.d/nginx/data/check +include /etc/nginx/shared/fpm.server.conf; diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/dependencies.d/ready b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/finish b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/finish new file mode 100755 index 00000000..1d46dca3 --- /dev/null +++ b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/finish @@ -0,0 +1,11 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Only shutdown the container if this service was enabled otherwise ignore. +if [[ "${RIPRAP_CROND_ENABLE_SERVICE}" == "true" ]]; then + # shellcheck disable=SC1091 + source /usr/local/share/s6/finish "${1}" "${2}" +else + exec s6-svc -Od . +fi diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/run b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/run new file mode 100755 index 00000000..3972a894 --- /dev/null +++ b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/run @@ -0,0 +1,8 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# Only run the service if explicitly told to do so. +if [[ "${RIPRAP_CROND_ENABLE_SERVICE}" == "true" ]]; then + exec crond -f -l "${RIPRAP_CROND_LOG_LEVEL}" -d "${RIPRAP_CROND_LOG_LEVEL}" -L /dev/stdout +fi diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/type b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/riprap/rootfs/etc/s6-overlay/s6-rc.d/crond/type @@ -0,0 +1 @@ +longrun diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/dependencies.d/ready b/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/type b/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/type @@ -0,0 +1 @@ +oneshot diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/up b/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/up new file mode 100755 index 00000000..3737f825 --- /dev/null +++ b/riprap/rootfs/etc/s6-overlay/s6-rc.d/riprap-setup/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/riprap-setup.sh diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/crond b/riprap/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/crond new file mode 100644 index 00000000..e69de29b diff --git a/riprap/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/riprap-setup b/riprap/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/riprap-setup new file mode 100644 index 00000000..e69de29b diff --git a/riprap/rootfs/etc/s6-overlay/scripts/riprap-setup.sh b/riprap/rootfs/etc/s6-overlay/scripts/riprap-setup.sh new file mode 100755 index 00000000..41fc80a7 --- /dev/null +++ b/riprap/rootfs/etc/s6-overlay/scripts/riprap-setup.sh @@ -0,0 +1,86 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +function mysql_create_database { + cat <<-EOF | create-database.sh +-- Create database in mariadb or mysql. +CREATE DATABASE IF NOT EXISTS ${RIPRAP_DB_NAME} CHARACTER SET utf8 COLLATE utf8_general_ci; + +-- Create user and grant rights. +CREATE USER IF NOT EXISTS '${RIPRAP_DB_USER}'@'%' IDENTIFIED BY '${RIPRAP_DB_PASSWORD}'; +GRANT ALL PRIVILEGES ON ${RIPRAP_DB_NAME}.* to '${RIPRAP_DB_USER}'@'%'; +FLUSH PRIVILEGES; + +-- Update user password if changed. +SET PASSWORD FOR ${RIPRAP_DB_USER}@'%' = PASSWORD('${RIPRAP_DB_PASSWORD}') +EOF +} + +function postgresql_create_database { + cat <<-EOF | create-database.sh +BEGIN; + +DO \$\$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${RIPRAP_DB_USER}') THEN + CREATE ROLE ${RIPRAP_DB_USER}; + END IF; +END +\$\$; + +ALTER ROLE ${RIPRAP_DB_USER} WITH LOGIN; +ALTER USER ${RIPRAP_DB_USER} PASSWORD '${RIPRAP_DB_PASSWORD}'; + +ALTER DATABASE ${RIPRAP_DB_NAME} OWNER TO ${RIPRAP_DB_USER}; +GRANT ALL PRIVILEGES ON DATABASE ${RIPRAP_DB_NAME} TO ${RIPRAP_DB_USER}; + +COMMIT; +EOF +} + +function create_database { + case "${DB_DRIVER}" in + sqlite) + # Running migrations will create the database. + ;; + mysql) + mysql_create_database + ;; + postgresql) + postgresql_create_database + ;; + *) + echo "Only SQLite/MySQL/PostgresSQL databases are supported for now." >&2 + exit 1 + ;; + esac +} + +function setup_cron { + if [[ "${RIPRAP_CROND_ENABLE_SERVICE}" == "true" ]]; then + cat </dev/null +SELECT COUNT(*) as count FROM fixity_check_event; +EOF +} + +# Exit non-zero if database does not exist. +cat <<-EOF | execute-sql-file.sh + use ${DB_NAME} +EOF + +# Perform check-fixity (ingests from CSV). +check-fixity.sh "--settings=/var/www/riprap/cron_config.yaml" + +# Query the database to determine if the expected number of checks occured. +rows=$(count) + +# Check if results meet expectations. +if [[ "${rows}" != "3" ]]; then + echo "Failed to created the expected number of rows: ${rows}!=3." + exit 1 +else + echo "Created the expected number of rows." +fi + +# All tests were successful +exit 0 diff --git a/riprap/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml b/riprap/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml new file mode 100644 index 00000000..5eb63066 --- /dev/null +++ b/riprap/tests/ServiceStartsWithBackendPostgreSQL/docker-compose.yml @@ -0,0 +1,16 @@ +# file: docker-compose.yml +version: "3.8" + +name: riprap-servicestartswithbackendsqlite +services: + postgresql: + image: ${POSTGRESQL:-islandora/postgresql:local} + riprap: + # Allow downstream container to override `DB` environment variables. + environment: + RIPRAP_DB_DRIVER: postgresql + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. + image: ${RIPRAP:-islandora/riprap:local} diff --git a/riprap/tests/ServiceStartsWithBackendPostgreSQL/test.sh b/riprap/tests/ServiceStartsWithBackendPostgreSQL/test.sh new file mode 100755 index 00000000..51f2e04a --- /dev/null +++ b/riprap/tests/ServiceStartsWithBackendPostgreSQL/test.sh @@ -0,0 +1,28 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +function count { + cat <query($sql); +if($result){ + while($row = $result->fetch(PDO::FETCH_ASSOC)){ + echo $row['count']; + } +} +?> +EOF +) + +# Check if results meet expectations. +if [[ "${rows}" != "3" ]]; then + echo "Failed to created the expected number of rows: ${rows}!=3." + exit 1 +else + echo "Created the expected number of rows." +fi + +# All tests were successful +exit 0 diff --git a/settings.gradle.kts b/settings.gradle.kts index 937cf978..b91df5d1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,18 +1,23 @@ rootProject.name = "isle-buildkit" -// Include plugin for building Docker images. -sourceControl { - gitRepository(uri("https://github.com/Islandora-Devops/isle-gradle-docker-plugin.git")) { - producesModule("ca.islandora:isle-gradle-docker-plugin") - } -} - // Include any folder that has a Dockerfile as a sub-project. rootProject.projectDir - .walk() - .maxDepth(1) // Only immediate directories. - .filter { it.isDirectory && it.resolve("Dockerfile").exists() } // Must have a Dockerfile. - .forEach { - // Include as a sub-project. - include(it.relativeTo(rootProject.projectDir).path) + .walk() + .maxDepth(1) // Only immediate directories. + .filter { it.isDirectory && it.resolve("Dockerfile").exists() } // Must have a Dockerfile. + .forEach { docker -> + // Include as a sub-project. + include(docker.relativeTo(rootProject.projectDir).path) + // Include any tests as sub-projects of the docker project. + val tests = docker.resolve("tests") + if (tests.isDirectory) { + include(tests.relativeTo(rootProject.projectDir).path.replace("/", ":")) + // Add any sub-folders that container project files as well. + tests + .walk() + .filter { it.isDirectory && (it.resolve("build.gradle.kts").exists() || it.resolve("docker-compose.yml").exists())} + .forEach { + include(it.relativeTo(rootProject.projectDir).path.replace("/", ":")) + } } + } diff --git a/solr/.dockerignore b/solr/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/solr/.dockerignore +++ b/solr/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/solr/Dockerfile b/solr/Dockerfile index a4040879..5307aac0 100644 --- a/solr/Dockerfile +++ b/solr/Dockerfile @@ -1,23 +1,37 @@ -# syntax=docker/dockerfile:experimental -FROM local/java:latest +# syntax=docker/dockerfile:1.5.1 +FROM java -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - SOLR_VERSION="7.1.0" && \ - SOLR_FILE="solr-${SOLR_VERSION}.tgz" && \ - SOLR_URL="https://archive.apache.org/dist/lucene/solr/${SOLR_VERSION}/${SOLR_FILE}" && \ - SOLR_FILE_SHA256="5cd25cc2634e47efbb529658d6ddd406a7cd1b211affa26563a28db2d80b8133" && \ - SOLR_SIG_SHA256="b187742e041a7315661b414bbadc69814e2a380ce49c0c2cc7c96acf0846d03b" && \ - download.sh --url "${SOLR_URL}" --sha256 "${SOLR_FILE_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - download.sh --url "${SOLR_URL}.asc" --sha256 "${SOLR_SIG_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-apache-service.sh \ - --name solr \ - --key "38D2EA16DDF5FC722EBC433FDC92616F177050F6" \ - --file "${DOWNLOAD_CACHE_DIRECTORY}/${SOLR_FILE}" \ - docs example licenses server/solr/configsets +ARG TARGETARCH +ARG SOLR_VERSION="8.11.2" +ARG SOLR_FILE="solr-${SOLR_VERSION}.tgz" +ARG SOLR_URL="https://archive.apache.org/dist/lucene/solr/${SOLR_VERSION}/${SOLR_FILE}" +ARG SOLR_FILE_SHA256="54d6ebd392942f0798a60d50a910e26794b2c344ee97c2d9b50e678a7066d3a6" + +EXPOSE 8983 WORKDIR /opt/solr -EXPOSE 8983 +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=solr-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${SOLR_URL}" \ + --sha256 "${SOLR_FILE_SHA256}" \ + --strip \ + --dest "/opt/solr" \ + docs \ + example \ + server/solr/configsets \ + && \ + cleanup.sh + +RUN create-service-user.sh --name solr /data && \ + cleanup.sh + +# Defaults environment variables to be overloaded. +ENV \ + SOLR_JAVA_OPTS= \ + SOLR_JETTY_OPTS= \ + SOLR_LOG_LEVEL=INFO \ + SOLR_MEMORY=512m -COPY rootfs / +COPY --link rootfs / diff --git a/solr/README.md b/solr/README.md index e64cb57a..f5eac4d5 100644 --- a/solr/README.md +++ b/solr/README.md @@ -1,6 +1,6 @@ # Solr -Docker image for [Solr] version 7.1.0. +Docker image for [Solr] version 8.11.2. Please refer to the [Solr Documentation] for more in-depth information. @@ -17,6 +17,15 @@ Requires `islandora/java` docker image to build. Please refer to the [Java Image README](../java/README.md) for additional information including additional settings, volumes, ports, etc. +## Settings + +| Environment Variable | Default | Description | +| :------------------- | :------ | :----------------------------------------------------------------------------- | +| SOLR_JAVA_OPTS | | Additional parameters to pass to the JVM when starting Solr | +| SOLR_JETTY_OPTS | | Additional parameters to pass to Jetty when starting Solr. | +| SOLR_LOG_LEVEL | INFO | Log level. Possible Values: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE or ALL | +| SOLR_MEMORY | 512m | Sets the min (-Xms) and max (-Xmx) heap size for the JVM | + ## Ports | Port | Description | @@ -31,10 +40,31 @@ additional settings, volumes, ports, etc. ## Logs -| Path | Description | -| :----------------------------- | :------------- | -| /opt/solr/server/logs/solr.log | [Solr Logging] | +- [Solr Logging] [Solr Documentation]: https://lucene.apache.org/solr/guide/7_1/ [Solr Logging]: https://lucene.apache.org/solr/guide/7_1/configuring-logging.html [Solr]: https://lucene.apache.org/solr/ + +## Changing versions + +There is 2 values you need to update/change the version. + +1. Solr version: found at [archive.apache.org](https://archive.apache.org/dist/lucene/solr) +1. SOLR_FILE_SHA256: sha256sum of the tgz file + +```dockerfile +ARG SOLR_VERSION="8.11.2" +ARG SOLR_FILE_SHA256="54d6ebd392942f0798a60d50a910e26794b2c344ee97c2d9b50e678a7066d3a6" +``` + +Go to [archive.apache.org](https://archive.apache.org/dist/lucene/solr) and find the version you want. There will be several files but the one to use have the following naming convention. + +* solr-${SOLR_VERSION}.tgz + +Download the two files and run and replace the _1.1.1_ with the version you have. + +```bash +# This outputs the value to use for $SOLR_FILE_SHA256. +sha256sum solr-1.1.1.tgz +``` diff --git a/solr/rootfs/etc/confd/conf.d/log4j.properties.toml b/solr/rootfs/etc/confd/conf.d/log4j.properties.toml new file mode 100644 index 00000000..d9984e55 --- /dev/null +++ b/solr/rootfs/etc/confd/conf.d/log4j.properties.toml @@ -0,0 +1,7 @@ +[template] +src = "log4j.properties.tmpl" +dest = "/opt/solr/server/resources/log4j.properties" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/solr/rootfs/etc/confd/templates/log4j.properties.tmpl b/solr/rootfs/etc/confd/templates/log4j.properties.tmpl new file mode 100644 index 00000000..39dae36d --- /dev/null +++ b/solr/rootfs/etc/confd/templates/log4j.properties.tmpl @@ -0,0 +1,19 @@ +# Default Solr log4j config +# rootLogger log level may be programmatically overridden by -Dsolr.log.level +solr.log=${solr.log.dir} +log4j.rootLogger={{ getenv "SOLR_LOG_LEVEL" }}, CONSOLE + +# Console appender will be programmatically disabled when Solr is started with option -Dsolr.log.muteconsole +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.EnhancedPatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p (%t) [%X{collection} %X{shard} %X{replica} %X{core}] %c{1.} %m%n + +# Adjust logging levels that should differ from root logger +log4j.logger.org.apache.zookeeper=WARN +log4j.logger.org.apache.hadoop=WARN +log4j.logger.org.eclipse.jetty=WARN +log4j.logger.org.eclipse.jetty.server.Server=INFO +log4j.logger.org.eclipse.jetty.server.ServerConnector=INFO + +# set to INFO to enable infostream log messages +log4j.logger.org.apache.solr.update.LoggingInfoStream=OFF diff --git a/solr/rootfs/etc/cont-init.d/02-solr-setup.sh b/solr/rootfs/etc/cont-init.d/02-solr-setup.sh deleted file mode 100755 index e5f40bee..00000000 --- a/solr/rootfs/etc/cont-init.d/02-solr-setup.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/with-contenv bash -set -e - -# When bind mounting we need to ensure that we -# actually can write to the folder. -chown -R solr:solr /opt/solr/server/solr diff --git a/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/dependencies.d/ready b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/finish b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/run b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/run new file mode 100755 index 00000000..593a6534 --- /dev/null +++ b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/run @@ -0,0 +1,18 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e +ARGS=(-m "${SOLR_MEMORY}") + +if [[ -n "${SOLR_JETTY_OPTS}" ]]; then + ARGS+=(-j "${SOLR_JETTY_OPTS}") +fi + +if [[ -n "${SOLR_JAVA_OPTS}" ]]; then + ARGS+=(-a "${SOLR_JAVA_OPTS}") +fi + +# When bind mounting we need to ensure that we +# actually can write to the folder. +chown -R solr:solr /opt/solr/server/solr + +exec s6-setuidgid solr /opt/solr/bin/solr start -f "${ARGS[@]}" diff --git a/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/type b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/solr/rootfs/etc/s6-overlay/s6-rc.d/solr/type @@ -0,0 +1 @@ +longrun diff --git a/solr/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/solr b/solr/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/solr new file mode 100644 index 00000000..e69de29b diff --git a/solr/rootfs/etc/services.d/solr/finish b/solr/rootfs/etc/services.d/solr/finish deleted file mode 100644 index f8984dd3..00000000 --- a/solr/rootfs/etc/services.d/solr/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh : -s6-svscanctl -t /var/run/s6/services diff --git a/solr/rootfs/etc/services.d/solr/run b/solr/rootfs/etc/services.d/solr/run deleted file mode 100644 index dc64b621..00000000 --- a/solr/rootfs/etc/services.d/solr/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh : -with-contenv -s6-setuidgid solr /opt/solr/bin/solr start -f diff --git a/solr/tests/ServiceStartsWithDefaults/docker-compose.yml b/solr/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..2e6d789e --- /dev/null +++ b/solr/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: solr-servicestartswithdefaults +services: + solr: + <<: *common + image: ${SOLR:-islandora/solr:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/solr/tests/ServiceStartsWithDefaults/test.sh b/solr/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..24e9898c --- /dev/null +++ b/solr/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,11 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Wait for service to start. +wait_20x http://localhost:8983/solr + +# Service must start for us to get to this point. +exit 0 diff --git a/test/.dockerignore b/test/.dockerignore new file mode 100644 index 00000000..1b2f9f5c --- /dev/null +++ b/test/.dockerignore @@ -0,0 +1,4 @@ +build.gradle.kts +README.md +tests +tests/**/* diff --git a/test/Dockerfile b/test/Dockerfile new file mode 100644 index 00000000..d4b43358 --- /dev/null +++ b/test/Dockerfile @@ -0,0 +1,33 @@ +# syntax=docker/dockerfile:1.5.1 +FROM drupal + +ARG TARGETARCH +ARG COMMIT=0.5.2 +ARG FILE=${COMMIT}.tar.gz +ARG URL=https://github.com/Islandora/islandora-starter-site/archive/${FILE} +ARG SHA256=456cdae4240d8cdebe4da7eee5820acf0d8c023a94e85be06acdf20dd04ded82 + +# Platform agnostic does not require arch specific identifier. +RUN --mount=type=cache,id=test-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ + download.sh \ + --url "${URL}" \ + --sha256 "${SHA256}" \ + --strip \ + --dest "/var/www/drupal" \ + && \ + cleanup.sh + +# Import Default content, includes content normally included via migrate import. +# So that the links between the default content and the tags work correctly (linked by UUID rather than ID). +RUN --mount=type=bind,source=rootfs/var/www/drupal/assets/patches/default_settings.txt,target=/var/www/drupal/assets/patches/default_settings.txt \ + --mount=type=bind,source=rootfs/var/www/drupal/web/modules/custom,target=/var/www/drupal/web/modules/custom \ + --mount=type=cache,id=test-drupal-composer-${TARGETARCH},sharing=locked,target=/root/.composer/cache \ + composer -d /var/www/drupal config minimum-stability dev && \ + composer -d /var/www/drupal config repositories.sample_core path ./web/modules/custom/sample_core && \ + composer -d /var/www/drupal require 'islandora/sample_core:*' && \ + composer install -d /var/www/drupal && \ + cleanup.sh + +COPY --link rootfs / + +RUN chown -R nginx:nginx /var/www diff --git a/test/README.md b/test/README.md new file mode 100644 index 00000000..7d976633 --- /dev/null +++ b/test/README.md @@ -0,0 +1,15 @@ +# Test + +This image is exclusively used for **manually testing** pull request to this +repository and is not intended for use in production environments. + +## Dependencies + +Requires `islandora/drupal` docker image to build. Please refer to the +[Drupal Image README](../drupal/README.md) for additional information. + +## Gotchas + +If updating the solr image [Solr Image](../solr/README.md) be sure to update the +configuration in +[test/rootfs/opt/solr/server/solr/default/conf](test/rootfs/opt/solr/server/solr/default/conf). diff --git a/test/rootfs/etc/s6-overlay/s6-rc.d/install/dependencies.d/ready b/test/rootfs/etc/s6-overlay/s6-rc.d/install/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/test/rootfs/etc/s6-overlay/s6-rc.d/install/type b/test/rootfs/etc/s6-overlay/s6-rc.d/install/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/test/rootfs/etc/s6-overlay/s6-rc.d/install/type @@ -0,0 +1 @@ +oneshot diff --git a/test/rootfs/etc/s6-overlay/s6-rc.d/install/up b/test/rootfs/etc/s6-overlay/s6-rc.d/install/up new file mode 100755 index 00000000..8a5ccd8b --- /dev/null +++ b/test/rootfs/etc/s6-overlay/s6-rc.d/install/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/install.sh diff --git a/test/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/install b/test/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/install new file mode 100644 index 00000000..e69de29b diff --git a/test/rootfs/etc/s6-overlay/scripts/install.sh b/test/rootfs/etc/s6-overlay/scripts/install.sh new file mode 100755 index 00000000..b22859e4 --- /dev/null +++ b/test/rootfs/etc/s6-overlay/scripts/install.sh @@ -0,0 +1,146 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -e + +# shellcheck disable=SC1091 +source /etc/islandora/utilities.sh + +readonly SITE="default" + +# Only care about derivatives for now. +# As Fedora is slow as beans. +readonly QUEUES=( + islandora-connector-fits + islandora-connector-homarus + islandora-connector-houdini + islandora-connector-ocr +) + +function jolokia { + local type="${1}" + local queue="${2}" + local action="${3}" + local url="http://${DRUPAL_DEFAULT_BROKER_HOST}:${DRUPAL_DEFAULT_BROKER_WEB_PORT}/api/jolokia/${type}/org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=${queue}" + if [ "$action" != "" ]; then + url="${url}/$action" + fi + curl -s -u "${DRUPAL_DEFAULT_BROKER_WEB_ADMIN_USER}:${DRUPAL_DEFAULT_BROKER_WEB_ADMIN_PASSWORD}" "${url}" + printf "\n" +} + +function wait_for_dequeue { + local queue_size=-1 + local continue_waiting=1 + while [ "${continue_waiting}" -ne 0 ]; do + continue_waiting=0 + for queue in "${QUEUES[@]}"; do + queue_size=$(jolokia "read" "${queue}" | jq .value.QueueSize) &>/dev/null || exit $? + echo "Queue (${queue}) remaining: ${queue_size}" + if [ "${queue_size}" != "0" ]; then + continue_waiting=1 + fi + done + sleep 3 + done +} + +function configure { + # Starter site post install steps. + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" cache:rebuild + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" user:role:add fedoraadmin admin + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" pm:uninstall pgsql sqlite + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" cache:rebuild + + # Ingest sample content. + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" pm:enable sample_content -y + + # Add check to wait for queue's to empty. + wait_for_dequeue + + # Add check to wait for solr index to complete. + drush search-api:index + + # Cache must be last as clearing the cache while adding content can cause deadlocks. + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" cron || true + drush --root=/var/www/drupal --uri="${DRUPAL_DRUSH_URI}" cache:rebuild +} + +function install { + wait_for_service "${SITE}" db + create_database "${SITE}" + install_site "${SITE}" + wait_for_service "${SITE}" broker + wait_for_service "${SITE}" fcrepo + wait_for_service "${SITE}" fits + wait_for_service "${SITE}" solr + wait_for_service "${SITE}" triplestore + create_blazegraph_namespace_with_default_properties "${SITE}" + configure +} + +function mysql_count_query { + cat <<-EOF +SELECT COUNT(DISTINCT table_name) +FROM information_schema.columns +WHERE table_schema = '${DRUPAL_DEFAULT_DB_NAME}'; +EOF +} + +# Check the number of tables to determine if it has already been installed. +function installed { + local count + count=$(execute-sql-file.sh <(mysql_count_query) -- -N 2>/dev/null) || exit $? + [[ $count -ne 0 ]] +} + +# Required even if not installing. +function setup() { + local site drupal_root subdir site_directory public_files_directory private_files_directory twig_cache_directory + site="${1}" + shift + + drupal_root=/var/www/drupal/web + subdir=$(drupal_site_env "${site}" "SUBDIR") + site_directory="${drupal_root}/sites/${subdir}" + public_files_directory="${site_directory}/files" + private_files_directory="/var/www/drupal/private" + twig_cache_directory="${private_files_directory}/php" + + # Ensure the files directories are writable by nginx, as when it is a new volume it is owned by root. + mkdir -p "${site_directory}" "${public_files_directory}" "${private_files_directory}" "${twig_cache_directory}" + chown nginx:nginx "${site_directory}" "${public_files_directory}" "${private_files_directory}" "${twig_cache_directory}" + chmod ug+rw "${site_directory}" "${public_files_directory}" "${private_files_directory}" "${twig_cache_directory}" +} + +function drush_cache_setup { + # Make sure the default drush cache directory exists and is writeable. + mkdir -p /tmp/drush-/cache + chmod a+rwx /tmp/drush-/cache +} + +# External processes can look for `/installed` to check if installation is completed. +function finished { + touch /installed + cat <<-EOT + + +##################### +# Install Completed # +##################### +EOT +} + +function main() { + cd /var/www/drupal + drush_cache_setup + for_all_sites setup + + if installed; then + echo "Already Installed" + else + echo "Installing" + install + fi + finished +} +main diff --git a/test/rootfs/opt/solr/server/solr/default/conf/accents_en.txt b/test/rootfs/opt/solr/server/solr/default/conf/accents_en.txt new file mode 100644 index 00000000..164a1524 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/accents_en.txt @@ -0,0 +1,185 @@ +# À => A +"\u00C0" => "A" +# Á => A +"\u00C1" => "A" +#  => A +"\u00C2" => "A" +# à => A +"\u00C3" => "A" +# Ä => A +"\u00C4" => "A" +# Å => A +"\u00C5" => "A" +# Ą => A +"\u0104" => "A" +# Æ => AE +"\u00C6" => "AE" +# Ç => C +"\u00C7" => "C" +# Ć => C +"\U0106" => "C" +# È => E +"\u00C8" => "E" +# É => E +"\u00C9" => "E" +# Ê => E +"\u00CA" => "E" +# Ë => E +"\u00CB" => "E" +# Ę => E +"\u0118" => "E" +# Ì => I +"\u00CC" => "I" +# Í => I +"\u00CD" => "I" +# Î => I +"\u00CE" => "I" +# Ï => I +"\u00CF" => "I" +# IJ => IJ +"\u0132" => "IJ" +# Ð => D +"\u00D0" => "D" +# Ł => L +"\u0141" => "L" +# Ñ => N +"\u00D1" => "N" +# Ń => N +"\u0143" => "N" +# Ò => O +"\u00D2" => "O" +# Ó => O +"\u00D3" => "O" +# Ô => O +"\u00D4" => "O" +# Õ => O +"\u00D5" => "O" +# Ö => O +"\u00D6" => "O" +# Ø => O +"\u00D8" => "O" +# Œ => OE +"\u0152" => "OE" +# Þ +"\u00DE" => "TH" +# Ù => U +"\u00D9" => "U" +# Ú => U +"\u00DA" => "U" +# Û => U +"\u00DB" => "U" +# Ü => U +"\u00DC" => "U" +# Ý => Y +"\u00DD" => "Y" +# Ÿ => Y +"\u0178" => "Y" +# à => a +"\u00E0" => "a" +# á => a +"\u00E1" => "a" +# â => a +"\u00E2" => "a" +# ã => a +"\u00E3" => "a" +# ä => a +"\u00E4" => "a" +# å => a +"\u00E5" => "a" +# æ => ae +"\u00E6" => "ae" +# ç => c +"\u00E7" => "c" +# è => e +"\u00E8" => "e" +# é => e +"\u00E9" => "e" +# ê => e +"\u00EA" => "e" +# ë => e +"\u00EB" => "e" +# ì => i +"\u00EC" => "i" +# í => i +"\u00ED" => "i" +# î => i +"\u00EE" => "i" +# ï => i +"\u00EF" => "i" +# ij => ij +"\u0133" => "ij" +# ð => d +"\u00F0" => "d" +# ñ => n +"\u00F1" => "n" +# ò => o +"\u00F2" => "o" +# ó => o +"\u00F3" => "o" +# ô => o +"\u00F4" => "o" +# õ => o +"\u00F5" => "o" +# ö => o +"\u00F6" => "o" +# ø => o +"\u00F8" => "o" +# œ => oe +"\u0153" => "oe" +# ß => ss +"\u00DF" => "ss" +# Ś => S +"\u015a" => "S" +# þ => th +"\u00FE" => "th" +# ù => u +"\u00F9" => "u" +# ú => u +"\u00FA" => "u" +# û => u +"\u00FB" => "u" +# ü => u +"\u00FC" => "u" +# ý => y +"\u00FD" => "y" +# ÿ => y +"\u00FF" => "y" +# Ź => Z +"\u0179" => "Z" +# Ż => Z +"\u017b" => "Z" +# ff => ff +"\uFB00" => "ff" +# fi => fi +"\uFB01" => "fi" +# fl => fl +"\uFB02" => "fl" +# ffi => ffi +"\uFB03" => "ffi" +# ffl => ffl +"\uFB04" => "ffl" +# ſt => st +"\uFB05" => "st" +# st => st +"\uFB06" => "st" +# Māori macrons. +# Ā => A +"\u0100" => "A" +# Ē => E +"\u0112" => "E" +# Ī => I +"\u012A" => "I" +# Ō => O +"\u014C" => "O" +# Ū => U +"\u016A" => "U" +# ā => a +"\u0101" => "a" +# ē => e +"\u0113" => "e" +# ī => i +"\u012B" => "i" +# ō => o +"\u014D" => "o" +# ū => u +"\u016B" => "u" diff --git a/test/rootfs/opt/solr/server/solr/default/conf/accents_und.txt b/test/rootfs/opt/solr/server/solr/default/conf/accents_und.txt new file mode 100644 index 00000000..7c883f87 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/accents_und.txt @@ -0,0 +1,148 @@ +# À => A +"\u00C0" => "A" +# Á => A +"\u00C1" => "A" +#  => A +"\u00C2" => "A" +# à => A +"\u00C3" => "A" +# Ä => A +"\u00C4" => "A" +# Å => A +"\u00C5" => "A" +# Æ => AE +"\u00C6" => "AE" +# Ç => C +"\u00C7" => "C" +# È => E +"\u00C8" => "E" +# É => E +"\u00C9" => "E" +# Ê => E +"\u00CA" => "E" +# Ë => E +"\u00CB" => "E" +# Ì => I +"\u00CC" => "I" +# Í => I +"\u00CD" => "I" +# Î => I +"\u00CE" => "I" +# Ï => I +"\u00CF" => "I" +# IJ => IJ +"\u0132" => "IJ" +# Ð => D +"\u00D0" => "D" +# Ñ => N +"\u00D1" => "N" +# Ò => O +"\u00D2" => "O" +# Ó => O +"\u00D3" => "O" +# Ô => O +"\u00D4" => "O" +# Õ => O +"\u00D5" => "O" +# Ö => O +"\u00D6" => "O" +# Ø => O +"\u00D8" => "O" +# Œ => OE +"\u0152" => "OE" +# Þ +"\u00DE" => "TH" +# Ù => U +"\u00D9" => "U" +# Ú => U +"\u00DA" => "U" +# Û => U +"\u00DB" => "U" +# Ü => U +"\u00DC" => "U" +# Ý => Y +"\u00DD" => "Y" +# Ÿ => Y +"\u0178" => "Y" +# à => a +"\u00E0" => "a" +# á => a +"\u00E1" => "a" +# â => a +"\u00E2" => "a" +# ã => a +"\u00E3" => "a" +# ä => a +"\u00E4" => "a" +# å => a +"\u00E5" => "a" +# æ => ae +"\u00E6" => "ae" +# ç => c +"\u00E7" => "c" +# è => e +"\u00E8" => "e" +# é => e +"\u00E9" => "e" +# ê => e +"\u00EA" => "e" +# ë => e +"\u00EB" => "e" +# ì => i +"\u00EC" => "i" +# í => i +"\u00ED" => "i" +# î => i +"\u00EE" => "i" +# ï => i +"\u00EF" => "i" +# ij => ij +"\u0133" => "ij" +# ð => d +"\u00F0" => "d" +# ñ => n +"\u00F1" => "n" +# ò => o +"\u00F2" => "o" +# ó => o +"\u00F3" => "o" +# ô => o +"\u00F4" => "o" +# õ => o +"\u00F5" => "o" +# ö => o +"\u00F6" => "o" +# ø => o +"\u00F8" => "o" +# œ => oe +"\u0153" => "oe" +# ß => ss +"\u00DF" => "ss" +# þ => th +"\u00FE" => "th" +# ù => u +"\u00F9" => "u" +# ú => u +"\u00FA" => "u" +# û => u +"\u00FB" => "u" +# ü => u +"\u00FC" => "u" +# ý => y +"\u00FD" => "y" +# ÿ => y +"\u00FF" => "y" +# ff => ff +"\uFB00" => "ff" +# fi => fi +"\uFB01" => "fi" +# fl => fl +"\uFB02" => "fl" +# ffi => ffi +"\uFB03" => "ffi" +# ffl => ffl +"\uFB04" => "ffl" +# ſt => st +"\uFB05" => "st" +# st => st +"\uFB06" => "st" diff --git a/test/rootfs/opt/solr/server/solr/default/conf/elevate.xml b/test/rootfs/opt/solr/server/solr/default/conf/elevate.xml new file mode 100644 index 00000000..193a0e72 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/elevate.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/protwords_en.txt b/test/rootfs/opt/solr/server/solr/default/conf/protwords_en.txt new file mode 100644 index 00000000..e69de29b diff --git a/test/rootfs/opt/solr/server/solr/default/conf/protwords_und.txt b/test/rootfs/opt/solr/server/solr/default/conf/protwords_und.txt new file mode 100644 index 00000000..e69de29b diff --git a/test/rootfs/opt/solr/server/solr/default/conf/schema.xml b/test/rootfs/opt/solr/server/solr/default/conf/schema.xml new file mode 100644 index 00000000..7c463e03 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/schema.xml @@ -0,0 +1,478 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &extrafields; + + + &extratypes; + + + id + + + + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/schema_extra_fields.xml b/test/rootfs/opt/solr/server/solr/default/conf/schema_extra_fields.xml new file mode 100644 index 00000000..c21aeff2 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/schema_extra_fields.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/schema_extra_types.xml b/test/rootfs/opt/solr/server/solr/default/conf/schema_extra_types.xml new file mode 100644 index 00000000..91d11778 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/schema_extra_types.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/solrconfig.xml b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig.xml new file mode 100644 index 00000000..c34beaeb --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig.xml @@ -0,0 +1,811 @@ + + + + + + +]> + + + + + + + ${solr.abortOnConfigurationError:true} + + + ${solr.luceneMatchVersion:LUCENE_80} + + + + + + + + + + + + + + + + + + + + + ${solr.data.dir:} + + + + + + + + + ${solr.hdfs.home:} + + ${solr.hdfs.confdir:} + + ${solr.hdfs.blockcache.enabled:true} + + ${solr.hdfs.blockcache.global:true} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${solr.lock.type:native} + + + + + + + + + + + + + true + + + &index; + + + + + + + + + ${solr.ulog.dir:} + + + + + ${solr.autoCommit.MaxDocs:-1} + ${solr.autoCommit.MaxTime:15000} + false + + + + + + ${solr.autoSoftCommit.MaxDocs:-1} + ${solr.autoSoftCommit.MaxTime:5000} + + + + + + + + + + + + + + + + &query; + + + + + + + + + + + + static firstSearcher warming in solrconfig.xml + + + + + + false + + + + + + + + + &requestdispatcher; + + + + + + + &extra; + + + + + + + + + 100 + + + + + + + + 70 + + 0.5 + + [-\w ,/\n\"']{20,200} + + + + + + + ]]> + ]]> + + + + + + + + + + + + + + + + + + + + + + + + ,, + ,, + ,, + ,, + ,]]> + ]]> + + + + + + 10 + .,!? + + + + + + + WORD + + + en + US + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_extra.xml b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_extra.xml new file mode 100644 index 00000000..41ccf8ae --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_extra.xml @@ -0,0 +1,188 @@ + + + en + spellcheck_en + solr.DirectSolrSpellChecker + internal + 0.5 + 2 + 1 + 5 + 4 + 0.01 + .01 + true + + + + und + spellcheck_und + solr.DirectSolrSpellChecker + internal + 0.5 + 2 + 1 + 5 + 4 + 0.01 + .01 + true + + + + + en + AnalyzingInfixLookupFactory + DocumentDictionaryFactory + twm_suggest + text_en + sm_context_tags + true + false + + + + und + AnalyzingInfixLookupFactory + DocumentDictionaryFactory + twm_suggest + text_und + sm_context_tags + true + false + + + + + + false + false + false + true + false + 1 + false + 10 + + + terms + spellcheck + suggest + + + + + + + true + ignored_ + true + links + ignored_ + + + + + + + 1 + 1 + false + ${solr.mlt.timeAllowed:2000} + + + + + + + lucene + id + explicit + true + ${solr.selectSearchHandler.timeAllowed:-1} + false + + + spellcheck + elevator + + + + + + + id + und + on + false + false + 1 + 5 + 5 + true + true + 10 + 5 + + + spellcheck + + + + + + + true + und + 10 + + + suggest + + + + + + + id + true + + + tvComponent + + + + + + string + elevate.xml + + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_index.xml b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_index.xml new file mode 100644 index 00000000..e69de29b diff --git a/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_query.xml b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_query.xml new file mode 100644 index 00000000..5bdd6969 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_query.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + true + + false + + 20 + 200 + 1024 diff --git a/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_requestdispatcher.xml b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_requestdispatcher.xml new file mode 100644 index 00000000..5f4b9949 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/solrconfig_requestdispatcher.xml @@ -0,0 +1,5 @@ + + diff --git a/test/rootfs/opt/solr/server/solr/default/conf/solrcore.properties b/test/rootfs/opt/solr/server/solr/default/conf/solrcore.properties new file mode 100644 index 00000000..749fd532 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/solrcore.properties @@ -0,0 +1,13 @@ +solr.replication.master=false +solr.replication.slave=false +solr.replication.pollInterval=00:00:60 +solr.replication.masterUrl=http://localhost:8983/solr +solr.replication.confFiles=schema.xml,schema_extra_types.xml,schema_extra_fields.xml,elevate.xml,stopwords_en.txt,protwords_en.txt,accents_en.txt,synonyms_en.txt,stopwords_und.txt,protwords_und.txt,accents_und.txt,synonyms_und.txt +solr.mlt.timeAllowed=2000 +solr.selectSearchHandler.timeAllowed=-1 +solr.autoCommit.MaxDocs=-1 +solr.autoCommit.MaxTime=15000 +solr.autoSoftCommit.MaxDocs=-1 +solr.autoSoftCommit.MaxTime=5000 + +solr.luceneMatchVersion=8.11 diff --git a/test/rootfs/opt/solr/server/solr/default/conf/stopwords_en.txt b/test/rootfs/opt/solr/server/solr/default/conf/stopwords_en.txt new file mode 100644 index 00000000..69810507 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/stopwords_en.txt @@ -0,0 +1,35 @@ +a +an +and +are +as +at +be +but +by +for +if +in +into +is +it +no +not +of +on +or +s +such +t +that +the +their +then +there +these +they +this +to +was +will +with diff --git a/test/rootfs/opt/solr/server/solr/default/conf/stopwords_und.txt b/test/rootfs/opt/solr/server/solr/default/conf/stopwords_und.txt new file mode 100644 index 00000000..e69de29b diff --git a/test/rootfs/opt/solr/server/solr/default/conf/synonyms_en.txt b/test/rootfs/opt/solr/server/solr/default/conf/synonyms_en.txt new file mode 100644 index 00000000..5dc4536b --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/synonyms_en.txt @@ -0,0 +1,17477 @@ +drupal, durpal +abettor's, abetter's +abettor, abetter +abettors, abetters +abnormalize, abnormalise +abnormalized, abnormalised +abnormalizing, abnormalising +abolitionize, abolitionise +abolitionized, abolitionised +abolitionizing, abolitionising +abridgment's, abridgement's +abridgment, abridgement +abridgments, abridgements +absinthe's, absinth's +absinthe, absinth +absinthes, absinths +academize, academise +academized, academised +academizing, academising +acalephe, acalephae +accessorize, accessorise +accessorized, accessorised +accessorizes, accessorises +accessorizing, accessorising +acclimatizable, acclimatisable +acclimatization's, acclimatisation's +acclimatization, acclimatisation +acclimatize, acclimatise +acclimatized, acclimatised +acclimatizer, acclimatiser +acclimatizers, acclimatisers +acclimatizes, acclimatises +acclimatizing, acclimatising +accorage, accourage +accoraged, accouraged +accorages, accourages +accoraging, accouraging +accouter, accoutre +accoutered, accoutred +accoutering, accoutring +accouterment's, accoutrement's +accouterment, accoutrement +accouterments, accoutrements +accouters, accoutres +Acemetae's, Acoemetae's +Acemetae, Acoemetae +Acemetic's, Acoemetic's +Acemetic, Acoemetic +Acer's, Acre's +Acer, Acre +acetonemia, acetonaemia +acetonemic, acetonaemic +achenia, achaenia +achenium, achaenium +acheniums, achaeniums +achenocarp, achaenocarp +achroiocythemia, achroiocythaemia +achromatization's, achromatisation's +achromatization, achromatisation +achromatizations, achromatisations +achromatize, achromatise +achromatized, achromatised +achromatizes, achromatises +achromatizing, achromatising +acidemia, acidaemia +acknowledgment's, acknowledgement's +acknowledgment, acknowledgement +acknowledgments, acknowledgements +acmesthesia, acmaesthesia +acroanesthesia, acroanaesthesia +acroesthesia, acroaesthesia +actualization's, actualisation's +actualization, actualisation +actualizations, actualisations +actualize, actualise +actualized, actualised +actualizes, actualises +actualizing, actualising +acuesthesia, acuaesthesia +adapter's, adaptor's +adapter, adaptor +adapters, adaptors +addable, addible +addenda, addendums +adjuster's, adjustor's +adjuster, adjustor +adjusters, adjustors +adonize, adonise +adonized, adonised +adonizes, adonises +adonizing, adonising +adrenalin's, adrenalin's +adrenaline, adrenalin +adulterize, adulterise +adulterized, adulterised +adulterizes, adulterises +adulterizing, adulterising +advene, advenae +adverbialize, adverbialise +adverbialized, adverbialised +adverbializes, adverbialises +adverbializing, adverbialising +advertise, advertize +advertised, advertized +advertisement's, advertizement's +advertisement, advertizement +advertisements, advertizements +advertises, advertizes +advertising, advertizing +advertizable, advertisable +adviser's, advisor's +adviser, advisor +advisers, advisors +adze's, adz's +adze, adz +aedile's, edile's +aedile, edile +aediles, ediles +Aedon's, Aaedon's +Aedon, Aaedon +Aeetes's, Aeaetes's +Aeetes, Aeaetes +aegis's, egis's +aegis, egis +aegises, egises +aerialness's, aaerialness's +aerialness, aaerialness +aeric, areic +aerogram, aerogramme +aerograms, aerogrammes +aerographer, areographer +aerographic, areographic +aerographical, areographical +aerographies, areographies +aerography's, areography's +aerography, areography +aerologic, areologic +aerological, areological +aerologies, areologies +aerologist's, areologist's +aerologist, areologist +aerology's, areology's +aerology, areology +aerometer, areometer +aerometers, areometers +aerometric, areometric +Aerope's, Aaerope's +Aerope, Aaerope +aesthete's, esthete's +aesthete, esthete +aesthetes, esthetes +aesthetic's, esthetic's +aesthetic, esthetic +aesthetically, esthetically +aestheticize, aestheticise +aestheticized, aestheticised +aestheticizes, aestheticises +aestheticizing, aestheticising +aesthetics, esthetics +affeer, affere +Africanization's, Africanisation's +Africanization, Africanisation +Africanizations, Africanisations +Africanize, Africanise +Africanized, Africanised +Africanizes, Africanises +Africanizing, Africanising +Afrikanerization, Afrikanerisation +Afrikanerize, Afrikanerise +Afrikanerized, Afrikanerised +Afrikanerizes, Afrikanerises +Afrikanerizing, Afrikanerising +agathodemon, agathodaemon +agatize, agatise +agatizes, agatises +ageism, agism +agenize, agenise +ager, agre +aggrandizable's, aggrandisable's +aggrandizable, aggrandisable +aggrandizables, aggrandisables +aggrandization, aggrandisation +aggrandize, aggrandise +aggrandized, aggrandised +aggrandizement's, aggrandisement's +aggrandizement, aggrandisement +aggrandizements, aggrandisements +aggrandizer's, aggrandiser's +aggrandizer, aggrandiser +aggrandizers, aggrandisers +aggrandizes, aggrandises +aggrandizing, aggrandising +aging's, ageing's +aging, ageing +agings, ageings +agnize, agnise +agnized, agnised +agnizes, agnises +agnizing, agnising +agonize, agonise +agonized, agonised +agonizedlies, agonisedlies +agonizedly, agonisedly +agonizer, agoniser +agonizers, agonisers +agonizes, agonises +agonizing, agonising +agonizinglier, agonisinglier +agonizingliest, agonisingliest +agonizingly, agonisingly +agrarianize, agrarianise +agrarianizes, agrarianises +agrize, agrise +agrized, agrised +agrizes, agrises +agrizing, agrising +aguize, aguise +aguized, aguised +aguizes, aguises +aguizing, aguising +aiger, aigre +air_gun, airgun +air_letter, airletter +airfoil's, aerofoil's +airfoil, aerofoil +airfoils, aerofoils +airgel, aerogel +airplane's, aeroplane's +airplane, aeroplane +airplanes, aeroplanes +airstrike's, air_strike's +airstrike, air_strike +airstrikes, air_strikes +aker, akre +Aktistete's, Aktistetae's +Aktistete, Aktistetae +albitize, albitise +albitized, albitised +albitizes, albitises +albitizing, albitising +albumenizer, albumeniser +albuminisation's, albuminization's +albuminisation, albuminization +albuminisations, albuminizations +albuminise, albuminize +albuminised, albuminized +albuminises, albuminizes +albuminising, albuminizing +alchemize, alchemise +alchemized, alchemised +alchemizes, alchemises +alchemizing, alchemising +Alcide's, Alcidae's +Alcide, Alcidae +Alcithoe's, Alcithoae's +Alcithoe, Alcithoae +alcoholizable's, alcoholisable's +alcoholizable, alcoholisable +alcoholizables, alcoholisables +alcoholization's, alcoholisation's +alcoholization, alcoholisation +alcoholizations, alcoholisations +alcoholize, alcoholise +alcoholized, alcoholised +alcoholizes, alcoholises +alcoholizing, alcoholising +aleucemic, aleucaemic +aleukemic, aleukaemic +Aleus's, Aloeus's +Aleus, Aloeus +algebraization's, algebraisation's +algebraization, algebraisation +algebraizations, algebraisations +algebraize, algebraise +algebraizes, algebraises +algesthesis, algaesthesis +alienize, alienise +alienizes, alienises +align, aline +aligned, alined +aligning, alining +alignment's, alinement's +alignment, alinement +alignments, alinements +aligns, alines +alkalinization's, alkalinisation's +alkalinization, alkalinisation +alkalinizations, alkalinisations +alkalinize, alkalinise +alkalinized, alkalinised +alkalinizes, alkalinises +alkalinizing, alkalinising +alkalizable, alkalisable +alkalization's, alkalisation's +alkalization, alkalisation +alkalizations, alkalisations +alkalize, alkalise +alkalized, alkalised +alkalizer's, alkaliser's +alkalizer, alkaliser +alkalizes, alkalises +alkalizing, alkalising +allegorization's, allegorisation's +allegorization, allegorisation +allegorizations, allegorisations +allegorize, allegorise +allegorized, allegorised +allegorizer's, allegoriser's +allegorizer, allegoriser +allegorizers, allegorisers +allegorizes, allegorises +allegorizing, allegorising +alleluia's, halleluiah's +alleluia, halleluiah +alleluias, halleluiahs +alloxuremia, alloxuraemia +almanac, almanack +almanacs, almanacks +alphabetization's, alphabetisation's +alphabetization, alphabetisation +alphabetizations, alphabetisations +alphabetize, alphabetise +alphabetized, alphabetised +alphabetizer's, alphabetiser's +alphabetizer, alphabetiser +alphabetizers, alphabetisers +alphabetizes, alphabetises +alphabetizing, alphabetising +alternize, alternise +alternizes, alternises +althea's, althaea's +althea, althaea +altheas, althaeas +althein, althaein +although, altho +aluminization, aluminisation +aluminize, aluminise +aluminized, aluminised +aluminizes, aluminises +aluminizing, aluminising +aluminum's, aluminium's +aluminum, aluminium +aluminums, aluminiums +alumni, alumnuses +alveole, alveolae +amalgamatize, amalgamatise +amalgamatizes, amalgamatises +amalgamization's, amalgamisation's +amalgamization, amalgamisation +amalgamizations, amalgamisations +amalgamize, amalgamise +amalgamizes, amalgamises +Amalthea's, Amalthaea's +Amalthea, Amalthaea +ambiance's, ambience's +ambiance, ambience +ambiances, ambiences +ambicolorate, ambicolourate +ambicoloration, ambicolouration +ambilevous, ambilaevous +ameban, amoeban +amebas, amebae +amebean, amoebean +amebian, amoebian +amebiases, amoebiases +amebiasis, amoebiasis +amebicidal, amoebicidal +amebicide, amoebicide +amebid, amoebid +amebiform, amoebiform +amebiosis, amoebiosis +amebocyte's, amoebocyte's +amebocyte, amoebocyte +amebocytes, amoebocytes +ameboidism's, amoeboidism's +ameboidism, amoeboidism +amebous, amoebous +amebula, amoebula +amenorrhea's, amenorrhoea's +amenorrhea, amenorrhoea +amenorrheal, amenorrhoeal +amenorrheas, amenorrhoeas +amenorrheic, amenorrhoeic +Americanization's, Americanisation's +Americanization, Americanisation +americanization, americanisation +Americanizations, Americanisations +Americanize, Americanise +Americanized, Americanised +americanized, americanised +Americanizer's, Americaniser's +Americanizer, Americaniser +Americanizers, Americanisers +Americanizes, Americanises +Americanizing, Americanising +amid, amidst +amir's, ameer's +amir, ameer +amirs, ameers +ammocete's, ammocoete's +ammocete, ammocoete +ammocetes, ammocoetes +ammoniemia, ammoniaemia +amoeba's, ameba's +amoeba, ameba +amoebic, amebic +amoeboid, ameboid +amok's, amuck's +amok, amuck +amoks, amucks +among, amongst +amoralize, amoralise +amoralizes, amoralises +amoret, amouret +amorism's, amourism's +amorism, amourism +amorisms, amourisms +amorist's, amourist's +amorist, amourist +amoristic, amouristic +amoristics, amouristics +amorists, amourists +amorphization, amorphisation +amorphize, amorphise +amortizable's, amortisable's +amortizable, amortisable +amortizabler, amortisabler +amortizables, amortisables +amortizablest, amortisablest +amortization's, amortisation's +amortization, amortisation +amortizations, amortisations +amortize, amortise +amortized, amortised +amortizement's, amortisement's +amortizement, amortisement +amortizements, amortisements +amortizes, amortises +amortizing, amortising +amphigean, amphigaean +amphitheater's, amphitheatre's +amphitheater, amphitheatre +amphitheaters, amphitheatres +ampoule's, ampul's +ampoule, ampul +ampoules, ampuls +amygdale, amygdalae +amyxorrhea, amyxorrhoea +anabaptize, anabaptise +anabaptized, anabaptised +anabaptizes, anabaptises +anabaptizing, anabaptising +anaesthetization's, anesthetisation's +anaesthetization, anesthetisation +anaesthetizations, anesthetisations +anaesthetize, anesthetise +anaesthetized, anesthetised +anaesthetizer, anesthetiser +anaesthetizers, anesthetisers +anaesthetizes, anesthetises +anaesthetizing, anesthetising +anagrammatize, anagrammatise +anagrammatized, anagrammatised +anagrammatizes, anagrammatises +anagrammatizing, anagrammatising +analogize, analogise +analogized, analogised +analogizes, analogises +analogizing, analogising +analytical, analytic +analytically, analyticalally +analyticiti, analyticaliti +analyticitis, analyticalitis +analyticity, analyticality +analyzability's, analysability's +analyzability, analysability +analyzable, analysable +analyzabler, analysabler +analyzablest, analysablest +analyzation's, analysation's +analyzation, analysation +analyzations, analysations +analyze, analyse +analyzed, analysed +analyzer's, analyser's +analyzer, analyser +analyzers, analysers +analyzes, analyses +analyzing, analysing +anapestically, anapaestically +anapneic, anapnoeic +anarchize, anarchise +anarchized, anarchised +anarchizes, anarchises +anarchizing, anarchising +anathematization's, anathematisation's +anathematization, anathematisation +anathematizations, anathematisations +anathematize, anathematise +anathematized, anathematised +anathematizer's, anathematiser's +anathematizer, anathematiser +anathematizes, anathematises +anathematizing, anathematising +anatomizable, anatomisable +anatomization's, anatomisation's +anatomization, anatomisation +anatomize, anatomise +anatomized, anatomised +anatomizer's, anatomiser's +anatomizer, anatomiser +anatomizes, anatomises +anatomizing, anatomising +Anchinoe's, Anchinoae's +Anchinoe, Anchinoae +ancille, ancillae +anematosis, anaematosis +anemia's, anaemia's +anemia, anaemia +anemias, anaemias +anemic, anaemic +anemically, anaemically +anemicer, anaemicer +anemicest, anaemicest +anemics, anaemics +aneretic, anaeretic +anesis, anoesis +anesthesia's, anaesthesia's +anesthesia, anaesthesia +anesthesiant, anaesthesiant +anesthesias, anaesthesias +anesthesiologies, anaesthesiologies +anesthesiologist's, anaesthesiologist's +anesthesiologist, anaesthesiologist +anesthesiologists, anaesthesiologists +anesthesiology's, anaesthesiology's +anesthesiology, anaesthesiology +anesthesis, anaesthesis +anesthetic's, anaesthetic's +anesthetic, anaesthetic +anesthetically, anaesthetically +anestheticer, anaestheticer +anestheticest, anaestheticest +anesthetics, anaesthetics +anesthetist's, anaesthetist's +anesthetist, anaesthetist +anesthetists, anaesthetists +anesthyl, anaesthyl +anestra, anoestra +anestri, anoestri +anestrous, anoestrous +anestrum, anoestrum +anestrus's, anoestrus's +anestrus, anoestrus +anestruses, anoestruses +anetic, anoetic +anetiological, anaetiological +aneurysm's, aneurism's +aneurysm, aneurism +aneurysms, aneurisms +angelicize, angelicise +angelicizes, angelicises +angelize, angelise +angelizes, angelises +Anglicanize's, Anglicanise's +Anglicanize, Anglicanise +Anglicanizes, Anglicanises +anglicization's, anglicisation's +anglicization, anglicisation +anglicizations, anglicisations +anglicize, anglicise +anglicized, anglicised +anglicizes, anglicises +anglicizing, anglicising +angrecum, angraecum +angularization's, angularisation's +angularization, angularisation +angularizations, angularisations +angularize, angularise +angularizes, angularises +anhematopoiesis's, anhaematopoiesis's +anhematopoiesis, anhaematopoiesis +anhematosis, anhaematosis +anhemolytic, anhaemolytic +anhydremia, anhydraemia +anhydremic, anhydraemic +anhydridization's, anhydridisation's +anhydridization, anhydridisation +anhydridizations, anhydridisations +anhydridize, anhydridise +anhydridizes, anhydridises +animalization's, animalisation's +animalization, animalisation +animalizations, animalisations +animalize, animalise +animalized, animalised +animalizes, animalises +animalizing, animalising +animized, animised +annalize, annalise +annalized, annalised +annalizes, annalises +annalizing, annalising +annualization, annualisation +annualize, annualise +annualized, annualised +annualizes, annualises +annualizing, annualising +anodization, anodisation +anodize, anodise +anodized, anodised +anodizes, anodises +anodizing, anodising +anonymize, anonymise +anonymized, anonymised +anonymizes, anonymises +anonymizing, anonymising +Anora's, Anoura's +Anora, Anoura +anoxemia's, anoxaemia's +anoxemia, anoxaemia +anoxemic, anoxaemic +anserine, anserinae +antagonizable, antagonisable +antagonization's, antagonisation's +antagonization, antagonisation +antagonizations, antagonisations +antagonize, antagonise +antagonized, antagonised +antagonizer, antagoniser +antagonizers, antagonisers +antagonizes, antagonises +antagonizing, antagonising +antennae, antenna +antennas, antenna +anthecological, anthoecological +anthecologist, anthoecologist +anthecology, anthoecology +anthologization, anthologisation +anthologize, anthologise +anthologized, anthologised +anthologizer, anthologiser +anthologizes, anthologises +anthologizing, anthologising +anthracemia, anthracaemia +anthracitization's, anthracitisation's +anthracitization, anthracitisation +anthracitizations, anthracitisations +anthropomorphization's, anthropomorphisation's +anthropomorphization, anthropomorphisation +anthropomorphizations, anthropomorphisations +anthropomorphize, anthropomorphise +anthropomorphized, anthropomorphised +anthropomorphizes, anthropomorphises +anthropomorphizing, anthropomorphising +anticatalyzer's, anticatalyser's +anticatalyzer, anticatalyser +anticatalyzers, anticatalysers +anticentralization's, anticentralisation's +anticentralization, anticentralisation +anticentralizations, anticentralisations +anticize, anticise +anticizes, anticises +antiepicenter's, antiepicentre's +antiepicenter, antiepicentre +antiepicenters, antiepicentres +antifertilizer's, antifertiliser's +antifertilizer, antifertiliser +antifertilizers, antifertilisers +antilabor's, antilabour's +antilabor, antilabour +antilabors, antilabours +antilemic, antiloemic +antimedieval, antimediaeval +antimedievalism's, antimediaevalism's +antimedievalism, antimediaevalism +antimedievalist's, antimediaevalist's +antimedievalist, antimediaevalist +antimedievally, antimediaevally +antioxidizer's, antioxidiser's +antioxidizer, antioxidiser +antioxidizers, antioxidisers +antioxidizing's, antioxidising's +antioxidizing, antioxidising +antioxidizings, antioxidisings +antipathize, antipathise +antipathizes, antipathises +antiquarianize, antiquarianise +antiquarianizes, antiquarianises +antirumor's, antirumour's +antirumor, antirumour +antirumors, antirumours +antisensitize, antisensitise +antisensitizer's, antisensitiser's +antisensitizer, antisensitiser +antisensitizers, antisensitisers +antisensitizes, antisensitises +antisepticize, antisepticise +antisepticized, antisepticised +antisepticizes, antisepticises +antisepticizing, antisepticising +antiseptize, antiseptise +antiseptizes, antiseptises +antisiphon's, antisyphon's +antisiphon, antisyphon +antisiphons, antisyphons +antithesize, antithesise +antithesizes, antithesises +anviled, anvilled +anviling, anvilling +apesthesia, apaesthesia +apesthetic, apaesthetic +aphereses, aphaereses +apheresis's, aphaeresis's +apheresis, aphaeresis +apheretic, aphaeretic +aphetize, aphetise +aphetized, aphetised +aphetizes, aphetises +aphetizing, aphetising +aphorize, aphorise +aphorized, aphorised +aphorizer's, aphoriser's +aphorizer, aphoriser +aphorizers, aphorisers +aphorizes, aphorises +aphorizing, aphorising +apnea's, apnoea's +apnea, apnoea +apneal, apnoeal +apneas, apnoeas +apneic, apnoeic +apocenter, apocentre +apogeic, apogaeic +apologize, apologise +apologized, apologised +apologizer's, apologiser's +apologizer, apologiser +apologizers, apologisers +apologizes, apologises +apologizing, apologising +apophthegmatize, apophthegmatise +apophthegmatized, apophthegmatised +apophthegmatizes, apophthegmatises +apophthegmatizing, apophthegmatising +aporrhea, aporrhoea +apostatization, apostatisation +apostatize, apostatise +apostatized, apostatised +apostatizes, apostatises +apostatizing, apostatising +apostolize, apostolise +apostolized, apostolised +apostolizes, apostolises +apostolizing, apostolising +apostrophize, apostrophise +apostrophized, apostrophised +apostrophizes, apostrophises +apostrophizing, apostrophising +apothegmatize, apothegmatise +apothegmatized, apothegmatised +apothegmatizes, apothegmatises +apothegmatizing, apothegmatising +apotheosize, apotheosise +apotheosized, apotheosised +apotheosizes, apotheosises +apotheosizing, apotheosising +appall, appal +appalls, appals +appareled, apparelled +appareling, apparelling +appendices, appendix +appendixes, appendix +appetize, appetise +appetized, appetised +appetizement's, appetisement's +appetizement, appetisement +appetizements, appetisements +appetizer's, appetiser's +appetizer, appetiser +appetizers, appetisers +appetizes, appetises +appetizing, appetising +appetizingly, appetisingly +apprizal, apprisal +apprizer, appriser +apprizers, apprisers +apprizings, apprisings +aquaculture's, aquiculture's +aquaculture, aquiculture +Arabianize's, Arabianise's +Arabianize, Arabianise +Arabianizes, Arabianises +Arabicize, Arabicise +Arabicizes, Arabicises +arabization's, arabisation's +arabization, arabisation +arabizations, arabisations +Arabize, Arabise +arabize, arabise +Arabized, Arabised +arabized, arabised +Arabizes, Arabises +arabizes, arabises +Arabizing, Arabising +arabizing, arabising +Aramean, Aramaean +Arameans, Aramaeans +arbalester, arbalestre +arbor's, arbour's +arbor, arbour +arbored, arboured +arbores, arboures +arborization's, arborisation's +arborization, arborisation +arborizations, arborisations +arborize, arborise +arborized, arborised +arborizes, arborises +arborizing, arborising +arbors, arbours +archaeologic, archeologic +archaeological, archeological +archaeologically, archeologically +archaeologies, archeologies +archaeologist's, archeologist's +archaeologist, archeologist +archaeologists, archeologists +archaeology's, archeology's +archaeology, archeology +archaize, archaise +archaized, archaised +archaizer's, archaiser's +archaizer, archaiser +archaizers, archaisers +archaizes, archaises +archaizing, archaising +arche, archae +archeal, archaeal +archean, archaean +archei, archaei +archeoastronomies, archaeoastronomies +archeoastronomy, archaeoastronomy +archeocyte's, archaeocyte's +archeocyte, archaeocyte +archeol, archaeol +archeolithic, archaeolithic +archeologian, archaeologian +archeometries, archaeometries +archeometry, archaeometry +Archeozic, Archaeozic +Archeozoic, Archaeozoic +archeozoic, archaeozoic +archetypal, archetypical +archetypally, archetypically +archeus, archaeus +arcticize, arcticise +arcticizes, arcticises +Arctogea's, Arctogaea's +Arctogea, Arctogaea +Arctogean's, Arctogaean's +Arctogean, Arctogaean +Arctogeic's, Arctogaeic's +Arctogeic, Arctogaeic +ardor's, ardour's +ardor, ardour +ardors, ardours +arenicolor, arenicolour +areole, areolae +areometric, araeometric +areometrical, araeometrical +areostyle, araeostyle +areostyles, araeostyles +areosystyle, araeosystyle +Arianize's, Arianise's +Arianize, Arianise +Arianized's, Arianised's +Arianized, Arianised +Arianizes, Arianises +Arianizing's, Arianising's +Arianizing, Arianising +Arimathea's, Arimathaea's +Arimathea, Arimathaea +Arimathean's, Arimathaean's +Arimathean, Arimathaean +ariste, aristae +arithmetization's, arithmetisation's +arithmetization, arithmetisation +arithmetizations, arithmetisations +arithmetize, arithmetise +arithmetized, arithmetised +arithmetizes, arithmetises +armor's, armour's +armor, armour +armorbearer's, armourbearer's +armorbearer, armourbearer +armored, armoured +armorer's, armourer's +armorer, armourer +armorers, armourers +armoried, armouried +armoring, armouring +armorless, armourless +armors, armours +armory's, armoury's +armory, armoury +aromatite, aromatitae +aromatization's, aromatisation's +aromatization, aromatisation +aromatize, aromatise +aromatized, aromatised +aromatizer's, aromatiser's +aromatizer, aromatiser +aromatizes, aromatises +aromatizing, aromatising +arsenicize, arsenicise +arsenicizes, arsenicises +Arsinoe's, Arsinoae's +Arsinoe, Arsinoae +arterialization's, arterialisation's +arterialization, arterialisation +arterializations, arterialisations +arterialize, arterialise +arterialized, arterialised +arterializes, arterialises +arterializing, arterialising +arthrempyesis, arthroempyesis +artifact's, artefact's +artifact, artefact +artifacts, artefacts +artificialize, artificialise +artificialized, artificialised +artificializes, artificialises +artificializing, artificialising +Aryanization, Aryanisation +Aryanize, Aryanise +Aryanized's, Aryanised's +Aryanized, Aryanised +Aryanizes, Aryanises +Aryanizing's, Aryanising's +Aryanizing, Aryanising +arytenoid, arytaenoid +arytenoids, arytaenoids +asafetida's, asafoetida's +asafetida, asafoetida +asafetidas, asafoetidas +ascendance's, ascendence's +ascendance, ascendence +ascendancy's, ascendency's +ascendancy, ascendency +ascendant's, ascendent's +ascendant, ascendent +ascendants, ascendents +Asclepiade's, Asclepiadae's +Asclepiade, Asclepiadae +Asel's, Asael's +Asel, Asael +asepticize, asepticise +asepticized, asepticised +asepticizes, asepticises +asepticizing, asepticising +asexualization's, asexualisation's +asexualization, asexualisation +asexualize, asexualise +asexualized, asexualised +asexualizing, asexualising +Asiaticization's, Asiaticisation's +Asiaticization, Asiaticisation +Asiaticizations, Asiaticisations +Asiaticize's, Asiaticise's +Asiaticize, Asiaticise +Asiaticizes, Asiaticises +Asmonean's, Asmonaean's +Asmonean, Asmonaean +aspheterize, aspheterise +aspheterized, aspheterised +aspheterizes, aspheterises +aspheterizing, aspheterising +assafetida, assafoetida +assafetidas, assafoetidas +asshole's, arsehole's +asshole, arsehole +assholes, arseholes +Assidean's, Assidaean's +Assidean, Assidaean +Assyrianize's, Assyrianise's +Assyrianize, Assyrianise +Assyrianizes, Assyrianises +Astera's, Astrea's +Astera, Astrea +astigmatizer's, astigmatiser's +astigmatizer, astigmatiser +astigmatizers, astigmatisers +Astrea's, Astraea's +Astrea, Astraea +astrean, astraean +astronomize, astronomise +astronomized, astronomised +astronomizes, astronomises +astronomizing, astronomising +asynchronize, asynchronise +asynchronized, asynchronised +asynchronizes, asynchronises +asynchronizing, asynchronising +atheize, atheise +atheized, atheised +atheizes, atheises +atheizing, atheising +athetize, athetise +athetized, athetised +athetizes, athetises +athetizing, athetising +atmolyze, atmolyse +atmolyzed, atmolysed +atmolyzes, atmolyses +atmolyzing, atmolysing +atomizability, atomisability +atomizable, atomisable +atomization's, atomisation's +atomization, atomisation +atomizations, atomisations +atomize, atomise +atomized, atomised +atomizer's, atomiser's +atomizer, atomiser +atomizers, atomisers +atomizes, atomises +atomizing, atomising +atroceruleus, atrocoeruleus +attemper, attempre +Atticize, Atticise +atticize, atticise +Atticized, Atticised +Atticizes, Atticises +atticizes, atticises +Atticizing, Atticising +attitudinization, attitudinisation +attitudinize, attitudinise +attitudinized, attitudinised +attitudinizer's, attitudiniser's +attitudinizer, attitudiniser +attitudinizers, attitudinisers +attitudinizes, attitudinises +attitudinizing, attitudinising +attitudinizings, attitudinisings +aunter, auntre +auntie's, aunty's +auntie, aunty +aureole's, aureola's +aureole, aureola +Australianize's, Australianise's +Australianize, Australianise +Australianizes, Australianises +Australopithecine's, Australopithecinae's +Australopithecine, Australopithecinae +Austrianize's, Austrianise's +Austrianize, Austrianise +Austrianizes, Austrianises +autecious, autoecious +auteciously, autoeciously +auteciousness's, autoeciousness's +auteciousness, autoeciousness +autecism's, autoecism's +autecism, autoecism +autecisms, autoecisms +autecy, autoecy +authorizable, authorisable +authorization's, authorisation's +authorization, authorisation +authorizations, authorisations +authorize, authorise +authorized, authorised +authorizer's, authoriser's +authorizer, authoriser +authorizers, authorisers +authorizes, authorises +authorizing, authorising +autocatalyze, autocatalyse +autocatalyzed, autocatalysed +autocatalyzes, autocatalyses +autocatalyzing, autocatalysing +autodialer, autodialler +autoimmunization, autoimmunisation +autoionization's, autoionisation's +autoionization, autoionisation +autolyzate, autolysate +autolyzates, autolysates +autolyze, autolyse +autolyzed, autolysed +autolyzes, autolyses +autolyzing, autolysing +automatization's, automatisation's +automatization, automatisation +automatizations, automatisations +automatize, automatise +automatized, automatised +automatizes, automatises +automatizing, automatising +Autonoe's, Autonoae's +Autonoe, Autonoae +autotomize, autotomise +autotomized, autotomised +autotomizes, autotomises +autotomizing, autotomising +autotoxemia's, autotoxaemia's +autotoxemia, autotoxaemia +autotoxemias, autotoxaemias +avianize, avianise +avianized, avianised +avianizes, avianises +avianizing, avianising +avizandum, avisandum +avizandums, avisandums +avize, avise +avized, avised +avizes, avises +avizing, avising +awestruck, awestricken +AWOL, awol +ax's, axe's +ax, axe +axiomatization's, axiomatisation's +axiomatization, axiomatisation +axiomatizations, axiomatisations +axiomatize, axiomatise +axiomatized, axiomatised +axiomatizes, axiomatises +axiomatizing, axiomatising +aye's, ay's +aye, ay +azotemia, azotaemia +azotization, azotisation +azotize, azotise +azotized, azotised +azotizes, azotises +azotizing, azotising +azotorrhea, azotorrhoea +Babelization's, Babelisation's +Babelization, Babelisation +Babelize's, Babelise's +Babelize, Babelise +Babelized's, Babelised's +Babelized, Babelised +Babelizing's, Babelising's +Babelizing, Babelising +Babylonize's, Babylonise's +Babylonize, Babylonise +Babylonizes, Babylonises +bachelorize, bachelorise +bachelorizes, bachelorises +bacillemia, bacillaemia +bacillemias, bacillaemias +bacilli, bacilluses +backpedaled, backpedalled +backpedaling, backpedalling +baconize, baconise +baconizes, baconises +bacteremia's, bacteraemia's +bacteremia, bacteraemia +bacteremias, bacteraemias +bacteria, bacteria +bacteriemia, bacteriaemia +bacterize, bacterise +bacterized, bacterised +bacterizes, bacterises +bacterizing, bacterising +baddie's, baddy's +baddie, baddy +Baer's, Bare's +Baer, Bare +balk's, baulk's +balk, baulk +Balkanization's, Balkanisation's +balkanization's, balkanisation's +Balkanization, Balkanisation +balkanization, balkanisation +Balkanizations, Balkanisations +balkanizations, balkanisations +Balkanize, Balkanise +balkanize, balkanise +Balkanized, Balkanised +balkanized, balkanised +Balkanizes, Balkanises +balkanizes, balkanises +Balkanizing, Balkanising +balkanizing, balkanising +balked, baulked +balking, baulking +balks, baulks +balladize, balladise +balladized, balladised +balladizes, balladises +balladizing, balladising +baloney's, boloney's +baloney, boloney +balsamize, balsamise +balsamizes, balsamises +banalization, banalisation +banalizations, banalisations +banalize, banalise +banalized, banalised +banalizes, banalises +banalizing, banalising +bandanna's, bandana's +bandanna, bandana +bandannas, bandanas +bandoleer's, bandolier's +bandoleer, bandolier +bandoleers, bandoliers +banister's, bannister's +banister, bannister +banisters, bannisters +banshee's, banshie's +banshee, banshie +banshees, banshies +bantamize, bantamise +bantamizes, bantamises +baptisteries, baptistries +baptistery's, baptistry's +baptistery, baptistry +baptizable's, baptisable's +baptizable, baptisable +baptizables, baptisables +baptize, baptise +baptized, baptised +baptizement's, baptisement's +baptizement, baptisement +baptizements, baptisements +baptizer's, baptiser's +baptizer, baptiser +baptizers, baptisers +baptizes, baptises +baptizing, baptising +barbarianize, barbarianise +barbarianizes, barbarianises +barbarization's, barbarisation's +barbarization, barbarisation +barbarizations, barbarisations +barbarize, barbarise +barbarized, barbarised +barbarizes, barbarises +barbarizing, barbarising +barbecue's, barbeque's +barbecue, barbeque +barbecued, barbequed +barbecues, barbeques +barbecuing, barbequing +barcarole's, barcarolle's +barcarole, barcarolle +barcaroles, barcarolles +baronetize, baronetise +baronetized, baronetised +baronetizing, baronetising +baronize, baronise +baronizes, baronises +barreled, barrelled +barreling, barrelling +bartizan, bartisan +bartizaned, bartisaned +bartizans, bartisans +barycenter, barycentre +bastardization's, bastardisation's +bastardization, bastardisation +bastardizations, bastardisations +bastardize, bastardise +bastardized, bastardised +bastardizes, bastardises +bastardizing, bastardising +bastinaded, bastinadoed +bastinades, bastinadoes +bathyscaphe's, bathyscaph's +bathyscaphe, bathyscaph +bathyscaphes, bathyscaphs +battleaxe's, battleax's +battleaxe, battleax +battologize, battologise +battologized, battologised +battologizing, battologising +beaverize, beaverise +beaverizes, beaverises +beclamor, beclamour +beclamored, beclamoured +beclamoring, beclamouring +beclamors, beclamours +becolor, becolour +becudgeled, becudgelled +becudgeling, becudgelling +bedeviled, bedevilled +bedeviling, bedevilling +bedlamize, bedlamise +bedlamized, bedlamised +bedlamizes, bedlamises +bedlamizing, bedlamising +bedriveled, bedrivelled +bedriveling, bedrivelling +Beera's, Berea's +Beera, Berea +beeves, beef +befavor, befavour +beglamor, beglamour +beglamored, beglamoured +beglamoring, beglamouring +beglamors, beglamours +behavior's, behaviour's +behavior, behaviour +behavioral, behavioural +behavioraler, behaviouraler +behavioralest, behaviouralest +behaviorally, behaviourally +behaviored, behavioured +behaviorism's, behaviourism's +behaviorism, behaviourism +behaviorisms, behaviourisms +behaviorist's, behaviourist's +behaviorist, behaviourist +behavioristic, behaviouristic +behavioristicer, behaviouristicer +behavioristicest, behaviouristicest +behavioristics, behaviouristics +behaviorists, behaviourists +behaviors, behaviours +Behmenism's, Boehmenism's +Behmenism, Boehmenism +behmenism, boehmenism +Behmenist's, Boehmenist's +Behmenist, Boehmenist +Behmenite's, Boehmenite's +Behmenite, Boehmenite +behoove's, behove's +behoove, behove +behooved, behoved +behooves, behoves +behooving's, behoving's +behooving, behoving +behoovingly, behovingly +behoovings, behovings +bejeweled, bejewelled +bejeweling, bejewelling +bel's, bael's +bel, bael +belabor's, belabour's +belabor, belabour +belabored, belaboured +belaboring, belabouring +belabors, belabours +bels, baels +Belter's, Boelter's +Belter, Boelter +Belus's, Boelus's +Belus, Boelus +bemedaled, bemedalled +Beria's, Baeria's +Beria, Baeria +berk, burk +berks, burks +Berl's, Baerl's +Berl, Baerl +Berlinize's, Berlinise's +Berlinize, Berlinise +Berlinizes, Berlinises +berloque, breloque +berme, breme +bern, bren +Bessemerize's, Bessemerise's +Bessemerize, Bessemerise +Bessemerizes, Bessemerises +bestialize, bestialise +bestialized, bestialised +bestializes, bestialises +bestializing, bestialising +beveled, bevelled +beveler's, beveller's +beveler, beveller +bevelers, bevellers +beveling, bevelling +bevelings, bevellings +Beyer's, Baeyer's +Beyer, Baeyer +biased, biassed +biasing, biassing +bichromatize, bichromatise +bichromatizes, bichromatises +bicolor's, bicolour's +bicolor, bicolour +bicolored, bicoloured +bicoloredder, bicolouredder +bicoloreddest, bicoloureddest +bicolorous, bicolourous +bicolorrer, bicolourer +bicolorrest, bicolourest +bicolors, bicolours +bimetalist, bimetallist +bimetalistic, bimetallistic +bingeing, binging +biocenology, biocoenology +biocenose, biocoenose +biocenoses, biocoenoses +biocenosis, biocoenosis +biocenotic, biocoenotic +biographize, biographise +biographizes, biographises +biologize, biologise +biologizes, biologises +biosynthesized, biosynthesised +bipolarization, bipolarisation +bipolarize, bipolarise +bipolarizes, bipolarises +Birminghamize's, Birminghamise's +Birminghamize, Birminghamise +Birminghamizes, Birminghamises +bister's, bistre's +bister, bistre +bistered, bistred +bisteredder, bistredder +bistereddest, bistreddest +bisters, bistres +bittor, bittour +bittors, bittours +bituminization's, bituminisation's +bituminization, bituminisation +bituminizations, bituminisations +bituminize, bituminise +bituminized, bituminised +bituminizes, bituminises +bituminizing, bituminising +bize's, bise's +bize, bise +bizet, biset +blaize, blaise +blamable, blameable +blastocele, blastocoele +blastule, blastulae +blennemesis, blennoemesis +blennorrhea, blennorrhoea +blowzier, blowsier +blowziest, blowsiest +blowzy, blowsy +bluing's, blueing's +bluing, blueing +bo's'n's, bos'n's +bo'suns, bos'ns +bocce's, bocci's +bocce, bocci +Boedromius's, Boaedromius's +Boedromius, Boaedromius +bogeyed, bogied +bogeying, bogieing +bogeys, bogies +bogie's, bogey's +bogie, bogey +bogies, bogeys +bogy's, bogie's +bogy, bogie +boled, boloed +Bolshevize, Bolshevise +bolshevize, bolshevise +Bolshevized, Bolshevised +bolshevized, bolshevised +bolshevizes, bolshevises +Bolshevizing, Bolshevising +bolshevizing, bolshevising +bolshie, bolshy +bonderize, bonderise +bonny, bonnie +bony, boney +boogeyman's, boogerman's +boogeyman, boogerman +boogeymen, boogermans +boombox's, boom_box's +boombox, boom_box +boomboxes, boom_boxes +bor, bour +borage, bourage +borasque, bourasque +bord, bourd +bords, bourds +borg, bourg +borize, borise +borizes, borises +borscht's, borsch's +borscht, borsch +bos'n, bo's'n +Boswellize, Boswellise +Boswellized, Boswellised +Boswellizes, Boswellises +Boswellizing, Boswellising +botanize, botanise +botanized, botanised +botanizer's, botaniser's +botanizer, botaniser +botanizes, botanises +botanizing, botanising +boulder's, bowlder's +boulder, bowlder +boulders, bowlders +boulevardize, boulevardise +boulevardizes, boulevardises +bourbonize, bourbonise +bourbonizes, bourbonises +bowdlerization's, bowdlerisation's +bowdlerization, bowdlerisation +bowdlerizations, bowdlerisations +bowdlerize, bowdlerise +bowdlerized, bowdlerised +bowdlerizer's, bowdleriser's +bowdlerizer, bowdleriser +bowdlerizers, bowdlerisers +bowdlerizes, bowdlerises +bowdlerizing, bowdlerising +boweled, bowelled +boweling, bowelling +bradypnea, bradypnoea +breathalyze, breathalyse +breathalyzed, breathalysed +breathalyzer's, breathalyser's +breathalyzer, breathalyser +breathalyzers, breathalysers +breathalyzes, breathalyses +breathalyzing, breathalysing +brier's, briar's +brier, briar +briers, briars +brimful, brimfull +brinkmanship's, brinksmanship's +brinkmanship, brinksmanship +briquette's, briquet's +briquette, briquet +briquettes, briquets +briza's, brisa's +briza, brisa +bromethylene, bromoethylene +brominize, brominise +brominizes, brominises +bromization's, bromisation's +bromization, bromisation +bromize, bromise +bromized, bromised +bromizing, bromising +bronco's, broncho's +bronco, broncho +broncos, bronchos +brusque, brusk +brusquely, bruskly +brusqueness's, bruskness's +brusqueness, bruskness +brusquenesses, brusknesses +brusquer, brusker +brusquest, bruskest +brutalization's, brutalisation's +brutalization, brutalisation +brutalizations, brutalisations +brutalize, brutalise +brutalized, brutalised +brutalizes, brutalises +brutalizing, brutalising +Budenny's, Budaenny's +Budenny, Budaenny +bunco's, bunko's +bunco, bunko +buncoed, bunkoed +buncoing, bunkoing +buncos, bunkos +bunkum's, buncombe's +bunkum, buncombe +bunkums, buncombes +bureaucratization's, bureaucratisation's +bureaucratization, bureaucratisation +bureaucratizations, bureaucratisations +bureaucratize, bureaucratise +bureaucratized, bureaucratised +bureaucratizes, bureaucratises +bureaucratizing, bureaucratising +burglarize, burglarise +burglarized, burglarised +burglarizes, burglarises +burglarizing, burglarising +burnettize, burnettise +burnettized, burnettised +burnettizes, burnettises +burnettizing, burnettising +burnoose's, burnous's +burnoose, burnous +burnooses, burnouses +burqa's, burkha's +burqa, burkha +burqas, burkhas +busheled, bushelled +busheler's, busheller's +busheler, busheller +bushelers, bushellers +busheling, bushelling +bushelings, bushellings +bylaw's, byelaw's +bylaw, byelaw +bylaws, byelaws +Byronize's, Byronise's +Byronize, Byronise +Byronizes, Byronises +Byzantinize's, Byzantinise's +Byzantinize, Byzantinise +Byzantinizes, Byzantinises +cabbala, cabbalah +cabby's, cabbie's +cabby, cabbie +cacesthesia, cacaesthesia +cachemia, cachaemia +cachemic, cachaemic +cacodemon, cacodaemon +cacodemoniac, cacodaemoniac +cacodemonial, cacodaemonial +cacodemonic, cacodaemonic +cacodemons, cacodaemons +cacoethes's, cacoaethes's +cacoethes, cacoaethes +cadaster's, cadastre's +cadaster, cadastre +cadasters, cadastres +cadaverize, cadaverise +cadaverizes, cadaverises +cadmiumize, cadmiumise +cadmiumizes, cadmiumises +caesarian's, cesarian's +caesarian, cesarian +caesarians, cesarians +Caesarize's, Caesarise's +Caesarize, Caesarise +Caesarizes, Caesarises +caffer, caffre +caftan's, kaftan's +caftan, kaftan +caftans, kaftans +cagey, cagy +caginess's, cageyness's +caginess, cageyness +caginesses, cageynesses +caiman's, cayman's +caiman, cayman +caimans, caymans +calander, calandre +calcemia, calcaemia +calendarization, calendarisation +calendarizations, calendarisations +calendarize, calendarise +calendarized, calendarised +calendarizes, calendarises +calendarizing, calendarising +Calender's, Calendre's +Calender, Calendre +caliber's, calibre's +caliber, calibre +calibers, calibres +calif's, khalif's +calif, khalif +califs, khalifs +caliper's, calliper's +caliper, calliper +calipered, callipered +calipering, callipering +calipers, callipers +calisthenic, callisthenic +calisthenics, callisthenics +calk's, caulk's +calk, caulk +calked, caulked +calking, caulking +calks, caulks +Callirrhoe's, Callirrhoae's +Callirrhoe, Callirrhoae +calodemon, calodaemon +Calvinize's, Calvinise's +Calvinize, Calvinise +Calvinizes, Calvinises +camisades, camisadoes +camize, camise +Canadianization's, Canadianisation's +Canadianization, Canadianisation +Canadianizations, Canadianisations +Canadianize's, Canadianise's +Canadianize, Canadianise +Canadianizes, Canadianises +canaled, canalled +canaler, canaller +canalers, canallers +canaling, canalling +canalization's, canalisation's +canalization, canalisation +canalizations, canalisations +canalize, canalise +canalized, canalised +canalizes, canalises +canalizing, canalising +Cananean's, Cananaean's +Cananean, Cananaean +cancelable, cancellable +cancelate, cancellate +cancelated, cancellated +canceled, cancelled +canceler's, canceller's +canceler, canceller +cancelers, cancellers +canceling, cancelling +cancellation, cancelation +cancelous, cancellous +candor's, candour's +candor, candour +candors, candours +canephore, canephorae +canephore, canephoroe +canisterization, canisterisation +canisterizations, canisterisations +canisterize, canisterise +canisterized, canisterised +canisterizes, canisterises +canisterizing, canisterising +cannibalization's, cannibalisation's +cannibalization, cannibalisation +cannibalizations, cannibalisations +cannibalize, cannibalise +cannibalized, cannibalised +cannibalizes, cannibalises +cannibalizing, cannibalising +canonicalization, canonicalisation +canonicalize, canonicalise +canonicalized, canonicalised +canonicalizes, canonicalises +canonicalizing, canonicalising +canonization's, canonisation's +canonization, canonisation +canonizations, canonisations +canonize, canonise +canonized, canonised +canonizer's, canoniser's +canonizer, canoniser +canonizers, canonisers +canonizes, canonises +canonizing, canonising +cantaloupe's, cantaloup's +cantaloupe, cantaloup +cantaloupes, cantaloups +cantonization, cantonisation +cantonizations, cantonisations +cantonize, cantonise +cantonized, cantonised +cantonizes, cantonises +cantonizing, cantonising +capitalizable's, capitalisable's +capitalizable, capitalisable +capitalizabler, capitalisabler +capitalizables, capitalisables +capitalizablest, capitalisablest +capitalization's, capitalisation's +capitalization, capitalisation +capitalizations, capitalisations +capitalize, capitalise +capitalized, capitalised +capitalizer's, capitaliser's +capitalizer, capitaliser +capitalizers, capitalisers +capitalizes, capitalises +capitalizing, capitalising +caponization's, caponisation's +Caponization, Caponisation +caponization, caponisation +caponize, caponise +caponized, caponised +caponizer's, caponiser's +caponizer, caponiser +caponizes, caponises +caponizing, caponising +capsulization, capsulisation +capsulize, capsulise +capsulized, capsulised +capsulizes, capsulises +capsulizing, capsulising +caracoled, caracolled +caracoling, caracolling +caramelization's, caramelisation's +caramelization, caramelisation +caramelizations, caramelisations +caramelize, caramelise +caramelized, caramelised +caramelizes, caramelises +caramelizing, caramelising +caravansarais, caravansarai +caravansary's, caravanserai's +caravansary, caravanserai +carbolization, carbolisation +carbolize, carbolise +carbolized, carbolised +carbolizes, carbolises +carbolizing, carbolising +carbonades, carbonadoes +carbonatization's, carbonatisation's +carbonatization, carbonatisation +carbonatizations, carbonatisations +carbonizable's, carbonisable's +carbonizable, carbonisable +carbonizabler, carbonisabler +carbonizables, carbonisables +carbonizablest, carbonisablest +carbonization's, carbonisation's +carbonization, carbonisation +carbonizations, carbonisations +carbonize, carbonise +carbonized, carbonised +carbonizer's, carboniser's +carbonizer, carboniser +carbonizers, carbonisers +carbonizes, carbonises +carbonizing, carbonising +carburettor's, carburetter's +carburettor, carburetter +carburettors, carburetters +carburization's, carburisation's +carburization, carburisation +carburizations, carburisations +carburize, carburise +carburized, carburised +carburizer's, carburiser's +carburizer, carburiser +carburizes, carburises +carburizing, carburising +cardie, cardiae +cardueline, carduelinae +carnalize, carnalise +carnalized, carnalised +carnalizes, carnalises +carnalizing, carnalising +carney's, carnie's +carney, carnie +carnies, carneys +caroled, carolled +caroler's, caroller's +caroler, caroller +carolers, carollers +caroling, carolling +carotinemia, carotinaemia +carousel's, carrousel's +carousel, carrousel +carousels, carrousels +cartelization's, cartelisation's +cartelization, cartelisation +cartelizations, cartelisations +cartelize, cartelise +cartelized, cartelised +cartelizes, cartelises +cartelizing, cartelising +caster's, castor's +caster's, castor's +caster, castor +caster, castor +casters, castors +casters, castors +castorized's, castorised's +castorized, castorised +castorizeds, castoriseds +casualization, casualisation +casualizations, casualisations +casualize, casualise +casualized, casualised +casualizes, casualises +casualizing, casualising +catabolize, catabolise +catalog's, catalogue's +catalog, catalogue +cataloged, catalogued +cataloger's, cataloguer's +cataloger, cataloguer +catalogers, cataloguers +cataloging, cataloguing +catalogs, catalogues +cataloguize, cataloguise +cataloguized, cataloguised +cataloguizes, cataloguises +cataloguizing, cataloguising +catalyze, catalyse +catalyzed, catalysed +catalyzer's, catalyser's +catalyzer, catalyser +catalyzers, catalysers +catalyzes, catalyses +catalyzing, catalysing +catechizable's, catechisable's +catechizable, catechisable +catechizabler, catechisabler +catechizables, catechisables +catechizablest, catechisablest +catechization's, catechisation's +catechization, catechisation +catechizations, catechisations +catechize, catechise +catechized, catechised +catechizer's, catechiser's +catechizer, catechiser +catechizers, catechisers +catechizes, catechises +catechizing, catechising +catechizings, catechisings +categorization's, categorisation's +categorization, categorisation +categorizations, categorisations +categorize, categorise +categorized, categorised +categorizer, categoriser +categorizers, categorisers +categorizes, categorises +categorizing, categorising +catharize, catharise +catharized, catharised +catharizes, catharises +catharizing, catharising +catheterization's, catheterisation's +catheterization, catheterisation +catheterizations, catheterisations +catheterize, catheterise +catheterized, catheterised +catheterizes, catheterises +catheterizing, catheterising +catholicization's, catholicisation's +Catholicization, Catholicisation +catholicization, catholicisation +catholicizations, catholicisations +catholicize, catholicise +Catholicized, Catholicised +catholicized, catholicised +catholicizer's, catholiciser's +catholicizer, catholiciser +catholicizers, catholicisers +catholicizes, catholicises +Catholicizing, Catholicising +catholicizing, catholicising +catsup's, catchup's +catsup, catchup +catsups, catchups +cauldron's, caldron's +cauldron, caldron +cauldrons, caldrons +caulk, calk +caulked, calked +caulking, calking +caulks, calks +causticization's, causticisation's +causticization, causticisation +causticizations, causticisations +causticize, causticise +causticizer, causticiser +causticizers, causticisers +causticizes, causticises +cauterization's, cauterisation's +cauterization, cauterisation +cauterizations, cauterisations +cauterize, cauterise +cauterized, cauterised +cauterizes, cauterises +cauterizing, cauterising +caviar's, caviare's +caviar, caviare +caviars, caviares +cavilation, cavillation +caviled, cavilled +caviler's, caviller's +caviler, caviller +cavilers, cavillers +caviling, cavilling +cavilings, cavillings +ce, coe +cecally, caecally +cecitis, caecitis +cecitises, caecitises +cecity, caecity +cecostomy, caecostomy +cecotomy, caecotomy +Celastraceae's, Coelastraceae's +Celastraceae, Coelastraceae +celastraceous, coelastraceous +celestialize, celestialise +celestializes, celestialises +celestine, coelestine +celiac, coeliac +celiacs, coeliacs +celialgia, coelialgia +celiomyalgia, coeliomyalgia +celiorrhea, coeliorrhea +celioscopy, coelioscopy +celiotomy, coeliotomy +celom's, coelom's +celom, coelom +celoma, coeloma +celomata, coelomata +celoscope's, coeloscope's +celoscope, coeloscope +Celticize's, Celticise's +Celticize, Celticise +Celticizes, Celticises +cenacle's, coenacle's +cenacle, coenacle +cenaculum, coenaculum +cenesthesia's, coenesthesia's +cenesthesia, coenesthesia +cenesthesias, coenesthesias +cenesthesis, coenesthesis +Cenis's, Caenis's +Cenis, Caenis +cenobe, coenobe +cenobite's, coenobite's +cenobite, coenobite +cenobites, coenobites +cenobitic, coenobitic +cenobitical, coenobitical +cenobitism's, coenobitism's +cenobitism, coenobitism +cenobium, coenobium +cenoby, coenoby +cenogenetic, caenogenetic +cenogenetic, coenogenetic +cenogenetically, caenogenetically +cenosite, coenosite +cenospecies, coenospecies +cenospecific, coenospecific +cenospecifically, coenospecifically +cenozoic, caenozoic +center's, centre's +center, centre +centerable's, centreable's +centerable, centreable +centerables, centreables +centerboard's, centreboard's +centerboard, centreboard +centerboards, centreboards +centered, centred +centerer, centrer +centerers, centrers +centerfold's, centrefold's +centerfold, centrefold +centerfolds, centrefolds +centering's, centring's +centering, centring +centerings, centrings +centerless, centreless +centerlesser, centrelesser +centerlessest, centrelessest +centerline's, centreline's +centerline, centreline +centerlines, centrelines +centermost, centremost +centerpiece's, centrepiece's +centerpiece, centrepiece +centerpieces, centrepieces +centers, centres +Centerville's, Centreville's +Centerville, Centreville +centigram's, centigramme's +centigram, centigramme +centigrams, centigrammes +centiliter's, centilitre's +centiliter, centilitre +centiliters, centilitres +centimeter's, centimetre's +centimeter, centimetre +centimeters, centimetres +centralization's, centralisation's +centralization, centralisation +centralizations, centralisations +centralize, centralise +centralized, centralised +centralizer's, centraliser's +centralizer, centraliser +centralizers, centralisers +centralizes, centralises +centralizing, centralising +centrifugalization's, centrifugalisation's +centrifugalization, centrifugalisation +centrifugalizations, centrifugalisations +centrifugalize, centrifugalise +centrifugalized, centrifugalised +centrifugalizes, centrifugalises +centrifugalizing, centrifugalising +cephalization's, cephalisation's +cephalization, cephalisation +cephalizations, cephalisations +cer, cre +cera, crea +cerat, creat +ceratin, creatin +ceratins, creatins +cere's, cree's +cere, cree +cerebralization's, cerebralisation's +cerebralization, cerebralisation +cerebralizations, cerebralisations +cerebralize, cerebralise +cerebralizes, cerebralises +ceremonialize, ceremonialise +ceremonializes, ceremonialises +ceres, crees +cerolite, creolite +cerule, caerule +ceruleolactite, coeruleolactite +cesar, caesar +Cesaria's, Caesaria's +Cesaria, Caesaria +cesious, caesious +cesium's, caesium's +cesium, caesium +cesiums, caesiums +cespitose, caespitose +cespitosely, caespitosely +cestus, caestus +cestuses, caestuses +cesural, caesural +cetus, coetus +chaces, chacoes +chalaze, chalazae +Chaldeans, Chaldaeans +chameleonize, chameleonise +chameleonizes, chameleonises +Chamizal's, Chamisal's +Chamizal, Chamisal +chamomile's, camomile's +chamomile, camomile +chamomiles, camomiles +championize, championise +championizes, championises +channeled, channelled +channeler's, channeller's +channeler, channeller +channelers, channellers +channeling, channelling +channelization's, channelisation's +channelization, channelisation +channelizations, channelisations +channelize, channelise +channelized, channelised +channelizes, channelises +channelizing, channelising +chaperon's, chaperone's +chaperon, chaperone +chaperons, chaperones +chaptalization, chaptalisation +chaptalizations, chaptalisations +chaptalize, chaptalise +chaptalized, chaptalised +chaptalizes, chaptalises +chaptalizing, chaptalising +characterizable's, characterisable's +characterizable, characterisable +characterizabler, characterisabler +characterizables, characterisables +characterizablest, characterisablest +characterization's, characterisation's +characterization, characterisation +characterizations, characterisations +characterize, characterise +characterized, characterised +characterizer's, characteriser's +characterizer, characteriser +characterizers, characterisers +characterizes, characterises +characterizing, characterising +charer, charre +chattelization's, chattelisation's +chattelization, chattelisation +chattelizations, chattelisations +chattelize, chattelise +chattelizes, chattelises +checkbook's, chequebook's +checkbook, chequebook +checkbooks, chequebooks +checkerboard's, chequerboard's +checkerboard, chequerboard +checkerboards, chequerboards +cheerfulize, cheerfulise +cheerfulizes, cheerfulises +cheerly, cherely +chelicere, chelicerae +chemicalization's, chemicalisation's +chemicalization, chemicalisation +chemicalizations, chemicalisations +chemicalize, chemicalise +chemicalizes, chemicalises +chenix, choenix +chenixes, choenixes +chetopod, chaetopod +chiffer, chiffre +childer, childre +chile's, chilli's +chile, chilli +chilis, chillies +chimera's, chimaera's +chimera, chimaera +chimeras, chimaeras +chimerid, chimaerid +chimerids, chimaerids +chimerism, chimaerism +chimerisms, chimaerisms +chiseled, chiselled +chiseler's, chiseller's +chiseler, chiseller +chiselers, chisellers +chiseling, chiselling +chitlins's, chitlings's +chitlins, chitlings +chivied, chivvied +chivies, chivvies +chivy, chivvy +chivying, chivvying +chloranemia, chloranaemia +chloremia, chloraemia +chloridize, chloridise +chloridized, chloridised +chloridizes, chloridises +chloridizing, chloridising +chlorinize, chlorinise +chlorinized, chlorinised +chlorinizes, chlorinises +chlorinizing, chlorinising +chloritization, chloritisation +chloritizations, chloritisations +chloroanemia, chloroanaemia +chloroformization's, chloroformisation's +chloroformization, chloroformisation +chloroformizations, chloroformisations +chloroformize, chloroformise +chloroformizes, chloroformises +chlorophyll's, chlorophyl's +chlorophyll, chlorophyl +chlorophylls, chlorophyls +chocoholic's, chocaholic's +chocoholic, chocaholic +chocoholics, chocaholics +chocolaty, chocolatey +Choephori's, Choaephori's +Choephori, Choaephori +cholemia, cholaemia +cholemias, cholaemias +cholophein, cholophaein +choosy, choosey +chorization's, chorisation's +chorization, chorisation +chorizations, chorisations +Christianization's, Christianisation's +Christianization, Christianisation +christianization, christianisation +Christianizations, Christianisations +christianizations, christianisations +Christianize, Christianise +christianize, christianise +Christianized, Christianised +christianized, christianised +Christianizer's, Christianiser's +Christianizer, Christianiser +christianizer, christianiser +Christianizers, Christianisers +christianizers, christianisers +Christianizes, Christianises +christianizes, christianises +Christianizing, Christianising +christianizing, christianising +chromatize, chromatise +chromatizes, chromatises +chromesthesia, chromaesthesia +chromicize, chromicise +chromicizes, chromicises +chromize, chromise +chromized, chromised +chromizes, chromises +chromizing, chromising +chronologize, chronologise +chronologized, chronologised +chronologizes, chronologises +chronologizing, chronologising +chutzpa's, hutzpah's +chutzpa, hutzpah +chutzpas, hutzpahes +cicatrices, cicatrixes +cicatricule, cicatriculae +cicatrix's, cicatrice's +cicatrix, cicatrice +cicatrizant, cicatrisant +cicatrizate, cicatrisate +cicatrization's, cicatrisation's +cicatrization, cicatrisation +cicatrizations, cicatrisations +cicatrize, cicatrise +cicatrized, cicatrised +cicatrizer's, cicatriser's +cicatrizer, cicatriser +cicatrizes, cicatrises +cicatrizing, cicatrising +Ciceronianize's, Ciceronianise's +Ciceronianize, Ciceronianise +Ciceronianizes, Ciceronianises +cigarette's, cigaret's +cigarette, cigaret +cigarettes, cigarets +cimicide, cimicidae +cinchonization's, cinchonisation's +cinchonization, cinchonisation +cinchonizations, cinchonisations +cinchonize, cinchonise +cinchonized, cinchonised +cinchonizes, cinchonises +cinchonizing, cinchonising +cinematize, cinematise +cinter, cintre +cipher's, cypher's +cipher, cypher +ciphered, cyphered +ciphering, cyphering +ciphers, cyphers +Circean, Circaean +circularization's, circularisation's +circularization, circularisation +circularizations, circularisations +circularize, circularise +circularized, circularised +circularizer's, circulariser's +circularizer, circulariser +circularizers, circularisers +circularizes, circularises +circularizing, circularising +circumcenter, circumcentre +circumcenters, circumcentres +circumesophagal, circumoesophagal +cithern, cithren +citherns, cithrens +citizenize, citizenise +citizenized, citizenised +citizenizes, citizenises +citizenizing, citizenising +civilianization, civilianisation +civilianizations, civilianisations +civilianize, civilianise +civilianized, civilianised +civilianizes, civilianises +civilianizing, civilianising +civilizable's, civilisable's +civilizable, civilisable +civilizabler, civilisabler +civilizables, civilisables +civilizablest, civilisablest +civilization's, civilisation's +civilization, civilisation +civilizational's, civilisational's +civilizational, civilisational +civilizationaler, civilisationaler +civilizationalest, civilisationalest +civilizationals, civilisationals +civilizations, civilisations +civilizatory, civilisatory +civilize, civilise +civilized, civilised +civilizedness's, civilisedness's +civilizedness, civilisedness +civilizednesses, civilisednesses +civilizer's, civiliser's +civilizer, civiliser +civilizers, civilisers +civilizes, civilises +civilizing, civilising +civvies, civies +civvy's, civie's +civvy, civie +cize, cise +clamor's, clamour's +clamor, clamour +clamored, clamoured +clamorer's, clamourer's +clamorer, clamourer +clamorers, clamourers +clamoring, clamouring +clamorist's, clamourist's +clamorist, clamourist +clamors, clamours +clamorsome, clamoursome +clangor's, clangour's +clangor, clangour +clangored, clangoured +clangoring, clangouring +clangors, clangours +clares, claroes +clarinetist's, clarinettist's +clarinetist, clarinettist +clarinetists, clarinettists +classicalize, classicalise +classicalizes, classicalises +classicization, classicisation +classicize, classicise +classicized, classicised +classicizes, classicises +classicizing, classicising +clausule, clausulae +clericalize, clericalise +clericalizes, clericalises +Clete's, Cloete's +Clete, Cloete +climatize, climatise +climatized, climatised +climatizes, climatises +climatizing, climatising +clower, clowre +Clytie's, Clytiae's +Clytie, Clytiae +coalize, coalise +coalized, coalised +coalizer, coaliser +coalizers, coalisers +coalizes, coalises +coalizing, coalising +cocaine's, cocain's +cocaine, cocain +cocainization's, cocainisation's +cocainization, cocainisation +cocainizations, cocainisations +cocainize, cocainise +cocainized, cocainised +cocainizes, cocainises +cocainizing, cocainising +coconut's, cocoanut's +coconut, cocoanut +coconuts, cocoanuts +cocuiza, cocuisa +Coe's, Cooe's +Coe, Cooe +coeducationalize, coeducationalise +coeducationalizes, coeducationalises +coeloms, coelomata +coenamor, coenamour +coenamored, coenamoured +coenamoring, coenamouring +coenamorment, coenamourment +coenamors, coenamours +coequalize, coequalise +coequalizes, coequalises +cognizability's, cognisability's +cognizability, cognisability +cognizable, cognisable +cognizableness's, cognisableness's +cognizableness, cognisableness +cognizabler, cognisabler +cognizablest, cognisablest +cognizablier, cognisablier +cognizabliest, cognisabliest +cognizably, cognisably +cognizance's, cognisance's +cognizance, cognisance +cognizances, cognisances +cognizant, cognisant +cognizanter, cognisanter +cognizantest, cognisantest +cognize, cognise +cognized, cognised +cognizer's, cogniser's +cognizer, cogniser +cognizers, cognisers +cognizes, cognises +cognizing, cognising +colander's, cullender's +colander, cullender +colanders, cullenders +collateralize, collateralise +collectibilities, collectabilities +collectibility's, collectability's +collectibility, collectability +collectible's, collectable's +collectible, collectable +collectibles, collectables +collectivization's, collectivisation's +collectivization, collectivisation +collectivizations, collectivisations +collectivize, collectivise +collectivized, collectivised +collectivizes, collectivises +collectivizing, collectivising +colloquialize, colloquialise +colloquializes, colloquialises +colloquize, colloquise +colloquized, colloquised +colloquizes, colloquises +colloquizing, colloquising +colonialize, colonialise +colonialized, colonialised +colonializes, colonialises +colonializing, colonialising +colonizabilities, colonisabilities +colonizability's, colonisability's +colonizability, colonisability +colonizable's, colonisable's +colonizable, colonisable +colonizabler, colonisabler +colonizables, colonisables +colonizablest, colonisablest +colonization's, colonisation's +colonization, colonisation +colonizationist's, colonisationist's +colonizationist, colonisationist +colonizationists, colonisationists +colonizations, colonisations +colonize, colonise +colonized, colonised +colonizer's, coloniser's +colonizer, coloniser +colonizers, colonisers +colonizes, colonises +colonizing, colonising +color's, colour's +color, colour +colorabilities, colourabilities +colorability's, colourability's +colorability, colourability +colorable's, colourable's +colorable, colourable +colorableness's, colourableness's +colorableness, colourableness +colorablenesses, colourablenesses +colorabler, colourabler +colorables, colourables +colorablest, colourablest +colorablier, colourablier +colorablies, colourablies +colorabliest, colourabliest +colorably, colourably +coloradoite's, colouradoite's +coloradoite, colouradoite +colorama, colourama +colorant's, colourant's +colorant, colourant +colorants, colourants +colorate, colourate +coloration's, colouration's +coloration, colouration +colorational, colourational +colorationaler, colourationaler +colorationalest, colourationalest +colorationallier, colourationallier +colorationalliest, colourationalliest +colorationally, colourationally +colorations, colourations +colorative, colourative +colorbearer's, colourbearer's +colorbearer, colourbearer +colorblind, colourblind +colorblindness's, colourblindness's +colorblindness, colourblindness +colorblindnesses, colourblindnesses +colorbred, colourbred +colorbreed, colourbreed +colorbreeding, colourbreeding +colorbreeds, colourbreeds +colorcast's, colourcast's +colorcast, colourcast +colorcasted, colourcasted +colorcaster, colourcaster +colorcasters, colourcasters +colorcasting, colourcasting +colorcasts, colourcasts +colorectal, colourectal +colorectitis, colourectitis +colorectostomy, colourectostomy +colored's, coloured's +colored, coloured +coloreds, coloureds +colorer's, colourer's +colorer, colourer +colorers, colourers +colorfast, colourfast +colorfastness's, colourfastness's +colorfastness, colourfastness +colorfastnesses, colourfastnesses +colorful, colourful +colorfuler, colourfuler +colorfulest, colourfulest +colorfullier, colourfullier +colorfulliest, colourfulliest +colorfully, colourfully +colorfulness's, colourfulness's +colorfulness, colourfulness +colorfulnesses, colourfulnesses +colorific's, colourific's +colorific, colourific +colorifics, colourifics +colorimeter's, colourimeter's +colorimeter, colourimeter +colorimeters, colourimeters +colorimetric, colourimetric +colorimetrical, colourimetrical +colorimetrically, colourimetrically +colorimetrics, colourimetrics +colorimetries, colourimetries +colorimetrist's, colourimetrist's +colorimetrist, colourimetrist +colorimetry, colourimetry +coloring's, colouring's +coloring, colouring +colorings, colourings +colorism, colourism +colorisms, colourisms +colorist's, colourist's +colorist, colourist +coloristic, colouristic +coloristically, colouristically +coloristicer, colouristicer +coloristicest, colouristicest +coloristics, colouristics +colorists, colourists +colorless, colourless +colorlesser, colourlesser +colorlessest, colourlessest +colorlesslier, colourlesslier +colorlessliest, colourlessliest +colorlessly, colourlessly +colorlessness's, colourlessness's +colorlessness, colourlessness +colorlessnesses, colourlessnesses +colormaker, colourmaker +colormaking, colourmaking +colorman's, colourman's +colorman, colourman +colormap's, colourmap's +colormap, colourmap +colormaps, colourmaps +colormen, colourmen +coloroto, colouroto +colorpoint, colourpoint +colorpoints, colourpoints +colorrest, colourest +colorrhaphy, colourrhaphy +colors, colours +colortype, colourtype +colorway, colourway +colorways, colourways +colory, coloury +colourisation's, colourization's +colourisation, colourization +colourisations, colourizations +colourise, colourize +colourised, colourized +colourises, colourizes +colourising, colourizing +columnization's, columnisation's +columnization, columnisation +columnizations, columnisations +columnize, columnise +columnized, columnised +columnizes, columnises +columnizing, columnising +comedia, comoedia +commercialization's, commercialisation's +commercialization, commercialisation +commercializations, commercialisations +commercialize, commercialise +commercialized, commercialised +commercializes, commercialises +commercializing, commercialising +commonize, commonise +commonizes, commonises +communalization's, communalisation's +communalization, communalisation +communalizations, communalisations +communalize, communalise +communalized, communalised +communalizer's, communaliser's +communalizer, communaliser +communalizers, communalisers +communalizes, communalises +communalizing, communalising +communization's, communisation's +communization, communisation +communizations, communisations +communize, communise +communized, communised +communizes, communises +communizing, communising +companionize, companionise +companionizes, companionises +compartmentalization's, compartmentalisation's +compartmentalization, compartmentalisation +compartmentalizations, compartmentalisations +compartmentalize, compartmentalise +compartmentalized, compartmentalised +compartmentalizes, compartmentalises +compartmentalizing, compartmentalising +compartmentize, compartmentise +compartmentizes, compartmentises +comper, compoer +complementizer's, complementiser's +complementizer, complementiser +Composite, Compositae +comprehensivization, comprehensivisation +comprehensivizations, comprehensivisations +comprehensivize, comprehensivise +comprehensivized, comprehensivised +comprehensivizes, comprehensivises +comprehensivizing, comprehensivising +comprizable, comprisable +comprizal's, comprisal's +comprizal, comprisal +computerizable, computerisable +computerization's, computerisation's +computerization, computerisation +computerizations, computerisations +computerize, computerise +computerized, computerised +computerizes, computerises +computerizing, computerising +concenter, concentre +concentered, concentred +concentering, concentring +concenters, concentres +conceptualization's, conceptualisation's +conceptualization, conceptualisation +conceptualizations, conceptualisations +conceptualize, conceptualise +conceptualized, conceptualised +conceptualizer, conceptualiser +conceptualizes, conceptualises +conceptualizing, conceptualising +concertist, concretist +concertize, concertise +concertized, concertised +concertizer's, concertiser's +concertizer, concertiser +concertizers, concertisers +concertizes, concertises +concertizing, concertising +conche, conchae +concolor, concolour +concolorous, concolourous +concretization's, concretisation's +concretization, concretisation +concretizations, concretisations +concretize, concretise +concretized, concretised +concretizes, concretises +concretizing, concretising +conditionalize, conditionalise +conditionalizes, conditionalises +coneys, conies +confederatize, confederatise +confederatizes, confederatises +congenialize, congenialise +congenializes, congenialises +conges, congoes +congregationalize, congregationalise +congregationalizes, congregationalises +conjurer's, conjuror's +conjurer, conjuror +conjurers, conjurors +connectable, connectible +connection's, connexion's +connection, connexion +connections, connexions +connector's, connecter's +connector, connecter +connectors, connecters +conservatize, conservatise +conservatized, conservatised +conservatizes, conservatises +conservatizing, conservatising +consonantize, consonantise +consonantized, consonantised +consonantizes, consonantises +consonantizing, consonantising +constitutionalization's, constitutionalisation's +constitutionalization, constitutionalisation +constitutionalizations, constitutionalisations +constitutionalize, constitutionalise +constitutionalized, constitutionalised +constitutionalizes, constitutionalises +constitutionalizing, constitutionalising +containerization's, containerisation's +containerization, containerisation +containerizations, containerisations +containerize, containerise +containerized, containerised +containerizes, containerises +containerizing, containerising +contemporization, contemporisation +contemporize, contemporise +contemporized, contemporised +contemporizes, contemporises +contemporizing, contemporising +contextualization, contextualisation +contextualizations, contextualisations +contextualize, contextualise +contextualized, contextualised +contextualizes, contextualises +contextualizing, contextualising +Continentalize, Continentalise +Continentalizes, Continentalises +controversialize, controversialise +controversializes, controversialises +conundrumize, conundrumise +conundrumizes, conundrumises +convener's, convenor's +convener, convenor +conveners, convenors +conventionalization's, conventionalisation's +conventionalization, conventionalisation +conventionalizations, conventionalisations +conventionalize, conventionalise +conventionalized, conventionalised +conventionalizes, conventionalises +conventionalizing, conventionalising +conventionize, conventionise +conventionizes, conventionises +conversationize, conversationise +conversationizes, conversationises +converter's, convertor's +converter's, convertor's +converter, convertor +converter, convertor +converters, convertors +converters, convertors +conveyor's, conveyer's +conveyor, conveyer +conveyorize, conveyorise +conveyorized, conveyorised +conveyorizes, conveyorises +conveyorizing, conveyorising +conveyors, conveyers +convivialize, convivialise +convivializes, convivialises +cony's, coney's +cony, coney +cookie's, cooky's +cookie, cooky +copolymerization's, copolymerisation's +copolymerization, copolymerisation +copolymerizations, copolymerisations +copolymerize, copolymerise +copolymerized, copolymerised +copolymerizes, copolymerises +copolymerizing, copolymerising +copperization's, copperisation's +copperization, copperisation +copperizations, copperisations +copperize, copperise +copperizes, copperises +copremia, copraemia +copremic, copraemic +coraled, coralled +coranto, couranto +corantoes, courantoes +corantos, courantos +corbe, courbe +corbed, courbed +corbeled, corbelled +corbeling's, corbelling's +corbeling, corbelling +corbelings, corbellings +cordialize, cordialise +cordialized, cordialised +cordializes, cordialises +cordializing, cordialising +corge, courge +Corinthianize's, Corinthianise's +Corinthianize, Corinthianise +corinthianize, corinthianise +corinthianized, corinthianised +Corinthianizes, Corinthianises +corinthianizes, corinthianises +corinthianizing, corinthianising +corporealization's, corporealisation's +corporealization, corporealisation +corporealizations, corporealisations +corporealize, corporealise +corporealized, corporealised +corporealizes, corporealises +corporealizing, corporealising +corsy, coursy +cortage, courtage +cortin, courtin +cortine, cortinae +corve, corvae +coryphe, coryphae +coryphes, coryphaes +cosmeticize, cosmeticise +cosmeticized, cosmeticised +cosmeticizes, cosmeticises +cosmeticizing, cosmeticising +cosmopolitanization's, cosmopolitanisation's +cosmopolitanization, cosmopolitanisation +cosmopolitanizations, cosmopolitanisations +cosmopolitanize, cosmopolitanise +cosmopolitanized, cosmopolitanised +cosmopolitanizes, cosmopolitanises +cosmopolitanizing, cosmopolitanising +cosplendor, cosplendour +coste, costae +costumier, costumire +cottar's, cotter's +cottar, cotter +cottars, cotters +cotte, cottae +cottonization's, cottonisation's +cottonization, cottonisation +cottonizations, cottonisations +cottonize, cottonise +cottonizes, cottonises +cotyle, cotylae +councilor's, councillor's +councilor, councillor +councilors, councillors +councilorship's, councillorship's +councilorship, councillorship +councilorships, councillorships +counseled, counselled +counselee, counsellee +counseling, counselling +counselor's, counsellor's +counselor, counsellor +counselors, counsellors +counselorship's, counsellorship's +counselorship, counsellorship +counselorships, counsellorships +countercolored, countercoloured +countor, countour +cozied, cosied +cozier, cosier +cozies, cosies +coziest, cosiest +cozily, cosily +coziness's, cosiness's +coziness, cosiness +cozy's, cosy's +cozy, cosy +cozying, cosying +craizey, craisey +crambes, cramboes +crawlerize, crawlerise +crawlerizes, crawlerises +creaturize, creaturise +creaturizes, creaturises +crenelate, crenellate +crenelated, crenellated +crenelater, crenellater +crenelates, crenellates +crenelatest, crenellatest +crenelating, crenellating +crenelation's, crenellation's +crenelation, crenellation +crenelations, crenellations +creneled, crenelled +creneling, crenelling +Creolization, Creolisation +creolization, creolisation +creolizations, creolisations +Creolize, Creolise +creolize, creolise +Creolized, Creolised +creolized, creolised +Creolizes, Creolises +creolizes, creolises +Creolizing, Creolising +creolizing, creolising +cretinization's, cretinisation's +cretinization, cretinisation +cretinizations, cretinisations +cretinize, cretinise +cretinized, cretinised +cretinizes, cretinises +cretinizing, cretinising +criminalization's, criminalisation's +criminalization, criminalisation +criminalizations, criminalisations +criminalize, criminalise +criminalized, criminalised +criminalizes, criminalises +criminalizing, criminalising +criticizable's, criticisable's +criticizable, criticisable +criticizabler, criticisabler +criticizables, criticisables +criticizablest, criticisablest +criticize, criticise +criticized, criticised +criticizer's, criticiser's +criticizer, criticiser +criticizers, criticisers +criticizes, criticises +criticizing, criticising +criticizinglier, criticisinglier +criticizinglies, criticisinglies +criticizingliest, criticisingliest +criticizingly, criticisingly +crofterization's, crofterisation's +crofterization, crofterisation +crofterizations, crofterisations +crofterize, crofterise +crofterizes, crofterises +crosier's, crozier's +crosier, crozier +crosiers, croziers +crueler, crueller +cruelest, cruellest +cruelize, cruelise +cruelizes, cruelises +cryesthesia, cryaesthesia +cryoanesthesia, cryoanaesthesia +cryptanalyzes, cryptanalyses +cryptesthesia, cryptaesthesia +cryptesthesias, cryptaesthesias +cryptesthetic, cryptaesthetic +crystalize, crystallise +crystalized, crystallised +crystalizes, crystallises +crystalizing, crystallising +crystallizabilities, crystallisabilities +crystallizability's, crystallisability's +crystallizability, crystallisability +crystallizable's, crystallisable's +crystallizable, crystallisable +crystallizabler, crystallisabler +crystallizables, crystallisables +crystallizablest, crystallisablest +crystallization's, crystallisation's +crystallization, crystallisation +crystallizations, crystallisations +crystallizer, crystalliser +crystallizers, crystallisers +Cubanize's, Cubanise's +Cubanize, Cubanise +Cubanizes, Cubanises +cuckoldize, cuckoldise +cuckoldized, cuckoldised +cuckoldizes, cuckoldises +cuckoldizing, cuckoldising +cudgeled, cudgelled +cudgeler's, cudgeller's +cudgeler, cudgeller +cudgelers, cudgellers +cudgeling, cudgelling +cudgelings, cudgellings +culicide, culicidae +culturization's, culturisation's +culturization, culturisation +culturizations, culturisations +culturize, culturise +culturizes, culturises +cupelation, cupellation +cupeled, cupelled +cupeler's, cupeller's +cupeler, cupeller +cupelers, cupellers +cupeling, cupelling +cupule, cupulae +curarize, curarise +curarized, curarised +curarizes, curarises +curarizing, curarising +curatize, curatise +curatizes, curatises +curricularization's, curricularisation's +curricularization, curricularisation +curricularizations, curricularisations +curricularize, curricularise +curricularizes, curricularises +curtsied, curtseyed +curtsies, curtseys +curtsy's, curtsey's +curtsy, curtsey +curtsying, curtseying +curvaceous, curvacious +customizable, customisable +customization's, customisation's +customization, customisation +customizations, customisations +customize, customise +customized, customised +customizer, customiser +customizers, customisers +customizes, customises +customizing, customising +cutesy, cutesie +cuticolor, cuticolour +cutinization's, cutinisation's +cutinization, cutinisation +cutinizations, cutinisations +cutinize, cutinise +cutinized, cutinised +cutinizes, cutinises +cutinizing, cutinising +cutization's, cutisation's +cutization, cutisation +cutizations, cutisations +cutlass's, cutlas's +cutlass, cutlas +cutlasses, cutlases +cuve, cuvae +Cyanee's, Cyaneae's +Cyanee, Cyaneae +cyanize, cyanise +cyanized, cyanised +cyanizes, cyanises +cyanizing, cyanising +cyanomethemoglobin, cyanomethaemoglobin +cyclization's, cyclisation's +cyclization, cyclisation +cyclizations, cyclisations +cyclize, cyclise +cyclized, cyclised +cyclizes, cyclises +cyclizing, cyclising +cyclopedia's, cyclopaedia's +cyclopedia, cyclopaedia +cyclopedias, cyclopaedias +cyclopedic, cyclopaedic +cyclopedically, cyclopaedically +cyclopedist's, cyclopaedist's +cyclopedist, cyclopaedist +cyme, cymae +Czechization's, Czechisation's +Czechization, Czechisation +Czechizations, Czechisations +d'oh's, doh's +d'oh, doh +d'ohs, dohs +danaide, danaidae +dandizette, dandisette +dandyize, dandyise +dandyizes, dandyises +dane, danae +Danization's, Danisation's +Danization, Danisation +Danizations, Danisations +Danize's, Danise's +Danize, Danise +Danizes, Danises +Darwinize's, Darwinise's +Darwinize, Darwinise +Darwinizes, Darwinises +dastardize, dastardise +dastardizes, dastardises +deaconize, deaconise +deaconizes, deaconises +deadrize, deadrise +dealcoholize, dealcoholise +dealcoholized, dealcoholised +dealcoholizes, dealcoholises +dealcoholizing, dealcoholising +deaminize, deaminise +deary's, dearie's +deary, dearie +decagram's, decagramme's +decagram, decagramme +decagrams, decagrammes +decaliter, decalitre +decaliter, decalitre's +decaliter, decalitres +decameter, decametre +decameter, decametre's +decameter, decametres +decapitalization, decapitalisation +decapitalizations, decapitalisations +decapitalize, decapitalise +decapitalized, decapitalised +decapitalizes, decapitalises +decapitalizing, decapitalising +decarbonization's, decarbonisation's +decarbonization, decarbonisation +decarbonizations, decarbonisations +decarbonize, decarbonise +decarbonized, decarbonised +decarbonizer's, decarboniser's +decarbonizer, decarboniser +decarbonizers, decarbonisers +decarbonizes, decarbonises +decarbonizing, decarbonising +decarburization's, decarburisation's +decarburization, decarburisation +decarburizations, decarburisations +decarburize, decarburise +decarburized, decarburised +decarburizes, decarburises +decarburizing, decarburising +decasualization's, decasualisation's +decasualization, decasualisation +decasualizations, decasualisations +decasualize, decasualise +decasualized, decasualised +decasualizing, decasualising +decenters, decentres +decentralization's, decentralisation's +decentralization, decentralisation +decentralizationist, decentralisationist +decentralizations, decentralisations +decentralize, decentralise +decentralized, decentralised +decentralizes, decentralises +decentralizing, decentralising +decerebrize, decerebrise +decerebrized, decerebrised +decerebrizes, decerebrises +decerebrizing, decerebrising +dechristianization, dechristianisation +dechristianizations, dechristianisations +dechristianize, dechristianise +dechristianized, dechristianised +dechristianizes, dechristianises +dechristianizing, dechristianising +decigram's, decigramme's +decigram, decigramme +decigrams, decigrammes +deciliter's, decilitre's +deciliter, decilitre +deciliters, decilitres +decimalization's, decimalisation's +decimalization, decimalisation +decimalizations, decimalisations +decimalize, decimalise +decimalized, decimalised +decimalizes, decimalises +decimalizing, decimalising +decimeter's, decimetre's +decimeter, decimetre +decimeters, decimetres +decivilize, decivilise +decivilized, decivilised +decivilizes, decivilises +decivilizing, decivilising +decolonization's, decolonisation's +decolonization, decolonisation +decolonizations, decolonisations +decolonize, decolonise +decolonized, decolonised +decolonizes, decolonises +decolonizing, decolonising +decolor, decolour +decolorant, decolourant +decolorants, decolourants +decolorate, decolourate +decolorated, decolourated +decolorates, decolourates +decoloration's, decolouration's +decoloration, decolouration +decolorations, decolourations +decolored, decoloured +decolorimeter, decolourimeter +decoloring, decolouring +decolors, decolours +decolourisation's, decolourization's +decolourisation, decolourization +decolourisations, decolourizations +decolourise, decolourize +decolourised, decolourized +decolouriser's, decolourizer's +decolouriser, decolourizer +decolourisers, decolourizers +decolourises, decolourizes +decolourising, decolourizing +decriminalization's, decriminalisation's +decriminalization, decriminalisation +decriminalizations, decriminalisations +decriminalize, decriminalise +decriminalized, decriminalised +decriminalizes, decriminalises +decriminalizing, decriminalising +dedal, daedal +dedalian, daedalian +dedramatize, dedramatise +dedramatized, dedramatised +dedramatizes, dedramatises +dedramatizing, dedramatising +deemphasization's, deemphasisation's +deemphasization, deemphasisation +deemphasize, deemphasise +deemphasized, deemphasised +deemphasizer, deemphasiser +deemphasizers, deemphasisers +deemphasizes, deemphasises +deemphasizing, deemphasising +deenergize, deenergise +deenergized, deenergised +deenergizer, deenergiser +deenergizes, deenergises +deenergizing, deenergising +defedation, defoedation +defeminization's, defeminisation's +defeminization, defeminisation +defeminize, defeminise +defeminized, defeminised +defeminizes, defeminises +defeminizing, defeminising +defense's, defence's +defense, defence +defensed, defenced +defenseless, defenceless +defenselesser, defencelesser +defenselessest, defencelessest +defenselesslier, defencelesslier +defenselessliest, defencelessliest +defenselessly, defencelessly +defenselessness's, defencelessness's +defenselessness, defencelessness +defenselessnesses, defencelessnesses +defenseman's, defenceman's +defenseman, defenceman +defensemen, defencemen +defenses, defences +defensing, defencing +defeudalize, defeudalise +defeudalized, defeudalised +defeudalizes, defeudalises +defeudalizing, defeudalising +defibrinize, defibrinise +defibrinized, defibrinised +defibrinizes, defibrinises +defibrinizing, defibrinising +definitization's, definitisation's +definitization, definitisation +definitizations, definitisations +definitize, definitise +definitized, definitised +definitizes, definitises +definitizing, definitising +deflectionization's, deflectionisation's +deflectionization, deflectionisation +deflectionizations, deflectionisations +deflectionize, deflectionise +deflectionizes, deflectionises +deformalize, deformalise +defunctionalization's, defunctionalisation's +defunctionalization, defunctionalisation +defunctionalizations, defunctionalisations +defunctionalize, defunctionalise +defunctionalizes, defunctionalises +deglycerolized, deglycerolised +dehumanization's, dehumanisation's +dehumanization, dehumanisation +dehumanizations, dehumanisations +dehumanize, dehumanise +dehumanized, dehumanised +dehumanizes, dehumanises +dehumanizing, dehumanising +dehydrogenization's, dehydrogenisation's +dehydrogenization, dehydrogenisation +dehydrogenize, dehydrogenise +dehydrogenized, dehydrogenised +dehydrogenizer's, dehydrogeniser's +dehydrogenizer, dehydrogeniser +dehydrogenizing, dehydrogenising +dehypnotization's, dehypnotisation's +dehypnotization, dehypnotisation +dehypnotizations, dehypnotisations +dehypnotize, dehypnotise +dehypnotized, dehypnotised +dehypnotizes, dehypnotises +dehypnotizing, dehypnotising +deindustrialization's, deindustrialisation's +deindustrialization, deindustrialisation +deindustrializations, deindustrialisations +deindustrialize, deindustrialise +deindustrialized, deindustrialised +deindustrializes, deindustrialises +deindustrializing, deindustrialising +deionization's, deionisation's +deionization, deionisation +deionize, deionise +deionized, deionised +deionizes, deionises +deionizing, deionising +delimitize, delimitise +delimitizes, delimitises +delocalization's, delocalisation's +delocalization, delocalisation +delocalizations, delocalisations +delocalize, delocalise +delocalized, delocalised +delocalizes, delocalises +delocalizing, delocalising +deluster, delustre +demagnetizable's, demagnetisable's +demagnetizable, demagnetisable +demagnetizabler, demagnetisabler +demagnetizables, demagnetisables +demagnetizablest, demagnetisablest +demagnetization's, demagnetisation's +demagnetization, demagnetisation +demagnetizations, demagnetisations +demagnetize, demagnetise +demagnetized, demagnetised +demagnetizer's, demagnetiser's +demagnetizer, demagnetiser +demagnetizers, demagnetisers +demagnetizes, demagnetises +demagnetizing, demagnetising +demagogue's, demagog's +demagogue, demagog +demagogued, demagoged +demagogueri, demagogri +demagogueris, demagogris +demagoguery, demagogry +demagogues, demagogs +demagoguing, demagoging +demasculinization's, demasculinisation's +demasculinization, demasculinisation +demasculinize, demasculinise +demasculinized, demasculinised +demasculinizing, demasculinising +dematerialization's, dematerialisation's +dematerialization, dematerialisation +dematerializations, dematerialisations +dematerialize, dematerialise +dematerialized, dematerialised +dematerializes, dematerialises +dematerializing, dematerialising +demeanor's, demeanour's +demeanor, demeanour +demeanors, demeanours +demilitarization's, demilitarisation's +demilitarization, demilitarisation +demilitarizations, demilitarisations +demilitarize, demilitarise +demilitarized, demilitarised +demilitarizes, demilitarises +demilitarizing, demilitarising +demiluster, demilustre +demineralization's, demineralisation's +demineralization, demineralisation +demineralizations, demineralisations +demineralize, demineralise +demineralized, demineralised +demineralizer, demineraliser +demineralizes, demineralises +demineralizing, demineralising +demobilization's, demobilisation's +demobilization, demobilisation +demobilizations, demobilisations +demobilize, demobilise +demobilized, demobilised +demobilizes, demobilises +demobilizing, demobilising +democratization's, democratisation's +democratization, democratisation +democratizations, democratisations +democratize, democratise +democratized, democratised +democratizer, democratiser +democratizes, democratises +democratizing, democratising +demonetization's, demonetisation's +demonetization, demonetisation +demonetizations, demonetisations +demonetize, demonetise +demonetized, demonetised +demonetizes, demonetises +demonetizing, demonetising +demonian, daemonian +demonization, demonisation +demonize, demonise +demonized, demonised +demonizes, demonises +demonizing, demonising +demoralization's, demoralisation's +demoralization, demoralisation +demoralizations, demoralisations +demoralize, demoralise +demoralized, demoralised +demoralizer's, demoraliser's +demoralizer, demoraliser +demoralizers, demoralisers +demoralizes, demoralises +demoralizing, demoralising +demoralizingly, demoralisingly +demutualization, demutualisation +demutualizations, demutualisations +demutualize, demutualise +demutualized, demutualised +demutualizes, demutualises +demutualizing, demutualising +demythologization's, demythologisation's +demythologization, demythologisation +demythologizations, demythologisations +demythologize, demythologise +demythologized, demythologised +demythologizer, demythologiser +demythologizes, demythologises +demythologizing, demythologising +denationalization's, denationalisation's +denationalization, denationalisation +denationalizations, denationalisations +denationalize, denationalise +denationalized, denationalised +denationalizes, denationalises +denationalizing, denationalising +denaturalization's, denaturalisation's +denaturalization, denaturalisation +denaturalizations, denaturalisations +denaturalize, denaturalise +denaturalized, denaturalised +denaturalizes, denaturalises +denaturalizing, denaturalising +denaturization's, denaturisation's +denaturization, denaturisation +denaturizations, denaturisations +denaturize, denaturise +denaturized, denaturised +denaturizer's, denaturiser's +denaturizer, denaturiser +denaturizers, denaturisers +denaturizes, denaturises +denaturizing, denaturising +denicotinize, denicotinise +denizenize, denizenise +denizenizes, denizenises +denominationalize, denominationalise +denominationalizes, denominationalises +denormalize, denormalise +dentalization's, dentalisation's +dentalization, dentalisation +dentalizations, dentalisations +dentalize, dentalise +dentalized, dentalised +dentalizes, dentalises +dentalizing, dentalising +dentin's, dentine's +dentin, dentine +dentins, dentines +denuclearization's, denuclearisation's +denuclearization, denuclearisation +denuclearizations, denuclearisations +denuclearize, denuclearise +denuclearized, denuclearised +denuclearizes, denuclearises +denuclearizing, denuclearising +deodorization's, deodorisation's +deodorization, deodorisation +deodorizations, deodorisations +deodorize, deodorise +deodorized, deodorised +deodorizer's, deodoriser's +deodorizer, deodoriser +deodorizers, deodorisers +deodorizes, deodorises +deodorizing, deodorising +deoxidization's, deoxidisation's +deoxidization, deoxidisation +deoxidizations, deoxidisations +deoxidize, deoxidise +deoxidized, deoxidised +deoxidizer's, deoxidiser's +deoxidizer, deoxidiser +deoxidizers, deoxidisers +deoxidizes, deoxidises +deoxidizing, deoxidising +deoxygenize, deoxygenise +deoxygenized, deoxygenised +deoxygenizes, deoxygenises +deoxygenizing, deoxygenising +departmentalization's, departmentalisation's +departmentalization, departmentalisation +departmentalizations, departmentalisations +departmentalize, departmentalise +departmentalized, departmentalised +departmentalizes, departmentalises +departmentalizing, departmentalising +departmentization's, departmentisation's +departmentization, departmentisation +departmentizations, departmentisations +departmentize, departmentise +departmentizes, departmentises +depauperization, depauperisation +depauperize, depauperise +depauperized, depauperised +depauperizes, depauperises +depauperizing, depauperising +dependence's, dependance's +dependence, dependance +dependences, dependances +depersonalization's, depersonalisation's +depersonalization, depersonalisation +depersonalizations, depersonalisations +depersonalize, depersonalise +depersonalized, depersonalised +depersonalizes, depersonalises +depersonalizing, depersonalising +depolarization's, depolarisation's +depolarization, depolarisation +depolarizations, depolarisations +depolarize, depolarise +depolarized, depolarised +depolarizer's, depolariser's +depolarizer, depolariser +depolarizers, depolarisers +depolarizes, depolarises +depolarizing, depolarising +depoliticization, depoliticisation +depoliticize, depoliticise +depoliticized, depoliticised +depoliticizes, depoliticises +depoliticizing, depoliticising +depolymerization's, depolymerisation's +depolymerization, depolymerisation +depolymerizations, depolymerisations +depolymerize, depolymerise +depolymerized, depolymerised +depolymerizes, depolymerises +depolymerizing, depolymerising +depressurization's, depressurisation's +depressurization, depressurisation +depressurizations, depressurisations +depressurize, depressurise +depressurized, depressurised +depressurizes, depressurises +depressurizing, depressurising +deputationize, deputationise +deputationizes, deputationises +deputization, deputisation +deputize, deputise +deputized, deputised +deputizes, deputises +deputizing, deputising +deracialize, deracialise +deracialized, deracialised +deracializes, deracialises +deracializing, deracialising +derationalization's, derationalisation's +derationalization, derationalisation +derationalizations, derationalisations +derationalize, derationalise +derationalizes, derationalises +deratization's, deratisation's +deratization, deratisation +deratizations, deratisations +derealization, derealisation +derecognize, derecognise +derecognized, derecognised +derecognizes, derecognises +derecognizing, derecognising +deregulationize, deregulationise +deregulationizes, deregulationises +dereligionize, dereligionise +dereligionized, dereligionised +dereligionizes, dereligionises +dereligionizing, dereligionising +derk, drek +dermatorrhea, dermatorrhoea +Derr's, Drer's +Derr, Drer +desacralization, desacralisation +desacralizations, desacralisations +desacralize, desacralise +desacralized, desacralised +desacralizes, desacralises +desacralizing, desacralising +desalinization's, desalinisation's +desalinization, desalinisation +desalinizations, desalinisations +desalinize, desalinise +desalinized, desalinised +desalinizes, desalinises +desalinizing, desalinising +desensitization's, desensitisation's +desensitization, desensitisation +desensitizations, desensitisations +desensitize, desensitise +desensitized, desensitised +desensitizer's, desensitiser's +desensitizer, desensitiser +desensitizers, desensitisers +desensitizes, desensitises +desensitizing, desensitising +desertization, desertisation +desertizations, desertisations +desexualization's, desexualisation's +desexualization, desexualisation +desexualizations, desexualisations +desexualize, desexualise +desexualized, desexualised +desexualizes, desexualises +desexualizing, desexualising +desilverization, desilverisation +desilverizations, desilverisations +desilverize, desilverise +desilverized, desilverised +desilverizes, desilverises +desilverizing, desilverising +despiritualization, despiritualisation +despiritualize, despiritualise +despotize, despotise +despotizes, despotises +destabilization, destabilisation +destabilize, destabilise +destabilized, destabilised +destabilizer, destabiliser +destabilizers, destabilisers +destabilizes, destabilises +destabilizing, destabilising +destalinize, destalinise +destalinized, destalinised +destalinizes, destalinises +destalinizing, destalinising +desterilize, desterilise +destigmatization, destigmatisation +desulfurizer's, desulfuriser's +desulfurizer, desulfuriser +desulphurisation's, desulphurization's +desulphurisation, desulphurization +desulphurisations, desulphurizations +desulphurise, desulphurize +desulphurised, desulphurized +desulphurises, desulphurizes +desulphurising, desulphurizing +desulphurizer, desulphuriser +desulphurizers, desulphurisers +desynchronization's, desynchronisation's +desynchronization, desynchronisation +desynchronizations, desynchronisations +desynchronize, desynchronise +desynchronized, desynchronised +desynchronizes, desynchronises +desynchronizing, desynchronising +detribalization's, detribalisation's +detribalization, detribalisation +detribalizations, detribalisations +detribalize, detribalise +detribalized, detribalised +detribalizes, detribalises +detribalizing, detribalising +deva, daeva +devalorization, devalorisation +devalorizations, devalorisations +devalorize, devalorise +devalorized, devalorised +devalorizes, devalorises +devalorizing, devalorising +develed, develled +develing, develling +deviled, devilled +deviling, devilling +devilize, devilise +devilizes, devilises +devitalization's, devitalisation's +devitalization, devitalisation +devitalizations, devitalisations +devitalize, devitalise +devitalized, devitalised +devitalizes, devitalises +devitalizing, devitalising +devocalization's, devocalisation's +devocalization, devocalisation +devocalize, devocalise +devocalized, devocalised +devocalizes, devocalises +devocalizing, devocalising +devolatilization's, devolatilisation's +devolatilization, devolatilisation +devolatilizations, devolatilisations +devolatilize, devolatilise +devolatilized, devolatilised +devolatilizes, devolatilises +devolatilizing, devolatilising +dexterous, dextrous +dexterously, dextrously +dexterousness, dextrousness +diabolization's, diabolisation's +diabolization, diabolisation +diabolizations, diabolisations +diabolize, diabolise +diabolized, diabolised +diabolizes, diabolises +diabolizing, diabolising +diagonalizable, diagonalisable +diagonalization, diagonalisation +diagonalize, diagonalise +diagonalized, diagonalised +diagonalizes, diagonalises +diagonalizing, diagonalising +dialecticize, dialecticise +dialecticizes, dialecticises +dialed, dialled +dialer's, dialler's +dialer, dialler +dialers, diallers +dialing's, dialling's +dialing, dialling +dialings, diallings +dialist's, diallist's +dialist, diallist +dialists, diallists +dialogize, dialogise +dialogized, dialogised +dialogizes, dialogises +dialogizing, dialogising +dialogue's, dialog's +dialogue, dialog +dialogued, dialogged +dialogues, dialogs +dialoguing, dialogging +dialyzabilities, dialysabilities +dialyzability's, dialysability's +dialyzability, dialysability +dialyzable's, dialysable's +dialyzable, dialysable +dialyzabler, dialysabler +dialyzables, dialysables +dialyzablest, dialysablest +dialyzate's, dialysate's +dialyzate, dialysate +dialyzates, dialysates +dialyzation's, dialysation's +dialyzation, dialysation +dialyze, dialyse +dialyzed, dialysed +dialyzer's, dialyser's +dialyzer, dialyser +dialyzers, dialysers +dialyzes, dialyses +dialyzing, dialysing +diamondize, diamondise +diamondizes, diamondises +diarize, diarise +diarized, diarised +diarizes, diarises +diarizing, diarising +diarrhea's, diarrhoea's +diarrhea, diarrhoea +diarrheal, diarrhoeal +diarrhealer, diarrhoealer +diarrhealest, diarrhoealest +diarrheas, diarrhoeas +diarrheic, diarrhoeic +diarrheicer, diarrhoeicer +diarrheicest, diarrhoeicest +diarrhetic, diarrhoetic +diarrheticer, diarrhoeticer +diarrheticest, diarrhoeticest +dichotomization's, dichotomisation's +dichotomization, dichotomisation +dichotomizations, dichotomisations +dichotomize, dichotomise +dichotomized, dichotomised +dichotomizes, dichotomises +dichotomizing, dichotomising +dickeys, dickies +dicky's, dickie's +dicky, dickie +diene, diaene +dieretic, diaeretic +dieselization's, dieselisation's +dieselization, dieselisation +dieselizations, dieselisations +dieselize, dieselise +dieselized, dieselised +dieselizes, dieselises +dieselizing, dieselising +diestrous, dioestrous +diestrual, dioestrual +diestrum, dioestrum +diestrus's, dioestrus's +diestrus, dioestrus +diestruses, dioestruses +diethylstilbestrol's, diethylstilboestrol's +diethylstilbestrol, diethylstilboestrol +dietitian's, dietician's +dietitian, dietician +dietitians, dieticians +differentialize, differentialise +differentializes, differentialises +digitalization's, digitalisation's +digitalization, digitalisation +digitalizations, digitalisations +digitalize, digitalise +digitalized, digitalised +digitalizes, digitalises +digitalizing, digitalising +digitization's, digitisation's +digitization, digitisation +digitizations, digitisations +digitize, digitise +digitized, digitised +digitizer's, digitiser's +digitizer, digitiser +digitizers, digitisers +digitizes, digitises +digitizing, digitising +dike's, dyke's +dike, dyke +diked, dyked +dikes, dykes +diking, dyking +dimensionalization, dimensionalisation +dimensionalize, dimensionalise +dimensionalized, dimensionalised +dimensionalizes, dimensionalises +dimensionalizing, dimensionalising +dimerization's, dimerisation's +dimerization, dimerisation +dimerizations, dimerisations +dimerize, dimerise +dimerized, dimerised +dimerizes, dimerises +dimerizing, dimerising +diminutivize, diminutivise +diminutivizes, diminutivises +dingoes, dingos +dioecious, diecious +dioeciously, dieciously +dionize, dionise +diopter's, dioptre's +diopter, dioptre +diopters, dioptres +diphthongization's, diphthongisation's +diphthongization, diphthongisation +diphthongizations, diphthongisations +diphthongize, diphthongise +diphthongized, diphthongised +diphthongizes, diphthongises +diphthongizing, diphthongising +diple, diploe +diploe's, diploae's +diploe, diploae +diplomatize, diplomatise +diplomatized, diplomatised +diplomatizes, diplomatises +diplomatizing, diplomatising +dis's, diss's +dis, diss +disangularize, disangularise +disangularizes, disangularises +disauthorize, disauthorise +disauthorized, disauthorised +disauthorizes, disauthorises +disauthorizing, disauthorising +disboweled, disbowelled +disboweling, disbowelling +discanonization's, discanonisation's +discanonization, discanonisation +discanonizations, discanonisations +discanonize, discanonise +discanonizes, discanonises +discolor's, discolour's +discolor, discolour +discolorate, discolourate +discolorated, discolourated +discoloration's, discolouration's +discoloration, discolouration +discolorations, discolourations +discolored's, discoloured's +discolored, discoloured +discoloredness, discolouredness +discoloreds, discoloureds +discoloring, discolouring +discolorment's, discolourment's +discolorment, discolourment +discolorments, discolourments +discolors, discolours +discolourisation's, discolourization's +discolourisation, discolourization +discolourisations, discolourizations +discretization, discretisation +discretize, discretise +disdenominationalize, disdenominationalise +disdenominationalizes, disdenominationalises +disdiplomatize, disdiplomatise +disdiplomatizes, disdiplomatises +disemboweled, disembowelled +disemboweling, disembowelling +disequalize's, disequalise's +disequalize, disequalise +disequalizer, disequaliser +disequalizers, disequalisers +disequalizes, disequalises +disfavor's, disfavour's +disfavor, disfavour +disfavored, disfavoured +disfavorer's, disfavourer's +disfavorer, disfavourer +disfavorers, disfavourers +disfavoring, disfavouring +disfavors, disfavours +dishabille's, deshabille's +dishabille, deshabille +dishabilles, deshabilles +disharmonize, disharmonise +disharmonized, disharmonised +disharmonizes, disharmonises +disharmonizing, disharmonising +disheveled, dishevelled +disheveler, disheveller +disheveling, dishevelling +dishonor's, dishonour's +dishonor, dishonour +dishonorable's, dishonourable's +dishonorable, dishonourable +dishonorableness's, dishonourableness's +dishonorableness, dishonourableness +dishonorablenesses, dishonourablenesses +dishonorabler, dishonourabler +dishonorables, dishonourables +dishonorablest, dishonourablest +dishonorablier, dishonourablier +dishonorablies, dishonourablies +dishonorabliest, dishonourabliest +dishonorably, dishonourably +dishonorary, dishonourary +dishonored, dishonoured +dishonorer's, dishonourer's +dishonorer, dishonourer +dishonorers, dishonourers +dishonoring, dishonouring +dishonors, dishonours +dishumanize, dishumanise +dishumanizes, dishumanises +dishumor, dishumour +dishumored, dishumoured +dishumors, dishumours +disillusionize, disillusionise +disillusionized, disillusionised +disillusionizer's, disillusioniser's +disillusionizer, disillusioniser +disillusionizers, disillusionisers +disillusionizes, disillusionises +disillusionizing, disillusionising +disindividualize, disindividualise +disindividualized, disindividualised +disindividualizes, disindividualises +disindividualizing, disindividualising +disindustrialization, disindustrialisation +disindustrializations, disindustrialisations +disindustrialize, disindustrialise +disindustrialized, disindustrialised +disindustrializes, disindustrialises +disindustrializing, disindustrialising +disluster, dislustre +dismalize, dismalise +dismalizes, dismalises +disnaturalization's, disnaturalisation's +disnaturalization, disnaturalisation +disnaturalizations, disnaturalisations +disnaturalize, disnaturalise +disnaturalized, disnaturalised +disnaturalizes, disnaturalises +disnaturalizing, disnaturalising +disorganization's, disorganisation's +disorganization, disorganisation +disorganizations, disorganisations +disorganize, disorganise +disorganized, disorganised +disorganizer's, disorganiser's +disorganizer, disorganiser +disorganizers, disorganisers +disorganizes, disorganises +disorganizing, disorganising +disozonize, disozonise +disozonizes, disozonises +dispapalize, dispapalise +dispapalizes, dispapalises +dispatch's, despatch's +dispatch, despatch +dispatched, despatched +dispatches, despatches +dispatching, despatching +dispauperize, dispauperise +dispauperized, dispauperised +dispauperizes, dispauperises +dispauperizing, dispauperising +dispersonalize, dispersonalise +dispersonalizes, dispersonalises +dispopularize, dispopularise +dispopularizes, dispopularises +disrealize, disrealise +disrealizes, disrealises +disscepter's, dissceptre's +disscepter, dissceptre +disscepters, dissceptres +disseize, disseise +disseized, disseised +disseizee, disseisee +disseizes, disseises +disseizin's, disseisin's +disseizin, disseisin +disseizing, disseising +disseizins, disseisins +disseizor's, disseisor's +disseizor, disseisor +disseizors, disseisors +dissensualize, dissensualise +dissensualizes, dissensualises +disses, dises +dissocialize, dissocialise +dissocialized, dissocialised +dissocializes, dissocialises +dissocializing, dissocialising +dissyllabize, dissyllabise +dissyllabized, dissyllabised +dissyllabizing, dissyllabising +dissympathize, dissympathise +dissympathizes, dissympathises +distill, distil +distills, distils +disutilize, disutilise +disutilizes, disutilises +ditsier, ditzier +ditsy, ditzy +ditziness's, ditsiness's +ditziness, ditsiness +ditzinesses, ditsinesses +diversicolored, diversicoloured +divinister, divinistre +divinization's, divinisation's +divinization, divinisation +divinizations, divinisations +divinize, divinise +divinized, divinised +divinizes, divinises +divinizing, divinising +divisionalization, divisionalisation +divisionalizations, divisionalisations +djellaba's, djellabah's +djellaba, djellabah +djellabas, djellabahes +djinni's, djinn's +djinni, djinn +Docete's, Docetae's +Docete, Docetae +dockization's, dockisation's +dockization, dockisation +dockizations, dockisations +dockize, dockise +dockized, dockised +dockizes, dockises +dockizing, dockising +doctorization's, doctorisation's +doctorization, doctorisation +doctorizations, doctorisations +doctorize, doctorise +doctorizes, doctorises +doctrinization's, doctrinisation's +doctrinization, doctrinisation +doctrinizations, doctrinisations +doctrinize, doctrinise +doctrinizes, doctrinises +documentarization, documentarisation +documentarizations, documentarisations +documentarize, documentarise +documentarized, documentarised +documentarizes, documentarises +documentarizing, documentarising +documentize, documentise +documentizes, documentises +Dodonean's, Dodonaean's +Dodonean, Dodonaean +doggy's, doggie's +doggy, doggie +dogie's, dogy's +dogie, dogy +dogmatization's, dogmatisation's +dogmatization, dogmatisation +dogmatizations, dogmatisations +dogmatize, dogmatise +dogmatized, dogmatised +dogmatizer's, dogmatiser's +dogmatizer, dogmatiser +dogmatizers, dogmatisers +dogmatizes, dogmatises +dogmatizing, dogmatising +dognaped, dognapped +dognaping, dognapping +dollarization, dollarisation +dollarizations, dollarisations +dolomitization's, dolomitisation's +dolomitization, dolomitisation +dolomitizations, dolomitisations +dolomitize, dolomitise +dolomitized, dolomitised +dolomitizes, dolomitises +dolomitizing, dolomitising +dolor's, dolour's +dolor, dolour +dolors, dolours +domesticize, domesticise +domesticized, domesticised +domesticizes, domesticises +domesticizing, domesticising +domine, dominae +dopey, dopy +dora, doura +Doricize's, Doricise's +Doricize, Doricise +Doricizes, Doricises +dorize, dorise +dorized, dorised +dorizes, dorises +dorizing, dorising +doryline, dorylinae +doughnut's, donut's +doughnut, donut +doughnuts, donuts +doweled, dowelled +doweler, doweller +doweling, dowelling +downdraft's, downdraught's +downdraft, downdraught +dracena, dracaena +dracenaceae, dracaenaceae +dracenas, dracaenas +draftier, draughtier +draftiest, draughtiest +draftilier, draughtilier +draftiliest, draughtiliest +draftily, draughtily +draftiness's, draughtiness's +draftiness, draughtiness +draftinesses, draughtinesses +draftsman's, draughtsman's +draftsman, draughtsman +draftsmanship's, draughtsmanship's +draftsmanship, draughtsmanship +draftsmanships, draughtsmanships +draftsmen, draughtsmen +draftsperson, draughtsperson +draftswoman's, draughtswoman's +draftswoman, draughtswoman +draftswomen, draughtswomen +drafty, draughty +dragonize, dragonise +dragonized, dragonised +dragonizes, dragonises +dragonizing, dragonising +dramatizable's, dramatisable's +dramatizable, dramatisable +dramatizabler, dramatisabler +dramatizables, dramatisables +dramatizablest, dramatisablest +dramatization's, dramatisation's +dramatization, dramatisation +dramatizations, dramatisations +dramatize, dramatise +dramatized, dramatised +dramatizer's, dramatiser's +dramatizer, dramatiser +dramatizers, dramatisers +dramatizes, dramatises +dramatizing, dramatising +dreamed, dreamt +driveled, drivelled +driveler's, driveller's +driveler, driveller +drivelers, drivellers +driveling, drivelling +drought's, drouth's +drought, drouth +droughtiness, drouthiness +droughts, drouthes +droughty, drouthy +dryly, drily +dualization's, dualisation's +dualization, dualisation +dualizations, dualisations +dualize, dualise +dualizes, dualises +ductilize, ductilise +ductilizes, ductilises +dueled, duelled +dueler's, dueller's +dueler, dueller +duelers, duellers +dueling, duelling +duelings, duellings +duelist's, duellist's +duelist, duellist +duelists, duellists +duer, dure +dullness's, dulness's +dullness, dulness +dullnesses, dulnesses +dumbfound, dumfound +dumbfounded, dumfounded +dumbfounding, dumfounding +dumbfoundingly, dumfoundingly +dumbfounds, dumfounds +dumpster's, Dumpster's +dumpster, Dumpster +dumpsters, Dumpsters +dynamize, dynamise +dynamized, dynamised +dynamizes, dynamises +dynamizing, dynamising +dysesthesia, dysaesthesia +dysesthetic, dysaesthetic +dysmenorrhea's, dysmenorrhoea's +dysmenorrhea, dysmenorrhoea +dysmenorrheal, dysmenorrhoeal +dysmenorrheas, dysmenorrhoeas +dysmenorrheic, dysmenorrhoeic +dyspnea's, dyspnoea's +dyspnea, dyspnoea +dyspneal, dyspnoeal +dyspneas, dyspnoeas +dyspneic, dyspnoeic +earlierize, earlierise +earlierized, earlierised +earlierizes, earlierises +earlierizing, earlierising +easternize, easternise +ebionize, ebionise +ebionized, ebionised +ebionizes, ebionises +ebionizing, ebionising +ebonization, ebonisation +ebonize, ebonise +ebonized, ebonised +ebonizes, ebonises +ebonizing, ebonising +ec, aec +ecclesiasticize, ecclesiasticise +ecclesiasticizes, ecclesiasticises +echoize, echoise +echoized, echoised +echoizes, echoises +echoizing, echoising +eclecticize, eclecticise +eclecticizes, eclecticises +ecoid, oecoid +economization's, economisation's +economization, economisation +economizations, economisations +economize, economise +economized, economised +economizer's, economiser's +economizer, economiser +economizers, economisers +economizes, economises +economizing, economising +ecophobia, oecophobia +ecstasize, ecstasise +ecstasized, ecstasised +ecstasizes, ecstasises +ecstasizing, ecstasising +ecstaticize, ecstaticise +ecstaticizes, ecstaticises +ectethmoid, ectoethmoid +ectocelic, ectocoelic +ecumenic, oecumenic +ecumenicalism, oecumenicalism +ecumenicity, oecumenicity +ecumenism, oecumenism +ecus, oecus +edema's, oedema's +edema, oedema +edemas, oedemas +edematose, oedematose +edematous, oedematous +Edenization's, Edenisation's +Edenization, Edenisation +Edenizations, Edenisations +Edenize's, Edenise's +Edenize, Edenise +Edenizes, Edenises +edicule's, aedicule's +edicule, aedicule +edility, aedility +editorialization's, editorialisation's +editorialization, editorialisation +editorializations, editorialisations +editorialize, editorialise +editorialized, editorialised +editorializer's, editorialiser's +editorializer, editorialiser +editorializes, editorialises +editorializing, editorialising +eerie, eery +Eetion's, Eaetion's +Eetion, Eaetion +effectualize, effectualise +effectualizes, effectualises +effeminatize, effeminatise +effeminatizes, effeminatises +effeminization's, effeminisation's +effeminization, effeminisation +effeminize, effeminise +effeminized, effeminised +effeminizes, effeminises +effeminizing, effeminising +eger, aeger +eger, egre +egilops, aegilops +eglogue, aeglogue +egoize, egoise +egoizer, egoiser +egoizers, egoisers +egoizes, egoises +egophony, aegophony +egotize, egotise +egotized, egotised +egotizes, egotises +egotizing, egotising +egritude, aegritude +Egyptianization's, Egyptianisation's +Egyptianization, Egyptianisation +Egyptianizations, Egyptianisations +Egyptianize's, Egyptianise's +Egyptianize, Egyptianise +Egyptianized's, Egyptianised's +Egyptianized, Egyptianised +Egyptianizes, Egyptianises +Egyptianizing's, Egyptianising's +Egyptianizing, Egyptianising +Egyptize's, Egyptise's +Egyptize, Egyptise +Egyptizes, Egyptises +elasticization, elasticisation +elasticize, elasticise +elasticized, elasticised +elasticizer, elasticiser +elasticizers, elasticisers +elasticizes, elasticises +elasticizing, elasticising +electricalize, electricalise +electricalizes, electricalises +electricize, electricise +electricizes, electricises +electrization, electrisation +electrizations, electrisations +electrize, electrise +electrized, electrised +electrizes, electrises +electrizing, electrising +electroanesthesia's, electroanaesthesia's +electroanesthesia, electroanaesthesia +electroanesthesias, electroanaesthesias +electrocauterization's, electrocauterisation's +electrocauterization, electrocauterisation +electrocauterizations, electrocauterisations +electrodialyze, electrodialyse +electrodialyzer's, electrodialyser's +electrodialyzer, electrodialyser +electrodialyzers, electrodialysers +electrodialyzes, electrodialyses +electrogalvanize, electrogalvanise +electrogalvanizes, electrogalvanises +electrohomeopathies, electrohomoeopathies +electrohomeopathy's, electrohomoeopathy's +electrohomeopathy, electrohomoeopathy +electrolyzation's, electrolysation's +electrolyzation, electrolysation +electrolyze, electrolyse +electrolyzed, electrolysed +electrolyzer's, electrolyser's +electrolyzer, electrolyser +electrolyzes, electrolyses +electrolyzing, electrolysing +electromagnetizable, electromagnetisable +electrotonize, electrotonise +electrotonizes, electrotonises +elegize, elegise +elegized, elegised +elegizes, elegises +elegizing, elegising +elementalize, elementalise +elementalizes, elementalises +eleoblast, elaeoblast +eleolite, elaeolite +eleomargaric, elaeomargaric +eleometer, elaeometer +eleoptene's, elaeoptene's +eleoptene, elaeoptene +Elizabethanize's, Elizabethanise's +Elizabethanize, Elizabethanise +Elizabethanizes, Elizabethanises +Elizabethville's, Elisabethville's +Elizabethville, Elisabethville +embedment, imbedment +embedments, imbedments +emblematicize, emblematicise +emblematicizes, emblematicises +emblematization, emblematisation +emblematize, emblematise +emblematized, emblematised +emblematizes, emblematises +emblematizing, emblematising +emblemize, emblemise +emblemized, emblemised +emblemizes, emblemises +emblemizing, emblemising +embolization, embolisation +emboweled, embowelled +emboweling, embowelling +emotionalization's, emotionalisation's +emotionalization, emotionalisation +emotionalizations, emotionalisations +emotionalize, emotionalise +emotionalized, emotionalised +emotionalizes, emotionalises +emotionalizing, emotionalising +emotionize, emotionise +emotionizes, emotionises +empathize, empathise +empathized, empathised +empathizes, empathises +empathizing, empathising +emperize, emperise +emperized, emperised +emperizes, emperises +emperizing, emperising +empestic, empaestic +emphasize, emphasise +emphasized, emphasised +emphasizer, emphasiser +emphasizers, emphasisers +emphasizes, emphasises +emphasizing, emphasising +employee's, employe's +employee, employe +employees, employes +emprise, emprize +emprises, emprizes +empyreumatize, empyreumatise +empyreumatized, empyreumatised +empyreumatizes, empyreumatises +empyreumatizing, empyreumatising +emule, aemule +emuled, aemuled +emules, aemules +emuling, aemuling +emulsionize, emulsionise +emulsionized, emulsionised +emulsionizes, emulsionises +emulsionizing, emulsionising +enameled, enamelled +enameler's, enameller's +enameler, enameller +enamelers, enamellers +enameling, enamelling +enamelings, enamellings +enamelist's, enamellist's +enamelist, enamellist +enamelists, enamellists +enamor's, enamour's +enamor, enamour +enamored's, enamoured's +enamored, enamoured +enamoredness's, enamouredness's +enamoredness, enamouredness +enamorednesses, enamourednesses +enamoreds, enamoureds +enamoring, enamouring +enamorment's, enamourment's +enamorment, enamourment +enamorments, enamourments +enamors, enamours +enarbor's, enarbour's +enarbor, enarbour +enarbors, enarbours +encarnalization, encarnalisation +encarnalize, encarnalise +encarnalized, encarnalised +encarnalizes, encarnalises +encarnalizing, encarnalising +encephalocele, encephalocoele +enclose, inclose +enclosed, inclosed +encloses, incloses +enclosing, inclosing +enclosure's, inclosure's +enclosure, inclosure +enclosures, inclosures +encolor's, encolour's +encolor, encolour +encolored, encoloured +encoloring, encolouring +encolors, encolours +encrust, incrust +encrusted, incrusted +encrusting, incrusting +encrusts, incrusts +encumber, incumber +encumbered, incumbered +encumbering, incumbering +encumbers, incumbers +encyclopedia's, encyclopaedia's +encyclopedia, encyclopaedia +encyclopediac, encyclopaediac +encyclopedial, encyclopaedial +encyclopedian, encyclopaedian +encyclopedias, encyclopaedias +encyclopedic, encyclopaedic +encyclopedical, encyclopaedical +encyclopedically, encyclopaedically +encyclopedism, encyclopaedism +encyclopedisms, encyclopaedisms +encyclopedist, encyclopaedist +encyclopedists, encyclopaedists +endameba, endamoeba +endamebae, endamoebae +endamebas, endamoebas +endamebiasis, endamoebiasis +endamebic, endamoebic +endeavor's, endeavour's +endeavor, endeavour +endeavored, endeavoured +endeavorer's, endeavourer's +endeavorer, endeavourer +endeavorers, endeavourers +endeavoring, endeavouring +endeavors, endeavours +Enders, Endres +endorse, indorse +endorsed, indorsed +endorsement's, indorsement's +endorsement, indorsement +endorsements, indorsements +endorses, indorses +endorsing, indorsing +endue, indue +endued, indued +endues, indues +enduing, induing +eneid, aeneid +energization, energisation +energize, energise +energized, energised +energizer's, energiser's +energizer, energiser +energizers, energisers +energizes, energises +energizing, energising +Englishize's, Englishise's +Englishize, Englishise +Englishizes, Englishises +engrandize, engrandise +engrandizement's, engrandisement's +engrandizement, engrandisement +engrandizements, engrandisements +engrandizes, engrandises +enharbor, enharbour +enhemospore, enhaemospore +enhypostatize, enhypostatise +enhypostatized, enhypostatised +enhypostatizes, enhypostatises +enhypostatizing, enhypostatising +enigmatize, enigmatise +enigmatized, enigmatised +enigmatizes, enigmatises +enigmatizing, enigmatising +enjambment's, enjambement's +enjambment, enjambement +enjambments, enjambements +enocyte, oenocyte +enolic, oenolic +enolization's, enolisation's +enolization, enolisation +enolizations, enolisations +enolize, enolise +enolizes, enolises +enological, oenological +enologist, oenologist +enologists, oenologists +enomania, oenomania +enroll, enrol +enrollment's, enrolment's +enrollment, enrolment +enrollments, enrolments +enrolls, enrols +ensepulcher's, ensepulchre's +ensepulcher, ensepulchre +ensepulcherred, ensepulchred +ensepulcherring, ensepulchring +ensepulchers, ensepulchres +ensorceled, ensorcelled +ensorcels, ensorcells +entameba, entamoeba +entamebae, entamoebae +entamebas, entamoebas +entamebic, entamoebic +entender, entendre +entenders, entendres +enterocele, enterocoele +enteroceles, enterocoeles +enthrall, enthral +enthrallment's, enthralment's +enthrallment, enthralment +enthrallments, enthralments +enthralls, enthrals +enthronization's, enthronisation's +enthronization, enthronisation +enthronizations, enthronisations +enthronize, enthronise +enthronized, enthronised +enthronizes, enthronises +enthronizing, enthronising +entocele, entocoele +entomologize, entomologise +entomologized, entomologised +entomologizes, entomologises +entomologizing, entomologising +entre, entrae +entrench, intrench +entrenched, intrenched +entrenches, intrenches +entrenching, intrenching +entrenchment's, intrenchment's +entrenchment, intrenchment +entrenchments, intrenchments +entrust, intrust +entrusted, intrusted +entrusting, intrusting +entrustment, intrustment +entrustments, intrustments +entrusts, intrusts +envapor's, envapour's +envapor, envapour +envapors, envapours +envenomization, envenomisation +eolic, aeolic +eolipile's, aeolipile's +eolipile, aeolipile +eolipiles, aeolipiles +eolotropic, aeolotropic +eon's, aeon's +eon, aeon +eonian, aeonian +eonism's, aeonism's +eonism, aeonism +eonisms, aeonisms +eons, aeons +Eopaleozoic's, Eopalaeozoic's +Eopaleozoic, Eopalaeozoic +epaulet's, epaulette's +epaulet, epaulette +epaulets, epaulettes +epenetic, epaenetic +ephete, ephetae +epicele, epicoele +epicenter's, epicentre's +epicenter, epicentre +epicenters, epicentres +Epicurize's, Epicurise's +Epicurize, Epicurise +epicurize, epicurise +epicurized, epicurised +Epicurizes, Epicurises +epicurizes, epicurises +epicurizing, epicurising +epidotization, epidotisation +epidotizations, epidotisations +epidotized, epidotised +epigeal, epigaeal +epigean, epigaean +epigeous, epigaeous +epigrammatization, epigrammatisation +epigrammatize, epigrammatise +epigrammatized, epigrammatised +epigrammatizer, epigrammatiser +epigrammatizes, epigrammatises +epigrammatizing, epigrammatising +epilogize, epilogise +epilogized, epilogised +epilogizes, epilogises +epilogizing, epilogising +epilogue's, epilog's +epilogue, epilog +epilogues, epilogs +epiloguize, epiloguise +epiloguized, epiloguised +epiloguizes, epiloguises +epiloguizing, epiloguising +epimerize, epimerise +epimerized, epimerised +epimerizing, epimerising +epinephrine's, epinephrin's +epinephrine, epinephrin +epinephrines, epinephrins +epiphanize, epiphanise +epiphanized, epiphanised +epiphanizing, epiphanising +Episcopalianize's, Episcopalianise's +Episcopalianize, Episcopalianise +Episcopalianizes, Episcopalianises +episcopize, episcopise +episcopized, episcopised +episcopizes, episcopises +episcopizing, episcopising +epistolize, epistolise +epistolized, epistolised +epistolizes, epistolises +epistolizing, epistolising +epitaphize, epitaphise +epitaphizes, epitaphises +epithetize, epithetise +epithetizes, epithetises +epitomization's, epitomisation's +epitomization, epitomisation +epitomizations, epitomisations +epitomize, epitomise +epitomized, epitomised +epitomizer's, epitomiser's +epitomizer, epitomiser +epitomizers, epitomisers +epitomizes, epitomises +epitomizing, epitomising +eq, aeq +equaled, equalled +equaling, equalling +equalization's, equalisation's +equalization, equalisation +equalizations, equalisations +equalize, equalise +equalized, equalised +equalizer's, equaliser's +equalizer, equaliser +equalizers, equalisers +equalizes, equalises +equalizing, equalising +equalizings, equalisings +equestrianize, equestrianise +equestrianizes, equestrianises +erbia, rebia +erbias, rebias +ergotize, ergotise +ergotized, ergotised +ergotizes, ergotises +ergotizing, ergotising +eric, aeric +erical, aerical +erke, reke +ern, ren +ernes, renes +ernest, renest +erns, rens +erogenesis, aerogenesis +erogenic, aerogenic +eros, aeros +erose, aerose +eroticization, eroticisation +eroticize, eroticise +eroticized, eroticised +eroticizes, eroticises +eroticizing, eroticising +erses, reses +ersh, resh +ert, ret +eruginous, aeruginous +erugo, aerugo +erugos, aerugos +ervalenta, revalenta +ervalentas, revalentas +erythrean, erythraean +erythremia, erythraemia +esc, aesc +escalades, escaladoes +eschynite, aeschynite +escollope's, escalop's +escollope, escalop +escollopes, escalops +esculapian, aesculapian +esculetin, aesculetin +esculin's, aesculin's +esculin, aesculin +Eskimoized's, Eskimoised's +Eskimoized, Eskimoised +Eskimoizeds, Eskimoiseds +esop, aesop +esophagal, oesophagal +esophagean, oesophagean +esophagism, oesophagism +esophagismus, oesophagismus +esophagitis, oesophagitis +esophagus, oesophagus +Essenize's, Essenise's +Essenize, Essenise +Essenizes, Essenises +essentialize, essentialise +essentializes, essentialises +esterization's, esterisation's +esterization, esterisation +esterizations, esterisations +esterize, esterise +esterizes, esterises +estheses, aestheses +esthesia's, aesthesia's +esthesia, aesthesia +esthesias, aesthesias +esthesiogen, aesthesiogen +esthesiogenic, aesthesiogenic +esthesiogens, aesthesiogens +esthesis, aesthesis +esthetical, aesthetical +esthetician's, aesthetician's +esthetician, aesthetician +estheticians, aestheticians +estival, aestival +estivate, aestivate +estivated, aestivated +estivates, aestivates +estivating, aestivating +estivation's, aestivation's +estivation, aestivation +estivations, aestivations +estivator's, aestivator's +estivator, aestivator +estive, aestive +estradiol's, oestradiol's +estradiol, oestradiol +estradiols, oestradiols +estral, oestral +estrin's, oestrin's +estrin, oestrin +estrins, oestrins +estriol's, oestriol's +estriol, oestriol +estriols, oestriols +estrogen's, oestrogen's +estrogen, oestrogen +estrogenic, oestrogenic +estrogens, oestrogens +estrone's, oestrone's +estrone, oestrone +estrones, oestrones +estrous, oestrous +estrual, oestrual +estruate, oestruate +estruation, oestruation +estrum, oestrum +estrums, oestrums +estrus's, oestrus's +estrus, oestrus +estruses, oestruses +estuate, aestuate +estuous, aestuous +esture, aesture +estus, aestus +et, aet +eternalization's, eternalisation's +eternalization, eternalisation +eternalizations, eternalisations +eternalize, eternalise +eternalized, eternalised +eternalizes, eternalises +eternalizing, eternalising +eternization's, eternisation's +eternization, eternisation +eternizations, eternisations +eternize, eternise +eternized, eternised +eternizes, eternises +eternizing, eternising +etheling, aetheling +etherealization's, etherealisation's +etherealization, etherealisation +etherealizations, etherealisations +etherealize, etherealise +etherealized, etherealised +etherealizes, etherealises +etherealizing, etherealising +ethered, aethered +etherialization's, etherialisation's +etherialization, etherialisation +etherialize, etherialise +etherialized, etherialised +etherializing, etherialising +etheric, aetheric +etherization's, etherisation's +etherization, etherisation +etherizations, etherisations +etherize, etherise +etherized, etherised +etherizer's, etheriser's +etherizer, etheriser +etherizers, etherisers +etherizes, etherises +etherizing, etherising +ethicization, ethicisation +ethicize, ethicise +ethicized, ethicised +ethicizes, ethicises +ethicizing, ethicising +ethnicize, ethnicise +ethnicizes, ethnicises +etiogenic, aetiogenic +etiologically, aetiologically +etiologist's, aetiologist's +etiologist, aetiologist +etiologue, aetiologue +etiology's, aetiology's +etiology, aetiology +etiophyllin, aetiophyllin +etiotropic, aetiotropic +etiotropically, aetiotropically +etymologizable, etymologisable +etymologization, etymologisation +etymologize, etymologise +etymologized, etymologised +etymologizes, etymologises +etymologizing, etymologising +eudemon, eudaemon +eudemonia, eudaemonia +eudemonic, eudaemonic +eudemonics, eudaemonics +eudemonism, eudaemonism +eudemonisms, eudaemonisms +eudemonist's, eudaemonist's +eudemonist, eudaemonist +eudemonistic, eudaemonistic +eudemonistical, eudaemonistical +eudemonistically, eudaemonistically +eudemonists, eudaemonists +eudemons, eudaemons +eudemony, eudaemony +euhemerize, euhemerise +euhemerized, euhemerised +euhemerizes, euhemerises +euhemerizing, euhemerising +eukaryote's, eucaryote's +eukaryote, eucaryote +eukaryotes, eucaryotes +eukaryotic, eucaryotic +eulogization's, eulogisation's +eulogization, eulogisation +eulogizations, eulogisations +eulogize, eulogise +eulogized, eulogised +eulogizer's, eulogiser's +eulogizer, eulogiser +eulogizers, eulogisers +eulogizes, eulogises +eulogizing, eulogising +eunuchize, eunuchise +eunuchized, eunuchised +eunuchizes, eunuchises +eunuchizing, eunuchising +euphemization's, euphemisation's +euphemization, euphemisation +euphemize, euphemise +euphemized, euphemised +euphemizer's, euphemiser's +euphemizer, euphemiser +euphemizers, euphemisers +euphemizes, euphemises +euphemizing, euphemising +euphonization, euphonisation +euphonize, euphonise +euphonized, euphonised +euphonizes, euphonises +euphonizing, euphonising +euphuize, euphuise +euphuized, euphuised +euphuizes, euphuises +euphuizing, euphuising +eupnea's, eupnoea's +eupnea, eupnoea +eupneas, eupnoeas +eupneic, eupnoeic +Europeanization's, Europeanisation's +Europeanization, Europeanisation +Europeanizations, Europeanisations +Europeanize, Europeanise +europeanize, europeanise +Europeanized, Europeanised +europeanized, europeanised +Europeanizes, Europeanises +europeanizes, europeanises +Europeanizing, Europeanising +europeanizing, europeanising +Euryale's, Euryalae's +Euryale, Euryalae +evangelization's, evangelisation's +evangelization, evangelisation +evangelizations, evangelisations +evangelize, evangelise +evangelized, evangelised +evangelizer's, evangeliser's +evangelizer, evangeliser +evangelizers, evangelisers +evangelizes, evangelises +evangelizing, evangelising +eventualize, eventualise +eventualized, eventualised +eventualizes, eventualises +eventualizing, eventualising +eviler, eviller +evilest, evillest +eviternal, aeviternal +evolutionize, evolutionise +evolutionizes, evolutionises +excursionize, excursionise +excursionized, excursionised +excursionizes, excursionises +excursionizing, excursionising +exestuate, exaestuate +exhibitionize, exhibitionise +exhibitionizes, exhibitionises +existentialize, existentialise +existentializes, existentialises +exorcise, exorcize +exorcised, exorcized +exorcises, exorcizes +exorcising, exorcizing +exorcization, exorcisation +exorcizement, exorcisement +exorcizer's, exorciser's +exorcizer, exorciser +exorcizers, exorcisers +expediter's, expeditor's +expediter, expeditor +expediters, expeditors +experimentalize, experimentalise +experimentalized, experimentalised +experimentalizes, experimentalises +experimentalizing, experimentalising +experimentize, experimentise +experimentizes, experimentises +expertized, expertised +expertizing, expertising +exsiccate, exsiccatae +extemporization's, extemporisation's +extemporization, extemporisation +extemporizations, extemporisations +extemporize, extemporise +extemporized, extemporised +extemporizer's, extemporiser's +extemporizer, extemporiser +extemporizers, extemporisers +extemporizes, extemporises +extemporizing, extemporising +extendable, extendible +exteriorization's, exteriorisation's +exteriorization, exteriorisation +exteriorizations, exteriorisations +exteriorize, exteriorise +exteriorized, exteriorised +exteriorizes, exteriorises +exteriorizing, exteriorising +externalization's, externalisation's +externalization, externalisation +externalizations, externalisations +externalize, externalise +externalized, externalised +externalizes, externalises +externalizing, externalising +extol, extoll +extols, extolls +extrovert's, extravert's +extrovert, extravert +extroverted, extraverted +extroverts, extraverts +eyeing, eying +fabulize, fabulise +fabulized, fabulised +fabulizes, fabulises +fabulizing, fabulising +facsimilize, facsimilise +facsimilizes, facsimilises +factorization's, factorisation's +factorization, factorisation +factorizations, factorisations +factorize, factorise +factorized, factorised +factorizes, factorises +factorizing, factorising +faence's, faoence's +faence, faoence +faerie's, faery's +faerie, faery +faitor, faitour +faitors, faitours +falafel's, felafel's +falafel, felafel +familiarization's, familiarisation's +familiarization, familiarisation +familiarizations, familiarisations +familiarize, familiarise +familiarized, familiarised +familiarizer's, familiariser's +familiarizer, familiariser +familiarizers, familiarisers +familiarizes, familiarises +familiarizing, familiarising +familiarizingly, familiarisingly +fanaticize, fanaticise +fanaticized, fanaticised +fanaticizes, fanaticises +fanaticizing, fanaticising +fantasied, phantasied +fantasies, phantasies +fantasize, fantasise +fantasized, fantasised +fantasizer, fantasiser +fantasizes, fantasises +fantasizing, fantasising +fantasy's, phantasy's +fantasy, phantasy +fantasying, phantasying +faradization's, faradisation's +faradization, faradisation +faradizations, faradisations +faradize, faradise +faradized, faradised +faradizer's, faradiser's +faradizer, faradiser +faradizers, faradisers +faradizes, faradises +faradizing, faradising +fasciole, fasciolae +fascisticization's, fascisticisation's +fascisticization, fascisticisation +fascisticizations, fascisticisations +fascisticize, fascisticise +fascisticizes, fascisticises +fascistization's, fascistisation's +fascistization, fascistisation +fascistizations, fascistisations +fascistize, fascistise +fascistized, fascistised +fascistizes, fascistises +fascistizing, fascistising +fashionize, fashionise +fashionizes, fashionises +fatalize, fatalise +fatalizes, fatalises +favor's, favour's +favor, favour +favorable's, favourable's +favorable, favourable +favorableness's, favourableness's +favorableness, favourableness +favorablenesses, favourablenesses +favorabler, favourabler +favorables, favourables +favorablest, favourablest +favorablier, favourablier +favorabliest, favourabliest +favorably, favourably +favored's, favoured's +favored, favoured +favoredlier, favouredlier +favoredliest, favouredliest +favoredly, favouredly +favoredness's, favouredness's +favoredness, favouredness +favorednesses, favourednesses +favoreds, favoureds +favorer's, favourer's +favorer, favourer +favorers, favourers +favoress, favouress +favoring's, favouring's +favoring, favouring +favoringlier, favouringlier +favoringliest, favouringliest +favoringly, favouringly +favorings, favourings +favorite's, favourite's +favorite, favourite +favoriter, favouriter +favorites, favourites +favoritest, favouritest +favoritism's, favouritism's +favoritism, favouritism +favoritisms, favouritisms +favorless, favourless +favorlesser, favourlesser +favorlesses, favourlesses +favorlessest, favourlessest +favors, favours +fayer, fayre +fe, fae +fecal, faecal +fecalith, faecalith +feces's, faeces's +feces, faeces +fecula, faecula +feculence, faeculence +Fecunditatis's, Foecunditatis's +Fecunditatis, Foecunditatis +fecundize, fecundise +fecundizes, fecundises +fedarie, foedarie +fedaries, foedaries +federalization's, federalisation's +federalization, federalisation +federalizations, federalisations +federalize, federalise +federalized, federalised +federalizes, federalises +federalizing, federalising +Fedor's, Faedor's +Fedor, Faedor +feer, fere +feers, feres +femalize, femalise +femalizes, femalises +feminization's, feminisation's +feminization, feminisation +feminizations, feminisations +feminize, feminise +feminized, feminised +feminizes, feminises +feminizing, feminising +femtometer, femtometre +femtometers, femtometres +feralized, feralised +ferd, fred +ferie, feriae +ferity, freity +Ferneau's, Freneau's +Ferneau, Freneau +ferreled, ferrelled +ferreling, ferrelling +ferritization's, ferritisation's +ferritization, ferritisation +ferritizations, ferritisations +fertilizability's, fertilisability's +fertilizability, fertilisability +fertilizable's, fertilisable's +fertilizable, fertilisable +fertilizabler, fertilisabler +fertilizables, fertilisables +fertilizablest, fertilisablest +fertilization's, fertilisation's +fertilization, fertilisation +fertilizational's, fertilisational's +fertilizational, fertilisational +fertilizationaler, fertilisationaler +fertilizationalest, fertilisationalest +fertilizationals, fertilisationals +fertilizations, fertilisations +fertilize, fertilise +fertilized, fertilised +fertilizer's, fertiliser's +fertilizer, fertiliser +fertilizers, fertilisers +fertilizes, fertilises +fertilizing, fertilising +fervor's, fervour's +fervor, fervour +fervorless, fervourless +fervorlesses, fervourlesses +fervors, fervours +fetal, foetal +fetalism, foetalism +fetation's, foetation's +fetation, foetation +fetichize, fetichise +fetichized, fetichised +fetichizes, fetichises +fetichizing, fetichising +feticidal, foeticidal +feticide's, foeticide's +feticide, foeticide +feticides, foeticides +fetid, foetid +fetiferous, foetiferous +fetiparous, foetiparous +fetish's, fetich's +fetish, fetich +fetishes, fetiches +fetishization's, fetishisation's +fetishization, fetishisation +fetishizations, fetishisations +fetishize, fetishise +fetishized, fetishised +fetishizes, fetishises +fetishizing, fetishising +fetor's, foetor's +fetor, foetor +fetors, foetors +fetoscopies, foetoscopies +fetoscopy, foetoscopy +feture, foeture +fetus's, foetus's +fetus, foetus +fetuses, foetuses +feudalizable's, feudalisable's +feudalizable, feudalisable +feudalizables, feudalisables +feudalization's, feudalisation's +feudalization, feudalisation +feudalizations, feudalisations +feudalize, feudalise +feudalized, feudalised +feudalizes, feudalises +feudalizing, feudalising +feuter, feutre +fiber's, fibre's +fiber, fibre +fiberboard's, fibreboard's +fiberboard, fibreboard +fiberboards, fibreboards +fibered, fibred +fiberfill's, fibrefill's +fiberfill, fibrefill +fiberfills, fibrefills +fiberglass's, fibreglass's +fiberglass, fibreglass +fiberglasses, fibreglasses +fiberless, fibreless +fiberlesser, fibrelesser +fiberlesses, fibrelesses +fiberlessest, fibrelessest +fibers, fibres +fiberscope, fibrescope +fiberscopes, fibrescopes +fiberware, fibreware +fibrisation, fibrization +fibrise, fibrize +fibrised, fibrized +fibriser, fibrizer +fibrisers, fibrizers +fibrises, fibrizes +fibrising, fibrizing +fictionalization's, fictionalisation's +fictionalization, fictionalisation +fictionalizations, fictionalisations +fictionalize, fictionalise +fictionalized, fictionalised +fictionalizes, fictionalises +fictionalizing, fictionalising +fictionization's, fictionisation's +fictionization, fictionisation +fictionizations, fictionisations +fictionize, fictionise +fictionized, fictionised +fictionizes, fictionises +fictionizing, fictionising +figurize, figurise +figurizes, figurises +filmize, filmise +filmizes, filmises +filterable, filtrable +finalization's, finalisation's +finalization, finalisation +finalizations, finalisations +finalize, finalise +finalized, finalised +finalizes, finalises +finalizing, finalising +Finlandization, Finlandisation +Finlandizations, Finlandisations +fiscalization's, fiscalisation's +fiscalization, fiscalisation +fiscalizations, fiscalisations +fiscalize, fiscalise +fiscalizes, fiscalises +fjord's, fiord's +fjord, fiord +fjords, fiords +flamboyantize, flamboyantise +flamboyantizes, flamboyantises +flanneled, flannelled +flannelette's, flannelet's +flannelette, flannelet +flanneling, flannelling +flavor's, flavour's +flavor, flavour +flavored, flavoured +flavorer's, flavourer's +flavorer, flavourer +flavorers, flavourers +flavorful, flavourful +flavorfuler, flavourfuler +flavorfulest, flavourfulest +flavorfullier, flavourfullier +flavorfulliest, flavourfulliest +flavorfully, flavourfully +flavorier, flavourier +flavoriest, flavouriest +flavoring's, flavouring's +flavoring, flavouring +flavorings, flavourings +flavorless, flavourless +flavorlesser, flavourlesser +flavorlesses, flavourlesses +flavorlessest, flavourlessest +flavorous, flavourous +flavors, flavours +flavorsome, flavoursome +flavorsomer, flavoursomer +flavorsomest, flavoursomest +flavory, flavoury +fledgling's, fledgeling's +fledgling, fledgeling +fledglings, fledgelings +Fletcherize's, Fletcherise's +Fletcherize, Fletcherise +Fletcherized's, Fletcherised's +Fletcherized, Fletcherised +Fletcherizes, Fletcherises +Fletcherizing's, Fletcherising's +Fletcherizing, Fletcherising +flextime's, flexitime's +flextime, flexitime +flextimes, flexitimes +floozy's, floozie's +floozy, floozie +floralize, floralise +floralizes, floralises +floramor, floramour +flotation's, floatation's +flotation, floatation +flotations, floatations +fluidization's, fluidisation's +fluidization, fluidisation +fluidizations, fluidisations +fluidize, fluidise +fluidized, fluidised +fluidizer's, fluidiser's +fluidizer, fluidiser +fluidizers, fluidisers +fluidizes, fluidises +fluidizing, fluidising +fluky, flukey +flunkey's, flunkie's +flunkie, flunkey +flunkies, flunkeys +fluoridization's, fluoridisation's +fluoridization, fluoridisation +fluoridizations, fluoridisations +fluoridize, fluoridise +fluoridized, fluoridised +fluoridizes, fluoridises +fluoridizing, fluoridising +flutist's, flautist's +flutist, flautist +flutists, flautists +fo'c'sle's, fo'c's'le's +fo'c'sle, fo'c's'le +fo'c'sles, fo'c's'les +focalization's, focalisation's +focalization, focalisation +focalizations, focalisations +focalize, focalise +focalized, focalised +focalizes, focalises +focalizing, focalising +focused, focussed +focusing, focussing +fogies, fogeys +fogy's, fogey's +fogy, fogey +fondue's, fondu's +fondue, fondu +fondues, fondus +fontanel's, fontanelle's +fontanel, fontanelle +fontanels, fontanelles +foolhardize, foolhardise +foolhardized, foolhardised +foolhardizes, foolhardises +foolhardizing, foolhardising +forb, fourb +forche, fourche +foreignization's, foreignisation's +foreignization, foreignisation +foreignizations, foreignisations +foreignize, foreignise +foreignizes, foreignises +forejudgment's, forejudgement's +forejudgment, forejudgement +forejudgments, forejudgements +foreprize, foreprise +forgather, foregather +forgathered, foregathered +forgathering, foregathering +forgathers, foregathers +forgo, forego +forgoes, foregoes +forgoing, foregoing +forgone, foregone +formalizable, formalisable +formalization's, formalisation's +formalization, formalisation +formalizations, formalisations +formalize, formalise +formalized, formalised +formalizer's, formaliser's +formalizer, formaliser +formalizers, formalisers +formalizes, formalises +formalizing, formalising +forme, formae +formicide, formicidae +formularization's, formularisation's +formularization, formularisation +formularizations, formularisations +formularize, formularise +formularized, formularised +formularizer's, formulariser's +formularizer, formulariser +formularizers, formularisers +formularizes, formularises +formularizing's, formularising's +formularizing, formularising +formulization's, formulisation's +formulization, formulisation +formulizations, formulisations +formulize, formulise +formulized, formulised +formulizer's, formuliser's +formulizer, formuliser +formulizes, formulises +formulizing, formulising +forswear, foreswear +forswearing, foreswearing +forswears, foreswears +forswore, foreswore +forsworn, foresworn +forsworn, foresworn +forumize, forumise +forumizes, forumises +forwent, forewent +fosse, fossae +fossiled, fossilled +fossilizable's, fossilisable's +fossilizable, fossilisable +fossilizabler, fossilisabler +fossilizables, fossilisables +fossilizablest, fossilisablest +fossilization's, fossilisation's +fossilization, fossilisation +fossilizations, fossilisations +fossilize, fossilise +fossilized, fossilised +fossilizes, fossilises +fossilizing, fossilising +fossule, fossulae +foulder, fouldre +fouter, foutre +fouters, foutres +foveole, foveolae +fractionalization's, fractionalisation's +fractionalization, fractionalisation +fractionalizations, fractionalisations +fractionalize, fractionalise +fractionalized, fractionalised +fractionalizes, fractionalises +fractionalizing, fractionalising +fractionization's, fractionisation's +fractionization, fractionisation +fractionizations, fractionisations +fractionize, fractionise +fractionized, fractionised +fractionizes, fractionises +fractionizing, fractionising +fragmentization's, fragmentisation's +fragmentization, fragmentisation +fragmentize, fragmentise +fragmentized, fragmentised +fragmentizer, fragmentiser +fragmentizes, fragmentises +fragmentizing, fragmentising +frambesia's, framboesia's +frambesia, framboesia +frambesias, framboesias +Francize's, Francise's +Francize, Francise +Francizes, Francises +Franklinization's, Franklinisation's +Franklinization, Franklinisation +Franklinizations, Franklinisations +fraternization's, fraternisation's +fraternization, fraternisation +fraternizations, fraternisations +fraternize, fraternise +fraternized, fraternised +fraternizer's, fraterniser's +fraternizer, fraterniser +fraternizers, fraternisers +fraternizes, fraternises +fraternizing, fraternising +freebie's, freebee's +freebie, freebee +freebies, freebees +frena, fraena +Frenchize's, Frenchise's +Frenchize, Frenchise +Frenchizes, Frenchises +frenetic, phrenetic +frenula, fraenula +frenular, fraenular +frenulum's, fraenulum's +frenulum, fraenulum +frenum's, fraenum's +frenum, fraenum +frenums, fraenums +friborg, fribourg +frictionize, frictionise +frictionizes, frictionises +frivoled, frivolled +frivoler's, frivoller's +frivoler, frivoller +frivolers, frivollers +frivoling, frivolling +frizado, frisado +frize, frise +frizette's, frisette's +frizette, frisette +frizettes, frisettes +frizz's, friz's +frizz, friz +frowzier, frowsier +frowziest, frowsiest +frowzy, frowsy +fryer's, frier's +fryer, frier +fryers, friers +fuehrer's, f¸hrer's +fuehrer, f¸hrer +fuehrers, f¸hrers +fueled, fuelled +fueler's, fueller's +fueler, fueller +fuelers, fuellers +fueling, fuelling +fuelizer's, fueliser's +fuelizer, fueliser +fuelizers, fuelisers +fulfill, fulfil +fulfillment's, fulfilment's +fulfillment, fulfilment +fulfillments, fulfilments +fulfills, fulfils +fulgor, fulgour +fulgorous, fulgourous +fulgors, fulgours +fullness's, fulness's +fullness, fulness +fullnesses, fulnesses +functionalize, functionalise +functionalizes, functionalises +functionize, functionise +functionizes, functionises +funeralize, funeralise +funeralizes, funeralises +funneled, funnelled +funneler, funneller +funneling, funnelling +furcule, furculae +Furie's, Furiae's +Furie, Furiae +furor's, furore's +furor, furore +furors, furores +fusilier's, fusileer's +fusilier, fusileer +fusiliers, fusileers +fustianize, fustianise +fustianized, fustianised +fustianizes, fustianises +fustianizing, fustianising +futilize, futilise +futilizes, futilises +futurize, futurise +futurizes, futurises +gaberdine's, gabardine's +gaberdine, gabardine +gaberdines, gabardines +Gaelicization's, Gaelicisation's +Gaelicization, Gaelicisation +Gaelicizations, Gaelicisations +Gaelicize's, Gaelicise's +Gaelicize, Gaelicise +gaelicize, gaelicise +gaelicized, gaelicised +Gaelicizes, Gaelicises +gaelicizes, gaelicises +gaelicizing, gaelicising +gaiety's, gayety's +gaiety, gayety +gaily, gayly +galactorrhea, galactorrhoea +galactorrheas, galactorrhoeas +galactosemia, galactosaemia +galactosemias, galactosaemias +galee, galeae +gallantize, gallantise +gallantizes, gallantises +galliardize, galliardise +Gallicization's, Gallicisation's +Gallicization, Gallicisation +Gallicizations, Gallicisations +Gallicize, Gallicise +gallicize, gallicise +Gallicized, Gallicised +gallicized, gallicised +Gallicizer's, Galliciser's +Gallicizer, Galliciser +Gallicizes, Gallicises +gallicizes, gallicises +Gallicizing, Gallicising +gallicizing, gallicising +gallisize, gallisise +gallisized, gallisised +gallisizes, gallisises +gallisizing, gallisising +gallize, gallise +gallized, gallised +gallizes, gallises +gallizing, gallising +galosh's, galoshe's +galosh, galoshe +galvanization's, galvanisation's +galvanization, galvanisation +galvanizations, galvanisations +galvanize, galvanise +galvanized, galvanised +galvanizer's, galvaniser's +galvanizer, galvaniser +galvanizers, galvanisers +galvanizes, galvanises +galvanizing, galvanising +gambades, gambadoes +gamboled, gambolled +gamboling, gambolling +gamy, gamey +gargarize, gargarise +gargarized, gargarised +gargarizes, gargarises +gargarizing, gargarising +garotting, garoting +garrotte's, garote's +garrotte, garote +garrotted, garoted +garrottes, garotes +garruline, garrulinae +gases, gasses +gasoline's, gasolene's +gasoline, gasolene +gasolines, gasolenes +gastrea, gastraea +gastreas, gastraeas +gastrocele, gastrocoele +gaufer, gaufre +gaufers, gaufres +gauffer, gauffre +gauge's, gage's +gauge, gage +gauged, gaged +gauges, gages +gauging, gaging +gaveled, gavelled +gaveler, gaveller +gaveling, gavelling +ge, gae +ge, goe +ged, gaed +gelatin's, gelatine's +gelatin, gelatine +gelatinizabilities, gelatinisabilities +gelatinizability's, gelatinisability's +gelatinizability, gelatinisability +gelatinizable's, gelatinisable's +gelatinizable, gelatinisable +gelatinizables, gelatinisables +gelatinization's, gelatinisation's +gelatinization, gelatinisation +gelatinizations, gelatinisations +gelatinize, gelatinise +gelatinized, gelatinised +gelatinizer's, gelatiniser's +gelatinizer, gelatiniser +gelatinizers, gelatinisers +gelatinizes, gelatinises +gelatinizing, gelatinising +gelatins, gelatines +gelofer, gelofre +gemologies, gemmologies +gemology's, gemmology's +gemology, gemmology +genealogize, genealogise +genealogized, genealogised +genealogizes, genealogises +genealogizing, genealogising +generalizability, generalisability +generalizable's, generalisable's +generalizable, generalisable +generalizabler, generalisabler +generalizables, generalisables +generalizablest, generalisablest +generalization's, generalisation's +generalization, generalisation +generalizational, generalisational +generalizations, generalisations +generalize, generalise +generalized, generalised +generalizer's, generaliser's +generalizer, generaliser +generalizers, generalisers +generalizes, generalises +generalizing, generalising +genialize, genialise +genialized, genialised +genializes, genialises +genializing, genialising +genteelize, genteelise +genteelized, genteelised +genteelizes, genteelises +genteelizing, genteelising +gentilization's, gentilisation's +gentilization, gentilisation +gentilizations, gentilisations +gentilize, gentilise +gentilized, gentilised +gentilizes, gentilises +gentilizing, gentilising +gentlemanize, gentlemanise +gentlemanizes, gentlemanises +geodesia, geodaesia +geologize, geologise +geologized, geologised +geologizes, geologises +geologizing, geologising +geometricize, geometricise +geometricizes, geometricises +geometrization, geometrisation +geometrizations, geometrisations +geometrize, geometrise +geometrized, geometrised +geometrizes, geometrises +geometrizing, geometrising +ger, gre +gerenuk, greenuk +Germanization's, Germanisation's +germanization's, germanisation's +Germanization, Germanisation +germanization, germanisation +germanizations, germanisations +Germanize, Germanise +germanize, germanise +Germanized, Germanised +germanized, germanised +Germanizer's, Germaniser's +Germanizer, Germaniser +germanizer, germaniser +germanizers, germanisers +Germanizes, Germanises +germanizes, germanises +Germanizing, Germanising +germanizing, germanising +gerne, grene +gers, gres +Ges, Goes +gessed, gessoed +gesses, gessoes +geste, gestae +Getae's, Goetae's +Getae, Goetae +Getz's, Goetz's +Getz, Goetz +Getzville's, Goetzville's +Getzville, Goetzville +gewgaw's, geegaw's +gewgaw, geegaw +gewgaws, geegaws +gey, goey +Gheber's, Ghebre's +Gheber, Ghebre +Ghebers, Ghebres +ghettoization's, ghettoisation's +ghettoization, ghettoisation +ghettoizations, ghettoisations +ghettoize, ghettoise +ghettoized, ghettoised +ghettoizes, ghettoises +ghettoizing, ghettoising +giantize, giantise +giantizes, giantises +gigagram, gigagramme +gigagrams, gigagrammes +gigameter, gigametre +gigameters, gigametres +gimbaled, gimballed +gimbaling, gimballing +gingkos, gingkoes +ginkgo's, gingko's +ginkgo, gingko +girly, girlie +gizmo's, gismo's +gizmo, gismo +gizmos, gismos +glacialize, glacialise +glacializes, glacialises +glamorization's, glamorisation's +glamorizations, glamorisations +glamorless, glamourless +glamorous, glamourous +glamorousness's, glamourousness's +glamorousness, glamourousness +glamour's, glamor's +glamour, glamor +glamoured, glamored +glamouring, glamoring +glamourization, glamorisation +glamourize, glamorise +glamourized, glamorised +glamourizer's, glamoriser's +glamourizer, glamoriser +glamourizers, glamorisers +glamourizes, glamorises +glamourizing, glamorising +glamours, glamors +glauconitization, glauconitisation +glauconitizations, glauconitisations +glebe, glebae +globalization's, globalisation's +globalization, globalisation +globalizations, globalisations +globalize, globalise +globalized, globalised +globalizes, globalises +globalizing, globalising +globigerine, globigerinae +glottalization's, glottalisation's +glottalization, glottalisation +glottalize, glottalise +glottalizes, glottalises +glucemia, glucaemia +glucosemia, glucosaemia +gluing, glueing +gluteal, glutaeal +glutei, glutaei +gluteus, glutaeus +gluttonize, gluttonise +gluttonized, gluttonised +gluttonizes, gluttonises +gluttonizing, gluttonising +glycemia, glycaemia +glycemic, glycaemic +glycerin's, glycerine's +glycerin, glycerine +glycerinize, glycerinise +glycerinizes, glycerinises +glycerins, glycerines +glycerolize, glycerolise +glycerolized, glycerolised +glycerolizes, glycerolises +glycogenize, glycogenise +glycogenizes, glycogenises +glycohemia, glycohaemia +glycosemia, glycosaemia +Gnosticize, Gnosticise +gnosticize, gnosticise +Gnosticized's, Gnosticised's +Gnosticized, Gnosticised +Gnosticizer's, Gnosticiser's +Gnosticizer, Gnosticiser +gnosticizer, gnosticiser +gnosticizers, gnosticisers +Gnosticizes, Gnosticises +gnosticizes, gnosticises +Gnosticizing's, Gnosticising's +Gnosticizing, Gnosticising +gobbledygook's, gobbledegook's +gobbledygook, gobbledegook +gobbledygooks, gobbledegooks +goddamn's, goddam's +goddamn, goddam +goddamned, goddamed +goddamning, goddaming +goddamns, goddams +goddize, goddise +goddizes, goddises +goiter's, goitre's +goiter, goitre +goiters, goitres +gole, goloe +goliathize, goliathise +goliathized, goliathised +goliathizes, goliathises +goliathizing, goliathising +goloshes, goloshoes +gonorrhea's, gonorrhoea's +gonorrhea, gonorrhoea +gonorrheal, gonorrhoeal +gonorrhealer, gonorrhoealer +gonorrhealest, gonorrhoealest +gonorrheas, gonorrhoeas +gonorrheic, gonorrhoeic +goodbye's, goodby's +goodbye, goodby +goodbyes, goodbys +goody's, goodie's +goody, goodie +gor, gour +Gora's, Goura's +Gora, Goura +gora, goura +goramies, gouramies +gorgonize, gorgonise +gorgonized, gorgonised +gorgonizes, gorgonises +gorgonizing, gorgonising +gormandism's, gourmandism's +gormandism, gourmandism +gormandisms, gourmandisms +gormandize's, gormandise's +gormandize, gormandise +gormandized, gormandised +gormandizer's, gormandiser's +gormandizer, gormandiser +gormandizers, gormandisers +gormandizes, gormandises +gormandizing, gormandising +gormandizings, gormandisings +gospeler's, gospeller's +gospeler, gospeller +gospelers, gospellers +gospelize, gospelise +gospelized, gospelised +gospelizes, gospelises +gospelizing, gospelising +gospellize, gospellise +gospellized, gospellised +gospellizes, gospellises +gospellizing, gospellising +Gothicize, Gothicise +gothicize, gothicise +Gothicized, Gothicised +gothicized, gothicised +Gothicizer's, Gothiciser's +Gothicizer, Gothiciser +Gothicizers, Gothicisers +Gothicizes, Gothicises +gothicizes, gothicises +Gothicizing, Gothicising +gothicizing, gothicising +gourmandize, gourmandise +gourmandized, gourmandised +gourmandizes, gourmandises +gourmandizing, gourmandising +governmentalize, governmentalise +governmentalized, governmentalised +governmentalizes, governmentalises +governmentalizing, governmentalising +Goyesque, Goyaesque +Graecize, Graecise +Graecized, Graecised +Graecizes, Graecises +grammaticize, grammaticise +grammaticized, grammaticised +grammaticizes, grammaticises +grammaticizing, grammaticising +granddad's, grandad's +granddad, grandad +granddads, grandads +grangerization's, grangerisation's +grangerization, grangerisation +grangerizations, grangerisations +grangerize, grangerise +grangerized, grangerised +grangerizer's, grangeriser's +grangerizer, grangeriser +grangerizers, grangerisers +grangerizes, grangerises +grangerizing, grangerising +granitization's, granitisation's +granitization, granitisation +granitizations, granitisations +granitize, granitise +granitized, granitised +granitizes, granitises +granitizing, granitising +granny's, grannie's +granny, grannie +granulitization, granulitisation +granulitizations, granulitisations +granulize, granulise +granulizes, granulises +graphitizable, graphitisable +graphitization's, graphitisation's +graphitization, graphitisation +graphitizations, graphitisations +graphitize, graphitise +graphitized, graphitised +graphitizes, graphitises +graphitizing, graphitising +graveled, gravelled +graveling, gravelling +gray's, grey's +gray, grey +grayed, greyed +grayer, greyer +grayest, greyest +graying, greying +grayish, greyish +grayness's, greyness's +grayness, greyness +grays, greys +grecian, graecian +Grecianize, Grecianise +Grecianizes, Grecianises +Grecise's, Graecise's +Grecise, Graecise +Grecised's, Graecised's +Grecised, Graecised +Grecising's, Graecising's +Grecising, Graecising +Grecism's, Graecism's +Grecism, Graecism +grecism, graecism +Grecisms, Graecisms +Grecize, Grecise +grecize, grecise +Grecized, Grecised +grecized, grecised +grecizes, grecises +Grecizing, Grecising +grecizing, grecising +Greekize's, Greekise's +Greekize, Greekise +Greekizes, Greekises +greisenization, greisenisation +greisenizations, greisenisations +greisenize, greisenise +greisenized, greisenised +greisenizes, greisenises +greisenizing, greisenising +grizard, grisard +grize, grise +grizes, grises +groveled, grovelled +groveler's, groveller's +groveler, groveller +grovelers, grovellers +groveling, grovelling +grovelinglier, grovellinglier +grovelingliest, grovellingliest +grovelingly, grovellingly +grueled, gruelled +grueler's, grueller's +grueler, grueller +gruelers, gruellers +grueling's, gruelling's +grueling, gruelling +gruelingly, gruellingly +gruelings, gruellings +Gueber's, Guebre's +Gueber, Guebre +Guebers, Guebres +guerrilla's, guerilla's +guerrilla, guerilla +guerrillas, guerillas +guizer, guiser +guizers, guisers +gule, gulae +gunwale's, gunnel's +gunwale, gunnel +gunwales, gunnels +gutte, guttae +guttule, guttulae +gutturalization's, gutturalisation's +gutturalization, gutturalisation +gutturalizations, gutturalisations +gutturalize, gutturalise +gutturalized, gutturalised +gutturalizes, gutturalises +gutturalizing, gutturalising +gyne, gynae +gynecic, gynaecic +gynecocracies, gynaecocracies +gynecocracy's, gynaecocracy's +gynecocracy, gynaecocracy +gynecocrat's, gynaecocrat's +gynecocrat, gynaecocrat +gynecocratic, gynaecocratic +gynecocraticer, gynaecocraticer +gynecocraticest, gynaecocraticest +gynecocrats, gynaecocrats +gynecoid, gynaecoid +gynecol, gynaecol +gynecologic, gynaecologic +gynecological's, gynaecological's +gynecological, gynaecological +gynecologicaler, gynaecologicaler +gynecologicalest, gynaecologicalest +gynecologicals, gynaecologicals +gynecologicer, gynaecologicer +gynecologicest, gynaecologicest +gynecologics, gynaecologics +gynecologies, gynaecologies +gynecologist's, gynaecologist's +gynecologist, gynaecologist +gynecologists, gynaecologists +gynecology's, gynaecology's +gynecology, gynaecology +gynecomastia's, gynaecomastia's +gynecomastia, gynaecomastia +gynecomastias, gynaecomastias +gynecomasty's, gynaecomasty's +gynecomasty, gynaecomasty +gynecomorphous, gynaecomorphous +gyneconitis, gynaeconitis +gyneocracy, gynaeocracy +gyneolater, gynaeolater +gyneolatry, gynaeolatry +gynomonecious, gynomonoecious +gypsies, gipsies +gypsy's, gipsy's +gypsy, gipsy +gyrostabilization, gyrostabilisation +gyrostabilizations, gyrostabilisations +gyrostabilizer's, gyrostabiliser's +gyrostabilizer, gyrostabiliser +gyrostabilizers, gyrostabilisers +ha, hah +habitualize, habitualise +habitualizes, habitualises +hairdryer's, hairdrier's +hairdryer, hairdrier +hairdryers, hairdriers +hajj's, hadj's +hajj, hadj +hajji's, hadji's +hajji, hadji +hajjis, hadjis +hajjs, hadjs +hallo's, hollo's +hallo, hollo +halloing, holloing +hamletization's, hamletisation's +hamletization, hamletisation +hamletizations, hamletisations +hamletize, hamletise +hamletizes, hamletises +handseled, handselled +handseling, handselling +hankie's, hanky's +hankie, hanky +Hanoverianize's, Hanoverianise's +Hanoverianize, Hanoverianise +Hanoverianizes, Hanoverianises +Hanoverize's, Hanoverise's +Hanoverize, Hanoverise +Hanoverizes, Hanoverises +hansardize, hansardise +hansardized, hansardised +hansardizes, hansardises +hansardizing, hansardising +hanseled, hanselled +hanseling, hanselling +harbor's, harbour's +harbor, harbour +harborage's, harbourage's +harborage, harbourage +harborages, harbourages +harbored, harboured +harborer's, harbourer's +harborer, harbourer +harborers, harbourers +harborful, harbourful +harboring, harbouring +harborless, harbourless +harborlesser, harbourlesser +harborlesses, harbourlesses +harborlessest, harbourlessest +harborous, harbourous +harbors, harbours +harborside, harbourside +harborward, harbourward +harmonizable's, harmonisable's +harmonizable, harmonisable +harmonizabler, harmonisabler +harmonizables, harmonisables +harmonizablest, harmonisablest +harmonization's, harmonisation's +harmonization, harmonisation +harmonizations, harmonisations +harmonize, harmonise +harmonized, harmonised +harmonizer's, harmoniser's +harmonizer, harmoniser +harmonizers, harmonisers +harmonizes, harmonises +harmonizing, harmonising +Harmothoe's, Harmothoae's +Harmothoe, Harmothoae +Harvardize's, Harvardise's +Harvardize, Harvardise +Harvardizes, Harvardises +Harveyize's, Harveyise's +Harveyize, Harveyise +Harveyizes, Harveyises +hasheesh's, haschisch's +hasheesh, haschisch +Hasidean's, Hasidaean's +Hasidean, Hasidaean +Hasmonean, Hasmonaean +Hasmoneans, Hasmonaeans +hatcheled, hatchelled +hatcheling, hatchelling +Hattize's, Hattise's +Hattize, Hattise +Hattizes, Hattises +haussmannization, haussmannisation +haussmannizations, haussmannisations +haussmannize, haussmannise +haussmannized, haussmannised +haussmannizes, haussmannises +haussmannizing, haussmannising +havior, haviour +haviored, havioured +haviors, haviours +hazardize, hazardise +hazardizes, hazardises +heathenization, heathenisation +heathenize, heathenise +heathenized, heathenised +heathenizes, heathenises +heathenizing, heathenising +heavenize, heavenise +heavenizes, heavenises +Hebraicize's, Hebraicise's +Hebraicize, Hebraicise +Hebraicizes, Hebraicises +Hebraization's, Hebraisation's +Hebraization, Hebraisation +hebraization, hebraisation +hebraizations, hebraisations +Hebraize, Hebraise +hebraize, hebraise +Hebraized, Hebraised +hebraized, hebraised +Hebraizer's, Hebraiser's +Hebraizer, Hebraiser +Hebraizes, Hebraises +hebraizes, hebraises +Hebraizing, Hebraising +hebraizing, hebraising +Hecatean's, Hecataean's +Hecatean, Hecataean +hectogram's, hectogramme's +hectogram, hectogramme +hectograms, hectogrammes +hectoliter's, hectolitre's +hectoliter, hectolitre +hectoliters, hectolitres +hectometer's, hectometre's +hectometer, hectometre +hectometers, hectometres +hed, haed +Hegelianize's, Hegelianise's +Hegelianize, Hegelianise +Hegelianizes, Hegelianises +Hekatean's, Hekataean's +Hekatean, Hekataean +hele, heloe +helled, helloed +Hellenization's, Hellenisation's +Hellenization, Hellenisation +Hellenizations, Hellenisations +Hellenize, Hellenise +hellenize, hellenise +Hellenized, Hellenised +hellenized, hellenised +Hellenizer's, Helleniser's +Hellenizer, Helleniser +Hellenizes, Hellenises +hellenizes, hellenises +Hellenizing, Hellenising +hellenizing, hellenising +hemachrome's, haemachrome's +hemachrome, haemachrome +hemacytometer's, haemacytometer's +hemacytometer, haemacytometer +hemad, haemad +hemagglutinate, haemagglutinate +hemagglutinated, haemagglutinated +hemagglutinating, haemagglutinating +hemagglutination's, haemagglutination's +hemagglutination, haemagglutination +hemagglutinative, haemagglutinative +hemagglutinin, haemagglutinin +hemagogue, haemagogue +hemal, haemal +hemameba, hemamoeba +hemangioma's, haemangioma's +hemangioma, haemangioma +hemangiomas, haemangiomas +hemangiomata, haemangiomata +hemangiomatosis, haemangiomatosis +hemapophysis, haemapophysis +hemaspectroscope, haemaspectroscope +hematal, haematal +hematein's, haematein's +hematein, haematein +hematemesis, haematemesis +hematherm, haematherm +hemathermal, haemathermal +hemathermous, haemathermous +hematic, haematic +hematics, haematics +hematid, haematid +hematin's, haematin's +hematin, haematin +hematinic's, haematinic's +hematinic, haematinic +hematinics, haematinics +hematins, haematins +hematite's, haematite's +hematite, haematite +hematites, haematites +hematitic, haematitic +hematoblast's, haematoblast's +hematoblast, haematoblast +hematoblasts, haematoblasts +hematobranchiate, haematobranchiate +hematocele's, haematocele's +hematocele, haematocele +hematocrit's, haematocrit's +hematocrit, haematocrit +hematocrits, haematocrits +hematocryal, haematocryal +hematocyst's, haematocyst's +hematocyst, haematocyst +hematocystis, haematocystis +hematocyte's, haematocyte's +hematocyte, haematocyte +hematogeneses, haematogeneses +hematogenesis's, haematogenesis's +hematogenesis, haematogenesis +hematogenous, haematogenous +hematoid, haematoid +hematoidin, haematoidin +hematologic, haematologic +hematological, haematological +hematologies, haematologies +hematologist's, haematologist's +hematologist, haematologist +hematologists, haematologists +hematology's, haematology's +hematology, haematology +hematolysis, haematolysis +hematoma's, haematoma's +hematoma, haematoma +hematomas, haematomas +hematomata, haematomata +hematometer, haematometer +hematophyte's, haematophyte's +hematophyte, haematophyte +hematopoieses, haematopoieses +hematopoiesis, haematopoiesis +hematopoietic, haematopoietic +hematorrhachis, haematorrhachis +hematosepsis, haematosepsis +hematosin, haematosin +hematosis's, haematosis's +hematosis, haematosis +hematothermal, haematothermal +hematoxylic, haematoxylic +hematoxylin's, haematoxylin's +hematoxylin, haematoxylin +hematoxylins, haematoxylins +hematozoa, haematozoa +hematozoal, haematozoal +hematozoic, haematozoic +hematozoon's, haematozoon's +hematozoon, haematozoon +hematozzoa, haematozzoa +hematuria's, haematuria's +hematuria, haematuria +hematurias, haematurias +heme, haem +hemerythrin, hemoerythrin +hemic, haemic +hemihypesthesia, hemihypoesthesia +hemin's, haemin's +hemin, haemin +hemins, haemins +hemoblast's, haemoblast's +hemoblast, haemoblast +hemochromatoses, haemochromatoses +hemochromatosis, haemochromatosis +hemochrome, haemochrome +hemocoel, haemocoel +hemocoels, haemocoels +hemoconcentration's, haemoconcentration's +hemoconcentration, haemoconcentration +hemoconia, haemoconia +hemocyanin, haemocyanin +hemocyanins, haemocyanins +hemocyte's, haemocyte's +hemocyte, haemocyte +hemocytes, haemocytes +hemocytoblast's, haemocytoblast's +hemocytoblast, haemocytoblast +hemocytoblastic, haemocytoblastic +hemocytometer, haemocytometer +hemodialyses, haemodialyses +hemodialysis's, haemodialysis's +hemodialysis, haemodialysis +hemodilution, haemodilution +hemodynamic, haemodynamic +hemodynamics's, haemodynamics's +hemodynamics, haemodynamics +hemoflagellate's, haemoflagellate's +hemoflagellate, haemoflagellate +hemoglobic, haemoglobic +hemoglobin's, haemoglobin's +hemoglobin, haemoglobin +hemoglobinopathies, haemoglobinopathies +hemoglobinopathy, haemoglobinopathy +hemoglobinous, haemoglobinous +hemoglobinuria's, haemoglobinuria's +hemoglobinuria, haemoglobinuria +hemogram, haemogram +hemoid, haemoid +hemolysin's, haemolysin's +hemolysin, haemolysin +hemolysis, haemolysis +hemolytic, haemolytic +hemometer, haemometer +Hemon's, Haemon's +Hemon, Haemon +hemophile's, haemophile's +hemophile, haemophile +hemophilia's, haemophilia's +hemophilia, haemophilia +hemophiliac's, haemophiliac's +hemophiliac, haemophiliac +hemophiliacs, haemophiliacs +hemophilic, haemophilic +hemopod, haemopod +hemopoiesis, haemopoiesis +hemoptyses, haemoptyses +hemoptysis's, haemoptysis's +hemoptysis, haemoptysis +hemorrhage's, haemorrhage's +hemorrhage, haemorrhage +hemorrhaged, haemorrhaged +hemorrhages, haemorrhages +hemorrhaging, haemorrhaging +hemorrhoid, haemorrhoid +hemorrhoidal, haemorrhoidal +hemorrhoidectomy's, haemorrhoidectomy's +hemorrhoidectomy, haemorrhoidectomy +hemorrhoids, haemorrhoids +hemosporid, haemosporid +hemosporidian, haemosporidian +hemostases, haemostases +hemostasia, haemostasia +hemostasis's, haemostasis's +hemostasis, haemostasis +hemostatic, haemostatic +hemothorax's, haemothorax's +hemothorax, haemothorax +hemotoxic, haemotoxic +hemotoxin's, haemotoxin's +hemotoxin, haemotoxin +heparinize, heparinise +hepatization's, hepatisation's +hepatization, hepatisation +hepatizations, hepatisations +hepatize, hepatise +hepatized, hepatised +hepatizes, hepatises +hepatizing, hepatising +hepatorrhea, hepatorrhoea +heraldize, heraldise +heraldizes, heraldises +herborization, herborisation +herborizations, herborisations +herborize, herborise +herborized, herborised +herborizes, herborises +herborizing, herborising +heredes, haeredes +hereticize, hereticise +hereticizes, hereticises +heroinize, heroinise +heroinizes, heroinises +heroization's, heroisation's +heroization, heroisation +heroizations, heroisations +heroize, heroise +heroized, heroised +heroizes, heroises +heroizing, heroising +het, haet +heterecious, heteroecious +heteric, hetaeric +heterism, hetaerism +hets, haets +hexachlorethane, hexachloroethane +hexachlorethanes, hexachloroethanes +hexametrize, hexametrise +hexametrized, hexametrised +hexametrizes, hexametrises +hexametrizing, hexametrising +hexestrol, hexoestrol +Hibernicize's, Hibernicise's +Hibernicize, Hibernicise +hibernicize, hibernicise +Hibernicized's, Hibernicised's +Hibernicized, Hibernicised +hibernicized, hibernicised +hibernicizes, hibernicises +Hibernicizing's, Hibernicising's +Hibernicizing, Hibernicising +hibernicizing, hibernicising +hibernization, hibernisation +hibernizations, hibernisations +hibernize, hibernise +hibernized, hibernised +hibernizes, hibernises +hibernizing, hibernising +hiccuped, hiccupped +hiccuping, hiccupping +hierarchize, hierarchise +hierarchized, hierarchised +hierarchizing, hierarchising +hifalutin, highfaluting +high_jinks, hijinks +hijack's, highjack's +hijack, highjack +hijacked, highjacked +hijacker's, highjacker's +hijacker, highjacker +hijackers, highjackers +hijacking, highjacking +hijacks, highjacks +hilloed, hilloaed +Hinduize's, Hinduise's +Hinduize, Hinduise +Hinduized's, Hinduised's +Hinduized, Hinduised +Hinduizes, Hinduises +Hinduizing's, Hinduising's +Hinduizing, Hinduising +hippieness's, hippiness's +hippieness, hippiness +hippienesses, hippinesses +hirseled, hirselled +hirseling, hirselling +Hispanicization's, Hispanicisation's +Hispanicization, Hispanicisation +Hispanicizations, Hispanicisations +Hispanicize, Hispanicise +hispanicize, hispanicise +Hispanicized, Hispanicised +hispanicized, hispanicised +Hispanicizes, Hispanicises +hispanicizes, hispanicises +Hispanicizing, Hispanicising +hispanicizing, hispanicising +Hispaniolize's, Hispaniolise's +Hispaniolize, Hispaniolise +hispaniolize, hispaniolise +Hispaniolized's, Hispaniolised's +Hispaniolized, Hispaniolised +hispaniolized, hispaniolised +Hispaniolizes, Hispaniolises +hispaniolizes, hispaniolises +Hispaniolizing's, Hispaniolising's +Hispaniolizing, Hispaniolising +hispaniolizing, hispaniolising +historicize, historicise +historicized, historicised +historicizes, historicises +historicizing, historicising +hmm, hm +hoagie's, hoagy's +hoagie, hoagy +hollos, hallos +Hollywoodize's, Hollywoodise's +Hollywoodize, Hollywoodise +Hollywoodized's, Hollywoodised's +Hollywoodized, Hollywoodised +Hollywoodizes, Hollywoodises +Hollywoodizing's, Hollywoodising's +Hollywoodizing, Hollywoodising +homeoblastic, homoeoblastic +homeobox, homoeobox +homeochromatic, homoeochromatic +homeochronous, homoeochronous +homeocrystalline, homoeocrystalline +homeogenic, homoeogenic +homeogenous, homoeogenous +homeoid, homoeoid +homeokinesis, homoeokinesis +homeomeric, homoeomeric +homeomeries, homoeomeries +homeomerous, homoeomerous +homeomery, homoeomery +homeomorph's, homoeomorph's +homeomorph, homoeomorph +homeomorphic, homoeomorphic +homeomorphies, homoeomorphies +homeomorphous, homoeomorphous +homeomorphs, homoeomorphs +homeomorphy, homoeomorphy +homeopath's, homoeopath's +homeopath, homoeopath +homeopathic, homoeopathic +homeopathicallier, homoeopathicallier +homeopathicalliest, homoeopathicalliest +homeopathically, homoeopathically +homeopathicer, homoeopathicer +homeopathicest, homoeopathicest +homeopathician, homoeopathician +homeopathicity, homoeopathicity +homeopathies, homoeopathies +homeopathist's, homoeopathist's +homeopathist, homoeopathist +homeopathists, homoeopathists +homeopaths, homoeopaths +homeopathy's, homoeopathy's +homeopathy, homoeopathy +homeophony, homoeophony +homeoplasia, homoeoplasia +homeoplastic, homoeoplastic +homeoplasy, homoeoplasy +homeopolar, homoeopolar +homeoses, homoeoses +homeosis, homoeosis +homeostases, homoeostases +homeostasis's, homoeostasis's +homeostasis, homoeostasis +homeostatic, homoeostatic +homeoteleuton, homoeoteleuton +homeoteleutons, homoeoteleutons +homeothermal, homoeothermal +homeothermic, homoeothermic +homeothermous, homoeothermous +homeotic, homoeotic +homeotype, homoeotype +homeotypic, homoeotypic +homeotypical, homoeotypical +homeozoic, homoeozoic +homeyness's, hominess's +homeyness, hominess +homeynesses, hominesses +hominization, hominisation +hominized, hominised +homogenization's, homogenisation's +homogenization, homogenisation +homogenizations, homogenisations +homogenize, homogenise +homogenized, homogenised +homogenizer's, homogeniser's +homogenizer, homogeniser +homogenizers, homogenisers +homogenizes, homogenises +homogenizing, homogenising +homologization, homologisation +homologize, homologise +homologized, homologised +homologizer's, homologiser's +homologizer, homologiser +homologizers, homologisers +homologizes, homologises +homologizing, homologising +homologue's, homolog's +homologue, homolog +homologues, homologs +honkie's, honkey's +honkie, honkey +honkies, honkeys +honor's, honour's +honor, honour +honorabilities, honourabilities +honorability's, honourability's +honorability, honourability +honorable's, honourable's +honorable, honourable +honorableness's, honourableness's +honorableness, honourableness +honorablenesses, honourablenesses +honorabler, honourabler +honorables, honourables +honorableship's, honourableship's +honorableship, honourableship +honorableships, honourableships +honorablest, honourablest +honorablier, honourablier +honorablies, honourablies +honorabliest, honourabliest +honorably, honourably +honored, honoured +honoree's, honouree's +honoree, honouree +honorees, honourees +honorer's, honourer's +honorer, honourer +honorers, honourers +honoring, honouring +honorless, honourless +honorlesser, honourlesser +honorlesses, honourlesses +honorlessest, honourlessest +honors, honours +hooch, hootch +hoodlumize, hoodlumise +hoodlumizes, hoodlumises +hookies, hookeys +hooky's, hookey's +hooky, hookey +hooliganize, hooliganise +hooliganizes, hooliganises +hoorah's, hurray's +hoorah, hurray +hoorayed, hurrayed +hooraying, hurraying +Hoosierize's, Hoosierise's +Hoosierize, Hoosierise +Hoosierizes, Hoosierises +Hooverize's, Hooverise's +Hooverize, Hooverise +Hooverizes, Hooverises +hore, horae +horizontalization's, horizontalisation's +horizontalization, horizontalisation +horizontalizations, horizontalisations +horizontalize, horizontalise +horizontalizes, horizontalises +hormonize, hormonise +hormonizes, hormonises +horrorize, horrorise +horrorizes, horrorises +horsey, horsy +hospitalization's, hospitalisation's +hospitalization, hospitalisation +hospitalizations, hospitalisations +hospitalize, hospitalise +hospitalized, hospitalised +hospitalizes, hospitalises +hospitalizing, hospitalising +hostilize, hostilise +hostilizes, hostilises +hotelization's, hotelisation's +hotelization, hotelisation +hotelizations, hotelisations +hotelize, hotelise +hotelizes, hotelises +houseled, houselled +houseling, houselling +houselings, housellings +hoveled, hovelled +hoveler, hoveller +hovelers, hovellers +hoveling, hovelling +hucksterize, hucksterise +hucksterizes, hucksterises +huer, hure +humanitarianize, humanitarianise +humanitarianizes, humanitarianises +humanization's, humanisation's +humanization, humanisation +humanizations, humanisations +humanize, humanise +humanized, humanised +humanizer's, humaniser's +humanizer, humaniser +humanizers, humanisers +humanizes, humanises +humanizing, humanising +humongous, humungous +humor's, humour's +humor, humour +humoral, humoural +humored, humoured +humorer, humourer +humorers, humourers +humorful, humourful +humoring, humouring +humorize, humorise +humorizes, humorises +humorless, humourless +humorlesser, humourlesser +humorlesses, humourlesses +humorlessest, humourlessest +humorlessness's, humourlessness's +humorlessness, humourlessness +humorlessnesses, humourlessnesses +humors, humours +humorsome, humoursome +humorsomeness, humoursomeness +hurrays, hurrahes +hurricanize, hurricanise +hurricanizes, hurricanises +huzzah's, huzza's +huzzah, huzza +huzzahed, huzzaed +huzzahing, huzzaing +huzzahs, huzzas +hyalinization's, hyalinisation's +hyalinization, hyalinisation +hyalinizations, hyalinisations +hyalinize, hyalinise +hyalinized, hyalinised +hyalinizes, hyalinises +hyalinizing, hyalinising +hybridizable's, hybridisable's +hybridizable, hybridisable +hybridizabler, hybridisabler +hybridizables, hybridisables +hybridizablest, hybridisablest +hybridization's, hybridisation's +hybridization, hybridisation +hybridizations, hybridisations +hybridize, hybridise +hybridized, hybridised +hybridizer's, hybridiser's +hybridizer, hybridiser +hybridizers, hybridisers +hybridizes, hybridises +hybridizing, hybridising +hydremia's, hydraemia's +hydremia, hydraemia +hydremias, hydraemias +hydremic, hydraemic +hydrocele, hydrocoele +hydrocephalus's, hydrocephaly's +hydrocephalus, hydrocephaly +hydrocephaluses, hydrocephalies +hydrogenization's, hydrogenisation's +hydrogenization, hydrogenisation +hydrogenizations, hydrogenisations +hydrogenize, hydrogenise +hydrogenized, hydrogenised +hydrogenizes, hydrogenises +hydrogenizing, hydrogenising +hydrolize, hydrolise +hydrolyzable's, hydrolysable's +hydrolyzable, hydrolysable +hydrolyzabler, hydrolysabler +hydrolyzables, hydrolysables +hydrolyzablest, hydrolysablest +hydrolyzate, hydrolysate +hydrolyzates, hydrolysates +hydrolyzation's, hydrolysation's +hydrolyzation, hydrolysation +hydrolyze, hydrolyse +hydrolyzed, hydrolysed +hydrolyzer's, hydrolyser's +hydrolyzer, hydrolyser +hydrolyzes, hydrolyses +hydrolyzing, hydrolysing +hydrorrhea, hydrorrhoea +hydroxylization's, hydroxylisation's +hydroxylization, hydroxylisation +hydroxylizations, hydroxylisations +hydroxylize, hydroxylise +hydroxylizes, hydroxylises +hyena's, hyaena's +hyena, hyaena +hyenic, hyaenic +hygienization's, hygienisation's +hygienization, hygienisation +hygienizations, hygienisations +hygienize, hygienise +hygienizes, hygienises +hymenean, hymenaean +hyperbolize, hyperbolise +hyperbolized, hyperbolised +hyperbolizes, hyperbolises +hyperbolizing, hyperbolising +hypercalcemia, hypercalcaemia +hypercalcemias, hypercalcaemias +hypercalcinemia, hypercalcinaemia +hypercatharsises, hypercatharses +hyperchloremia, hyperchloraemia +hypercholesterolemia, hypercholesterolaemia +hypercholesterolemias, hypercholesterolaemias +hypercivilization's, hypercivilisation's +hypercivilization, hypercivilisation +hypercivilizations, hypercivilisations +hypercivilized's, hypercivilised's +hypercivilized, hypercivilised +hypercivilizeds, hyperciviliseds +hypercriticize, hypercriticise +hypercriticized, hypercriticised +hypercriticizes, hypercriticises +hypercriticizing, hypercriticising +hypercryesthesia, hypercryaesthesia +hyperemia's, hyperaemia's +hyperemia, hyperaemia +hyperemias, hyperaemias +hyperemic, hyperaemic +hyperemphasize, hyperemphasise +hyperemphasizes, hyperemphasises +hyperesthesia's, hyperaesthesia's +hyperesthesia, hyperaesthesia +hyperesthesias, hyperaesthesias +hyperesthete's, hyperaesthete's +hyperesthete, hyperaesthete +hyperesthetic, hyperaesthetic +hyperestheticer, hyperaestheticer +hyperestheticest, hyperaestheticest +hyperglycemic, hyperglycaemic +hyperimmunization's, hyperimmunisation's +hyperimmunization, hyperimmunisation +hyperimmunizations, hyperimmunisations +hyperimmunize, hyperimmunise +hyperimmunizes, hyperimmunises +hyperinsulinization's, hyperinsulinisation's +hyperinsulinization, hyperinsulinisation +hyperinsulinizations, hyperinsulinisations +hyperinsulinize, hyperinsulinise +hyperinsulinizes, hyperinsulinises +hyperlipemia, hyperlipaemia +hyperlipemic, hyperlipaemic +hyperlipidemia, hyperlipidaemia +hypernatremia, hypernatraemia +hyperoxygenize, hyperoxygenise +hyperoxygenizes, hyperoxygenises +hyperparasitize, hyperparasitise +hyperparasitizes, hyperparasitises +hyperpnea's, hyperpnoea's +hyperpnea, hyperpnoea +hyperrealize, hyperrealise +hyperrealizes, hyperrealises +hypersensitization's, hypersensitisation's +hypersensitization, hypersensitisation +hypersensitizations, hypersensitisations +hypersensitize, hypersensitise +hypersensitized, hypersensitised +hypersensitizes, hypersensitises +hypersensitizing, hypersensitising +hyperspiritualizing's, hyperspiritualising's +hyperspiritualizing, hyperspiritualising +hyperspiritualizings, hyperspiritualisings +hyperthyroidization's, hyperthyroidisation's +hyperthyroidization, hyperthyroidisation +hyperthyroidizations, hyperthyroidisations +hyperthyroidize, hyperthyroidise +hyperthyroidizes, hyperthyroidises +hypervitalization's, hypervitalisation's +hypervitalization, hypervitalisation +hypervitalizations, hypervitalisations +hypervitalize, hypervitalise +hypervitalizes, hypervitalises +hypesthesia's, hypaesthesia's +hypesthesia, hypaesthesia +hypesthesias, hypaesthesias +hypesthesic, hypaesthesic +hypethral, hypaethral +hyphenization's, hyphenisation's +hyphenization, hyphenisation +hyphenizations, hyphenisations +hyphenize, hyphenise +hyphenized, hyphenised +hyphenizes, hyphenises +hyphenizing, hyphenising +hypnoidize, hypnoidise +hypnoidized, hypnoidised +hypnoidizes, hypnoidises +hypnoidizing, hypnoidising +hypnopedia, hypnopaedia +hypnopedias, hypnopaedias +hypnotizabilities, hypnotisabilities +hypnotizability's, hypnotisability's +hypnotizability, hypnotisability +hypnotizable's, hypnotisable's +hypnotizable, hypnotisable +hypnotizabler, hypnotisabler +hypnotizables, hypnotisables +hypnotizablest, hypnotisablest +hypnotization's, hypnotisation's +hypnotization, hypnotisation +hypnotizations, hypnotisations +hypnotize, hypnotise +hypnotized, hypnotised +hypnotizer's, hypnotiser's +hypnotizer, hypnotiser +hypnotizers, hypnotisers +hypnotizes, hypnotises +hypnotizing, hypnotising +hypocenter's, hypocentre's +hypocenter, hypocentre +hypocenters, hypocentres +hypogea, hypogaea +hypogeal, hypogaeal +hypogean, hypogaean +hypogeic, hypogaeic +hypogeous, hypogaeous +hypogeum, hypogaeum +hypomagnesemia, hypomagnesaemia +hypomagnesemias, hypomagnesaemias +hypomenorrhea, hypomenorrhoea +hypomenorrheas, hypomenorrhoeas +hypophysectomize, hypophysectomise +hypophysectomized, hypophysectomised +hypopnea's, hypopnoea's +hypopnea, hypopnoea +hyposensitization's, hyposensitisation's +hyposensitization, hyposensitisation +hyposensitize, hyposensitise +hypostasize, hypostasise +hypostasized, hypostasised +hypostasizes, hypostasises +hypostasizing, hypostasising +hypostatization's, hypostatisation's +hypostatization, hypostatisation +hypostatizations, hypostatisations +hypostatize, hypostatise +hypostatized, hypostatised +hypostatizes, hypostatises +hypostatizing, hypostatising +hypothesize, hypothesise +hypothesized, hypothesised +hypothesizer's, hypothesiser's +hypothesizer, hypothesiser +hypothesizers, hypothesisers +hypothesizes, hypothesises +hypothesizing, hypothesising +hypothetize, hypothetise +hypothetized, hypothetised +hypothetizes, hypothetises +hypothetizing, hypothetising +hypoxemia, hypoxaemia +hypoxemias, hypoxaemias +hypoxemic, hypoxaemic +hysterectomize, hysterectomise +hysterectomized, hysterectomised +hysterectomizes, hysterectomises +hysterectomizing, hysterectomising +ichneumonized's, ichneumonised's +ichneumonized, ichneumonised +ichneumonizeds, ichneumoniseds +ichorrhea, ichorrhoea +ichorrhemia, ichorrhaemia +icon's, ikon's +icon's, ikon's +icon, ikon +icon, ikon +iconic, ikonic +iconically, ikonically +iconize, iconise +iconized, iconised +iconizes, iconises +iconizing, iconising +icons, ikons +icons, ikons +Idea's, Idaea's +Idea, Idaea +idealization's, idealisation's +idealization, idealisation +idealizations, idealisations +idealize, idealise +idealized, idealised +idealizer's, idealiser's +idealizer, idealiser +idealizers, idealisers +idealizes, idealises +idealizing, idealising +Idean's, Idaean's +Idean, Idaean +ideologize, ideologise +ideologized, ideologised +ideologizing, ideologising +idiotize, idiotise +idiotized, idiotised +idiotizes, idiotises +idiotizing, idiotising +idolaster, idolastre +idolatrize, idolatrise +idolatrized, idolatrised +idolatrizer's, idolatriser's +idolatrizer, idolatriser +idolatrizes, idolatrises +idolatrizing, idolatrising +idolization's, idolisation's +idolization, idolisation +idolizations, idolisations +idolize, idolise +idolized, idolised +idolizer's, idoliser's +idolizer, idoliser +idolizers, idolisers +idolizes, idolises +idolizing, idolising +Idumea's, Idumaea's +Idumea, Idumaea +Idumean, Idumaean +Idumeans, Idumaeans +idyll's, idyl's +idyll, idyl +idylls, idyls +Ier's, Ire's +Ier, Ire +ignitable, ignitible +igniter's, ignitor's +igniter, ignitor +igniters, ignitors +ileocecal, ileocaecal +Iliadize's, Iliadise's +Iliadize, Iliadise +Iliadizes, Iliadises +illegalization's, illegalisation's +illegalization, illegalisation +illegalizations, illegalisations +illegalize, illegalise +illegalized, illegalised +illegalizes, illegalises +illegalizing, illegalising +illegitimatize, illegitimatise +illegitimatized, illegitimatised +illegitimatizes, illegitimatises +illegitimatizing, illegitimatising +illiberalize, illiberalise +illiberalized, illiberalised +illiberalizes, illiberalises +illiberalizing, illiberalising +Illuminize, Illuminise +Illuminizes, Illuminises +Imer's, Imre's +Imer, Imre +immaterialization, immaterialisation +immaterialize, immaterialise +immaterialized, immaterialised +immaterializes, immaterialises +immaterializing, immaterialising +immiserization, immiserisation +immiserizations, immiserisations +immiserize, immiserise +immiserized, immiserised +immiserizes, immiserises +immiserizing, immiserising +immobilization's, immobilisation's +immobilization, immobilisation +immobilizations, immobilisations +immobilize, immobilise +immobilized, immobilised +immobilizer, immobiliser +immobilizers, immobilisers +immobilizes, immobilises +immobilizing, immobilising +immoralize, immoralise +immoralized, immoralised +immoralizes, immoralises +immoralizing, immoralising +immortalizable's, immortalisable's +immortalizable, immortalisable +immortalizabler, immortalisabler +immortalizables, immortalisables +immortalizablest, immortalisablest +immortalization's, immortalisation's +immortalization, immortalisation +immortalizations, immortalisations +immortalize, immortalise +immortalized, immortalised +immortalizer's, immortaliser's +immortalizer, immortaliser +immortalizers, immortalisers +immortalizes, immortalises +immortalizing, immortalising +immunization's, immunisation's +immunization, immunisation +immunizations, immunisations +immunize, immunise +immunized, immunised +immunizer's, immuniser's +immunizer, immuniser +immunizes, immunises +immunizing, immunising +impactionize, impactionise +impactionizes, impactionises +impanel, empanel +impanelled, empanelled +impanelling, empanelling +impanelment, empanelment +impanels, empanels +impasted, impastoed +imperialization's, imperialisation's +imperialization, imperialisation +imperializations, imperialisations +imperialize, imperialise +imperialized, imperialised +imperializes, imperialises +imperializing, imperialising +imperiled, imperilled +imperiling, imperilling +imperscriptible, imprescriptible +impersonalization's, impersonalisation's +impersonalization, impersonalisation +impersonalizations, impersonalisations +impersonalize, impersonalise +impersonalized, impersonalised +impersonalizes, impersonalises +impersonalizing, impersonalising +impostor's, imposter's +impostor, imposter +impostors, imposters +improvisatorise, improvisatorize +improvisatorises, improvisatorizes +improviser's, improvisor's +improviser, improvisor +improvisers, improvisors +incarnalize, incarnalise +incarnalized, incarnalised +incarnalizing, incarnalising +incenter, incentre +incenters, incentres +incentivization, incentivisation +incentivizations, incentivisations +incentivize, incentivise +incentivized, incentivised +incentivizes, incentivises +incentivizing, incentivising +incerate, increate +incognizable, incognisable +incognizance's, incognisance's +incognizance, incognisance +incognizances, incognisances +incognizant, incognisant +Indianization's, Indianisation's +Indianization, Indianisation +Indianize, Indianise +Indianized, Indianised +Indianizes, Indianises +Indianizing, Indianising +indigene, indigenae +indigenization, indigenisation +indigenizations, indigenisations +indigenize, indigenise +indigenized, indigenised +indigenizes, indigenises +indigenizing, indigenising +individualization's, individualisation's +individualization, individualisation +individualizations, individualisations +individualize, individualise +individualized, individualised +individualizer's, individualiser's +individualizer, individualiser +individualizers, individualisers +individualizes, individualises +individualizing, individualising +individualizingly, individualisingly +indraft's, indraught's +indraft, indraught +indrafts, indraughts +industrialization's, industrialisation's +industrialization, industrialisation +industrializations, industrialisations +industrialize, industrialise +industrialized, industrialised +industrializes, industrialises +industrializing, industrialising +inesthetic, inaesthetic +infamize, infamise +infamized, infamised +infamizes, infamises +infamizing, infamising +infamonize, infamonise +infamonized, infamonised +infamonizes, infamonises +infamonizing, infamonising +infere, infree +inferiorize, inferiorise +inferiorizes, inferiorises +infernalize, infernalise +infernalizes, infernalises +infidelize, infidelise +infidelizes, infidelises +infinitize, infinitise +infinitizes, infinitises +inflection's, inflexion's +inflection, inflexion +inflections, inflexions +informalize, informalise +informalizes, informalises +Ingveonic's, Ingvaeonic's +Ingveonic, Ingvaeonic +Ingweonic's, Ingwaeonic's +Ingweonic, Ingwaeonic +inhumanize, inhumanise +inhumanizes, inhumanises +initialed, initialled +initialer's, initialler's +initialer, initialler +initialers, initiallers +initialing, initialling +initializable, initialisable +initialization's, initialisation's +initialization, initialisation +initializations, initialisations +initialize, initialise +initialized, initialised +initializer, initialiser +initializers, initialisers +initializes, initialises +initializing, initialising +inorganization, inorganisation +inorganizations, inorganisations +inorganized, inorganised +inquire, enquire +inquired, enquired +inquires, enquires +inquiries, enquiries +inquiring, enquiring +inquiry's, enquiry's +inquiry, enquiry +insignia's, insigne's +insignia, insigne +insolubilization's, insolubilisation's +insolubilization, insolubilisation +insolubilize, insolubilise +insolubilized, insolubilised +insolubilizes, insolubilises +insolubilizing, insolubilising +install, instal +installment's, instalment's +installment, instalment +installments, instalments +installs, instals +instill, instil +instills, instils +instituter's, institutor's +instituter, institutor +instituters, institutors +institutionalization's, institutionalisation's +institutionalization, institutionalisation +institutionalizations, institutionalisations +institutionalize, institutionalise +institutionalized, institutionalised +institutionalizes, institutionalises +institutionalizing, institutionalising +institutionize, institutionise +institutionizes, institutionises +instrumentalize, instrumentalise +instrumentalizes, instrumentalises +insularize, insularise +insularizes, insularises +insurrectionize, insurrectionise +insurrectionized, insurrectionised +insurrectionizes, insurrectionises +insurrectionizing, insurrectionising +integralization's, integralisation's +integralization, integralisation +integralizations, integralisations +integralize, integralise +integralizes, integralises +intellectualization's, intellectualisation's +intellectualization, intellectualisation +intellectualizations, intellectualisations +intellectualize, intellectualise +intellectualized, intellectualised +intellectualizer's, intellectualiser's +intellectualizer, intellectualiser +intellectualizers, intellectualisers +intellectualizes, intellectualises +intellectualizing, intellectualising +intercivilization's, intercivilisation's +intercivilization, intercivilisation +intercivilizations, intercivilisations +intercolonization's, intercolonisation's +intercolonization, intercolonisation +intercolonizations, intercolonisations +intercrystallization's, intercrystallisation's +intercrystallization, intercrystallisation +intercrystallizations, intercrystallisations +intercrystallize, intercrystallise +intercrystallizes, intercrystallises +interhemal, interhaemal +interhybridize, interhybridise +interhybridizes, interhybridises +interiorization, interiorisation +interiorize, interiorise +interiorized, interiorised +interiorizes, interiorises +interiorizing, interiorising +interjectionalize, interjectionalise +interjectionalized, interjectionalised +interjectionalizes, interjectionalises +interjectionalizing, interjectionalising +interjectionize, interjectionise +interjectionizes, interjectionises +interjudgment's, interjudgement's +interjudgment, interjudgement +interjudgments, interjudgements +internalization's, internalisation's +internalization, internalisation +internalizations, internalisations +internalize, internalise +internalized, internalised +internalizes, internalises +internalizing, internalising +internationalization's, internationalisation's +internationalization, internationalisation +internationalizations, internationalisations +internationalize, internationalise +internationalized, internationalised +internationalizes, internationalises +internationalizing, internationalising +internment, internement +internments, internements +internship, interneship +internships, interneships +interorganizational, interorganisational +intime, intimae +intraorganization's, intraorganisation's +intraorganization, intraorganisation +intraorganizations, intraorganisations +inure, enure +inured, enured +inures, enures +inuring, enuring +invigor, invigour +iodization's, iodisation's +iodization, iodisation +iodize, iodise +iodized, iodised +iodizer's, iodiser's +iodizer, iodiser +iodizers, iodisers +iodizes, iodises +iodizing, iodising +Ionicization's, Ionicisation's +Ionicization, Ionicisation +Ionicizations, Ionicisations +Ionicize's, Ionicise's +Ionicize, Ionicise +Ionicized's, Ionicised's +Ionicized, Ionicised +Ionicizes, Ionicises +Ionicizing's, Ionicising's +Ionicizing, Ionicising +ionizable's, ionisable's +ionizable, ionisable +ionizabler, ionisabler +ionizables, ionisables +ionizablest, ionisablest +ionization's, ionisation's +ionization, ionisation +ionizations, ionisations +ionize, ionise +ionized, ionised +ionizer's, ioniser's +ionizer, ioniser +ionizers, ionisers +ionizes, ionises +ionizing, ionising +ionizings, ionisings +ionizion, ionision +ionizions, ionisions +Iphinoe's, Iphinoae's +Iphinoe, Iphinoae +ipomea, ipomoea +Iranize's, Iranise's +Iranize, Iranise +Iranizes, Iranises +Iricize's, Iricise's +Iricize, Iricise +Iricized's, Iricised's +Iricized, Iricised +Iricizing's, Iricising's +Iricizing, Iricising +iridectomize, iridectomise +iridectomized, iridectomised +iridectomizing, iridectomising +iridization, iridisation +iridizations, iridisations +iridize, iridise +iridized, iridised +iridizes, iridises +iridizing, iridising +Irishize's, Irishise's +Irishize, Irishise +Irishized's, Irishised's +Irishized, Irishised +Irishizes, Irishises +Irishizing's, Irishising's +Irishizing, Irishising +ironize, ironise +ironized, ironised +ironizes, ironises +ironizing, ironising +irrationalize, irrationalise +irrationalized, irrationalised +irrationalizes, irrationalises +irrationalizing, irrationalising +irrealizable, irrealisable +irrecognizable, irrecognisable +irregularize, irregularise +irregularizes, irregularises +ischemia's, ischaemia's +ischemia, ischaemia +ischemias, ischaemias +ischemic, ischaemic +Islamicize's, Islamicise's +Islamicize, Islamicise +Islamicized's, Islamicised's +Islamicized, Islamicised +Islamicizes, Islamicises +Islamicizing's, Islamicising's +Islamicizing, Islamicising +Islamization's, Islamisation's +Islamization, Islamisation +Islamizations, Islamisations +Islamize, Islamise +Islamized, Islamised +Islamizes, Islamises +Islamizing, Islamising +isochronization, isochronisation +isochronize, isochronise +isochronized, isochronised +isochronizes, isochronises +isochronizing, isochronising +isoimmunization's, isoimmunisation's +isoimmunization, isoimmunisation +isoimmunizations, isoimmunisations +isoimmunize, isoimmunise +isoimmunizes, isoimmunises +isomerization's, isomerisation's +isomerization, isomerisation +isomerizations, isomerisations +isomerize, isomerise +isomerized, isomerised +isomerizes, isomerises +isomerizing, isomerising +Israelitize's, Israelitise's +Israelitize, Israelitise +Israelitizes, Israelitises +Italianization's, Italianisation's +Italianization, Italianisation +Italianizations, Italianisations +Italianize, Italianise +italianize, italianise +Italianized, Italianised +italianized, italianised +Italianizer's, Italianiser's +Italianizer, Italianiser +Italianizers, Italianisers +Italianizes, Italianises +italianizes, italianises +Italianizing, Italianising +italianizing, italianising +italicization's, italicisation's +italicization, italicisation +italicizations, italicisations +italicize, italicise +italicized, italicised +italicizes, italicises +italicizing, italicising +itemization's, itemisation's +itemization, itemisation +itemizations, itemisations +itemize, itemise +itemized, itemised +itemizer's, itemiser's +itemizer, itemiser +itemizers, itemisers +itemizes, itemises +itemizing, itemising +Iturean, Ituraean +Itureans, Ituraeans +izing, ising +jacobean, jacobaean +Jacobinization's, Jacobinisation's +Jacobinization, Jacobinisation +Jacobinize's, Jacobinise's +Jacobinize, Jacobinise +Jacobinized's, Jacobinised's +Jacobinized, Jacobinised +Jacobinizes, Jacobinises +Jacobinizing's, Jacobinising's +Jacobinizing, Jacobinising +jail's, gaol's +jail, gaol +jailbird's, gaolbird's +jailbird, gaolbird +jailbirds, gaolbirds +jailbreak's, gaolbreak's +jailbreak, gaolbreak +jailbreaks, gaolbreaks +jailed, gaoled +jailing, gaoling +jailor's, gaoler's +jailor, gaoler +jailors, gaolers +jails, gaols +janizaries, janisaries +janizary, janisary +Japanization's, Japanisation's +Japanization, Japanisation +Japanizations, Japanisations +Japanize, Japanise +Japanized, Japanised +Japanizes, Japanises +Japanizing, Japanising +jargonization's, jargonisation's +jargonization, jargonisation +jargonizations, jargonisations +jargonize, jargonise +jargonized, jargonised +jargonizes, jargonises +jargonizing, jargonising +jasmine's, jessamine's +jasmine, jessamine +jasmines, jessamines +jasperize, jasperise +jasperized, jasperised +jasperizes, jasperises +jasperizing, jasperising +jeez, geez +jeopardization, jeopardisation +jeopardize, jeopardise +jeopardized, jeopardised +jeopardizes, jeopardises +jeopardizing, jeopardising +jerrican's, jerry_can's +jerrican, jerry_can +jerricans, jerry_cans +Jesuitization's, Jesuitisation's +Jesuitization, Jesuitisation +Jesuitize, Jesuitise +Jesuitized, Jesuitised +Jesuitizes, Jesuitises +Jesuitizing, Jesuitising +jeweled, jewelled +jeweler's, jeweller's +jeweler, jeweller +jewelers, jewellers +jeweling, jewelling +jewelry's, jewellery's +jewelry, jewellery +jihad's, jehad's +jihad, jehad +jihads, jehads +jinricksha's, jinriksha's +jinricksha, jinriksha +jinrickshas, jinrikshas +jiujitsu's, jujutsu's +jokey, joky +Jonathanization's, Jonathanisation's +Jonathanization, Jonathanisation +Jonathanizations, Jonathanisations +jor, jour +jors, jours +journalization's, journalisation's +journalization, journalisation +journalizations, journalisations +journalize, journalise +journalized, journalised +journalizer's, journaliser's +journalizer, journaliser +journalizers, journalisers +journalizes, journalises +journalizing, journalising +jovialize, jovialise +jovializes, jovialises +Judaization's, Judaisation's +Judaization, Judaisation +Judaize, Judaise +Judaized, Judaised +Judaizer's, Judaiser's +Judaizer, Judaiser +judaizer, judaiser +Judaizing, Judaising +Judean, Judaean +Judeans, Judaeans +Judeophobia's, Judaeophobia's +Judeophobia, Judaeophobia +judgment's, judgement's +judgment, judgement +judgmental, judgemental +judgmentaler, judgementaler +judgmentalest, judgementalest +judgments, judgements +judicialize, judicialise +judicializes, judicialises +jujutsu, jiujitsu +jujutsus, jiujitsus +Julide's, Julidae's +Julide, Julidae +jumboize, jumboise +jumboized, jumboised +jumboizes, jumboises +jumboizing, jumboising +junketeer's, junketer's +junketeer, junketer +junketeers, junketers +juvenilize, juvenilise +juvenilizes, juvenilises +kabob, kebob +kabobs, kebobs +kane, kanae +kaolinization's, kaolinisation's +kaolinization, kaolinisation +kaolinizations, kaolinisations +kaolinize, kaolinise +kaolinized, kaolinised +kaolinizes, kaolinises +kaolinizing, kaolinising +kebob's, kabob's +ked, kaed +Keizer's, Keiser's +Keizer, Keiser +kellia, koellia +kembed, kemboed +kenneled, kennelled +kenneling, kennelling +Keppel's, Koeppel's +Keppel, Koeppel +keratinization's, keratinisation's +keratinization, keratinisation +keratinizations, keratinisations +keratinize, keratinise +keratinized, keratinised +keratinizes, keratinises +keratinizing, keratinising +Kerin's, Krein's +Kerin, Krein +kerneled, kernelled +kerneling, kernelling +kerosene's, kerosine's +kerosene, kerosine +kerosenes, kerosines +ketonemia, ketonaemia +ketonization's, ketonisation's +ketonization, ketonisation +ketonizations, ketonisations +ketonize, ketonise +ketonizes, ketonises +kiddie's, kiddy's +kiddie, kiddy +kidnapped, kidnaped +kidnappee's, kidnapee's +kidnappee, kidnapee +kidnappees, kidnapees +kidnapper's, kidnaper's +kidnapper, kidnaper +kidnappers, kidnapers +kidnapping, kidnaping +kilogram's, kilogramme's +kilogram, kilogramme +kilograms, kilogrammes +kiloliter's, kilolitre's +kiloliter, kilolitre +kiloliters, kilolitres +kilometer's, kilometre's +kilometer, kilometre +kilometers, kilometres +kindergartner's, kindergartener's +kindergartner, kindergartener +kindergartners, kindergarteners +kinestheses, kinaestheses +kinesthesia's, kinaesthesia's +kinesthesia, kinaesthesia +kinesthesias, kinaesthesias +kinesthesis's, kinaesthesis's +kinesthesis, kinaesthesis +kinesthetic, kinaesthetic +kinestheticallier, kinaestheticallier +kinestheticalliest, kinaestheticalliest +kinesthetically, kinaesthetically +kinestheticer, kinaestheticer +kinestheticest, kinaestheticest +kinesthetics, kinaesthetics +kissogram's, kissagram's +kissogram, kissagram +kissograms, kissagrams +knickknack's, nicknack's +knickknack, nicknack +knickknacks, nicknacks +knockwurst's, knackwurst's +knockwurst, knackwurst +knockwursts, knackwursts +kooky, kookie +kopek's, copeck's +kopek, copeck +kopeks, copecks +Kossean's, Kossaean's +Kossean, Kossaean +kumquat's, cumquat's +kumquat, cumquat +kumquats, cumquats +kyanize, kyanise +kyanized, kyanised +kyanizes, kyanises +kyanizing, kyanising +kyles, kyloes +labelable, labellable +labeled, labelled +labeler's, labeller's +labeler, labeller +labelers, labellers +labeling, labelling +labialization's, labialisation's +labialization, labialisation +labializations, labialisations +labialize, labialise +labialized, labialised +labializes, labialises +labializing, labialising +labiate, labiatae +labilization's, labilisation's +labilization, labilisation +labilizations, labilisations +labilize, labilise +labilizes, labilises +labiovelarization's, labiovelarisation's +labiovelarization, labiovelarisation +labiovelarize, labiovelarise +labiovelarized, labiovelarised +labiovelarizing, labiovelarising +labor's, labour's +labor, labour +laborabilities, labourabilities +laborability's, labourability's +laborability, labourability +laborable's, labourable's +laborable, labourable +laborables, labourables +laborage, labourage +labored, laboured +laboredlier, labouredlier +laboredliest, labouredliest +laboredly, labouredly +laboredness's, labouredness's +laboredness, labouredness +laborednesses, labourednesses +laborer's, labourer's +laborer, labourer +laborers, labourers +laboress, labouress +laborhood's, labourhood's +laborhood, labourhood +laborhoods, labourhoods +laboring's, labouring's +laboring, labouring +laboringlier, labouringlier +laboringliest, labouringliest +laboringly, labouringly +laborings, labourings +Laborism's, Labourism's +laborism's, labourism's +Laborism, Labourism +laborism, labourism +laborisms, labourisms +laborist's, labourist's +laborist, labourist +laborists, labourists +Laborite's, Labourite's +laborite's, labourite's +Laborite, Labourite +laborite, labourite +Laborites, Labourites +laborites, labourites +laborless, labourless +laborlesser, labourlesser +laborlesses, labourlesses +laborlessest, labourlessest +labors, labours +laborsaving, laboursaving +laborsome, laboursome +laborsomely, laboursomely +lachrymal, lacrimal +lackluster's, lacklustre's +lackluster, lacklustre +lacklusterrer, lacklustrer +lacklusterrest, lacklustrest +lacklusters, lacklustres +laconize, laconise +laconized, laconised +laconizes, laconises +laconizing, laconising +lactonized, lactonised +lagniappe's, lagnappe's +lagniappe, lagnappe +lagniappes, lagnappes +laicization's, laicisation's +laicization, laicisation +laicizations, laicisations +laicize, laicise +laicized, laicised +laicizes, laicises +laicizing, laicising +lairize, lairise +lairized, lairised +lairizes, lairises +lairizing, lairising +lambaste, lambast +lambastes, lambasts +laminarize, laminarise +laminarized, laminarised +laminarizes, laminarises +laminarizing, laminarising +Lander's, Landre's +Lander, Landre +Laothoe's, Laothoae's +Laothoe, Laothoae +lapeled, lapelled +lasagna's, lasagne's +lasagna, lasagne +lasagnas, lasagnes +laster, lastre +latentize, latentise +latentizes, latentises +lateralization's, lateralisation's +lateralization, lateralisation +lateralizations, lateralisations +lateralize, lateralise +lateralizes, lateralises +laterization's, laterisation's +laterization, laterisation +laterizations, laterisations +Latinization's, Latinisation's +Latinization, Latinisation +Latinizations, Latinisations +Latinize, Latinise +latinize, latinise +Latinized, Latinised +Latinizer, Latiniser +Latinizers, Latinisers +Latinizes, Latinises +Latinizing, Latinising +launderette's, laundrette's +launderette, laundrette +launderettes, laundrettes +laure, laurae +laureled, laurelled +laureling, laurelling +lavalier_microphone's, lavaliere_microphone's +lavalier_microphone, lavaliere_microphone +lavalier_microphones, lavaliere_microphones +lavolted, lavoltaed +leaped, leapt +learned, learnt +leatherize, leatherise +leatherizes, leatherises +lefty's, leftie's +lefty, leftie +legalization's, legalisation's +legalization, legalisation +legalizations, legalisations +legalize, legalise +legalized, legalised +legalizes, legalises +legalizing, legalising +legitimatize, legitimatise +legitimatized, legitimatised +legitimatizes, legitimatises +legitimatizing, legitimatising +legitimization's, legitimisation's +legitimization, legitimisation +legitimizations, legitimisations +legitimize, legitimise +legitimized, legitimised +legitimizer, legitimiser +legitimizes, legitimises +legitimizing, legitimising +leguminose, leguminosae +lemmatize, lemmatise +lemmatized, lemmatised +lemmatizes, lemmatises +lemmatizing, lemmatising +leporide, leporidae +leptospire, leptospirae +Lernean's, Lernaean's +Lernean, Lernaean +lernean, lernaean +lesses, loesses +lethalize, lethalise +lethalizes, lethalises +lethargize, lethargise +lethargized, lethargised +lethargizes, lethargises +lethargizing, lethargising +leucemia, leucaemia +leucemias, leucaemias +leucemic, leucaemic +leuchemia, leuchaemia +leucocythemia, leucocythaemia +leucocythemic, leucocythaemic +leucorrhea's, leucorrhoea's +leucorrhea, leucorrhoea +leucorrheal, leucorrhoeal +leucorrheas, leucorrhoeas +Leucothoe's, Leucothoae's +Leucothoe, Leucothoae +leukemia's, leukaemia's +leukemia, leukaemia +leukemias, leukaemias +leukemogeneses, leukaemogeneses +leukemogenesis, leukaemogenesis +leukorrhea, leukorrhoea +leukorrheal, leukorrhoeal +leveled, levelled +leveler's, leveller's +leveler, leveller +levelers, levellers +levelest, levellest +leveling's, levelling's +leveling, levelling +levigate, laevigate +levigated, laevigated +levigates, laevigates +levigating, laevigating +levo, laevo +levoduction, laevoduction +levogyrate, laevogyrate +levogyre, laevogyre +levogyrous, laevogyrous +levolactic, laevolactic +levorotation's, laevorotation's +levorotation, laevorotation +levorotations, laevorotations +levorotatory, laevorotatory +levotartaric, laevotartaric +levoversion, laevoversion +levulin, laevulin +levulose's, laevulose's +levulose, laevulose +levuloses, laevuloses +lexicalization, lexicalisation +lexicalizations, lexicalisations +lexiconize, lexiconise +lexiconizes, lexiconises +libelant's, libellant's +libelant, libellant +libelants, libellants +libeled, libelled +libelee's, libellee's +libelee, libellee +libelees, libellees +libeler's, libeller's +libeler, libeller +libelers, libellers +libeling, libelling +libelous, libellous +libelouser, libellouser +libelousest, libellousest +libelouslier, libellouslier +libelousliest, libellousliest +libelously, libellously +liberalization's, liberalisation's +liberalization, liberalisation +liberalizations, liberalisations +liberalize, liberalise +liberalized, liberalised +liberalizer's, liberaliser's +liberalizer, liberaliser +liberalizers, liberalisers +liberalizes, liberalises +liberalizing, liberalising +licenseless, licenceless +licenselesses, licencelesses +lichenization's, lichenisation's +lichenization, lichenisation +lichenizations, lichenisations +lichenize, lichenise +lichenized, lichenised +lichenizes, lichenises +lichenizing, lichenising +licorice's, liquorice's +licorice, liquorice +lignitize, lignitise +lignitizes, lignitises +lignose, lignosae +ligule, ligulae +likabilities, likeabilities +likability's, likeability's +likability, likeability +likable, likeable +likableness's, likeableness's +likableness, likeableness +likablenesses, likeablenesses +Lilliputianize's, Lilliputianise's +Lilliputianize, Lilliputianise +Lilliputianizes, Lilliputianises +linchpin's, lynchpin's +linchpin, lynchpin +linchpins, lynchpins +linearizable, linearisable +linearization's, linearisation's +linearization, linearisation +linearizations, linearisations +linearize, linearise +linearized, linearised +linearizes, linearises +linearizing, linearising +linearizion, linearision +linenize, linenise +linenizer, lineniser +linenizers, linenisers +linenizes, linenises +linge, lingoe +lingualize, lingualise +lingualizes, lingualises +linguine's, linguini's +linguine, linguini +linguines, linguinis +lionizable's, lionisable's +lionizable, lionisable +lionizables, lionisables +lionization's, lionisation's +lionization, lionisation +lionizations, lionisations +lionize, lionise +lionized, lionised +lionizer's, lioniser's +lionizer, lioniser +lionizers, lionisers +lionizes, lionises +lionizing, lionising +lipemia, lipaemia +lipemic, lipaemic +lipoidemia, lipoidaemia +liquefied, liquified +liquefier, liquifier +liquefiers, liquifiers +liquefies, liquifies +liquefy, liquify +liquefying, liquifying +liquidization, liquidisation +liquidize, liquidise +liquidized, liquidised +liquidizer's, liquidiser's +liquidizer, liquidiser +liquidizers, liquidisers +liquidizes, liquidises +liquidizing, liquidising +lissome, lissom +lissomely, lissomly +lissomeness, lissomness +lissomenesses, lissomnesses +Listerize's, Listerise's +Listerize, Listerise +Listerized's, Listerised's +Listerized, Listerised +Listerizes, Listerises +Listerizing's, Listerising's +Listerizing, Listerising +liter's, litre's +liter, litre +literalization's, literalisation's +literalization, literalisation +literalizations, literalisations +literalize, literalise +literalized, literalised +literalizer's, literaliser's +literalizer, literaliser +literalizers, literalisers +literalizes, literalises +literalizing, literalising +liters, litres +lithed, lithoed +lithemia, lithaemia +lithemic, lithaemic +lithographize, lithographise +lithographizes, lithographises +lithopedion, lithopaedion +lithopedium, lithopaedium +lithophyse, lithophysae +lithotritize, lithotritise +lithotritized, lithotritised +lithotritizes, lithotritises +lithotritizing, lithotritising +livable, liveable +livableness, liveableness +lobotomize, lobotomise +lobotomized, lobotomised +lobotomizes, lobotomises +lobotomizing, lobotomising +localizable's, localisable's +localizable, localisable +localizabler, localisabler +localizables, localisables +localizablest, localisablest +localization's, localisation's +localization, localisation +localizations, localisations +localize, localise +localized, localised +localizer's, localiser's +localizer, localiser +localizers, localisers +localizes, localises +localizing, localising +locator's, locater's +locator, locater +locators, locaters +lodestar's, loadstar's +lodestar, loadstar +lodestars, loadstars +lodestone's, loadstone's +lodestone, loadstone +lodestones, loadstones +lodgment's, lodgement's +lodgment, lodgement +lodgments, lodgements +lodicule, lodiculae +loed, looed +logicalization's, logicalisation's +logicalization, logicalisation +logicalizations, logicalisations +logicalize, logicalise +logicalizes, logicalises +logicize, logicise +logicized, logicised +logicizes, logicises +logicizing, logicising +logopedic, logopaedic +logopedics's, logopaedics's +logopedics, logopaedics +logorrhea's, logorrhoea's +logorrhea, logorrhoea +logorrheas, logorrhoeas +lollipop's, lollypop's +lollipop, lollypop +lollipops, lollypops +lollygag, lallygag +lollygagged, lallygagged +lollygagging, lallygagging +lollygags, lallygags +Londonization's, Londonisation's +Londonization, Londonisation +Londonizations, Londonisations +Londonize's, Londonise's +Londonize, Londonise +Londonized's, Londonised's +Londonized, Londonised +Londonizes, Londonises +Londonizing's, Londonising's +Londonizing, Londonising +longeval, longaeval +longevous, longaevous +looneyies, looneys +loonier, looneyier +loony's, looney's +loony, looney +lordy, lourdy +lorings, lourings +lory, loury +louter, loutre +louver's, louvre's +louver, louvre +louvered, louvred +louvers, louvres +lovability, lovaebility +lovable, loveable +lovableness, loveableness +lovably, loveably +love, luv +loves, luvs +lovey, luvvie +loveys, luvvies +loyalize, loyalise +loyalizes, loyalises +lumbarization's, lumbarisation's +lumbarization, lumbarisation +lumbarizations, lumbarisations +lunatize, lunatise +lunatizes, lunatises +lunule, lunulae +luster's, lustre's +luster, lustre +lustered, lustred +lustering's, lustring's +lustering, lustring +lusterless, lustreless +lusterlesser, lustrelesser +lusterlessest, lustrelessest +lusters, lustres +lusterware's, lustreware's +lusterware, lustreware +lusterwares, lustrewares +luteinization's, luteinisation's +luteinization, luteinisation +luteinizations, luteinisations +luteinize, luteinise +luteinized, luteinised +luteinizes, luteinises +luteinizing, luteinising +Lutheranize's, Lutheranise's +Lutheranize, Lutheranise +Lutheranizer's, Lutheraniser's +Lutheranizer, Lutheraniser +Lutheranizers, Lutheranisers +Lutheranizes, Lutheranises +lutrine, lutrinae +luvvy, luvvie +lychee's, lichee's +lychee, lichee +lychees, lichees +lymphedema, lymphoedema +lymphemia, lymphaemia +lyophilization's, lyophilisation's +lyophilization, lyophilisation +lyophilizations, lyophilisations +lyophilize, lyophilise +lyophilized, lyophilised +lyophilizer, lyophiliser +lyophilizes, lyophilises +lyophilizing, lyophilising +lyricization's, lyricisation's +lyricization, lyricisation +lyricize, lyricise +lyricized, lyricised +lyricizes, lyricises +lyricizing, lyricising +lysogenization, lysogenisation +lysogenize, lysogenise +lysogenized, lysogenised +lysogenizes, lysogenises +lysogenizing, lysogenising +mac's, mack's +mac, mack +macadamization's, macadamisation's +macadamization, macadamisation +macadamizations, macadamisations +macadamize, macadamise +macadamized, macadamised +macadamizes, macadamises +macadamizing, macadamising +macarize, macarise +macarized, macarised +macarizes, macarises +macarizing, macarising +Maccabean, Maccabaean +machinization's, machinisation's +machinization, machinisation +machinizations, machinisations +machinize, machinise +machinizes, machinises +mackintosh's, macintosh's +mackintosh, macintosh +mackintoshes, macintoshes +macrander, macrandre +macs, macks +macule, maculae +Madera's, Madoera's +Madera, Madoera +maderization, maderisation +maderizations, maderisations +maderize, maderise +maderized, maderised +maderizes, maderises +maderizing, maderising +maed, maaed +maenad's, menad's +maenad, menad +maenadic, menadic +maenads, menads +magicalize, magicalise +magicalizes, magicalises +magnetizabilities, magnetisabilities +magnetizability's, magnetisability's +magnetizability, magnetisability +magnetizable's, magnetisable's +magnetizable, magnetisable +magnetizables, magnetisables +magnetization's, magnetisation's +magnetization, magnetisation +magnetizations, magnetisations +magnetize, magnetise +magnetized, magnetised +magnetizer's, magnetiser's +magnetizer, magnetiser +magnetizers, magnetisers +magnetizes, magnetises +magnetizing, magnetising +maharajah's, maharaja's +maharajah, maharaja +maharajahs, maharajas +maharani's, maharanee's +maharani, maharanee +maharanis, maharanees +mahoganize, mahoganise +mahoganized, mahoganised +mahoganizes, mahoganises +mahoganizing, mahoganising +maiger, maigre +mainor, mainour +mainors, mainours +mainprize, mainprise +maisters, maistres +Maize's, Maise's +Maize, Maise +majolica's, maiolica's +majolica, maiolica +majolicas, maiolicas +majorize, majorise +majorizes, majorises +majuscule, majusculae +Malayize's, Malayise's +Malayize, Malayise +Malayizes, Malayises +malleablize, malleablise +malleablizes, malleablises +malodor's, malodour's +malodor, malodour +malodorousness, malodourousness +malodors, malodours +mandarinize, mandarinise +mandarinizes, mandarinises +Mandean's, Mandaean's +Mandean, Mandaean +Mandeans, Mandaeans +mandoer, mandore +mandrel's, mandril's +mandrel, mandril +mandrels, mandrils +maneuverabilities, manoeuvrabilities +maneuverability's, manoeuvrability's +maneuverability, manoeuvrability +maneuverable, manoeuvrable +maneuverabler, manoeuvrabler +maneuverablest, manoeuvrablest +maneuverer's, manoeuvrer's +maneuverer, manoeuvrer +maneuverers, manoeuvrers +Manhattanize, Manhattanise +Manhattanizes, Manhattanises +Manicheanism's, Manichaeanism's +Manicheanism, Manichaeanism +Manicheans, Manichaeans +Manicheism's, Manichaeism's +Manicheism, Manichaeism +Manicheisms, Manichaeisms +Manicheus's, Manichaeus's +Manicheus, Manichaeus +manikin's, mannikin's +manikin, mannikin +manikins, mannikins +mannerize, mannerise +mannerizes, mannerises +manoeuvre's, manoeuver's +manoeuvre, manoeuver +manoeuvred, manoeuvered +manoeuvres, manoeuvers +manoeuvring, manoeuvering +manoeuvrings, manoeuverings +mantelpiece, mantlepiece +mantelpieces, mantlepieces +mantes, mantoes +marabou's, marabout's +marabou, marabout +marabous, marabouts +marbleize, marbleise +marbleized, marbleised +marbleizes, marbleises +marbleizing, marbleising +margarite, margaritae +marginalization, marginalisation +marginalize, marginalise +marginalized, marginalised +marginalizes, marginalises +marginalizing, marginalising +marijuana's, marihuana's +marijuana, marihuana +marijuanas, marihuanas +marlinespike's, marlinspike's +marlinespike, marlinspike +marlinespikes, marlinspikes +marmarize, marmarise +marmarized, marmarised +marmarizes, marmarises +marmarizing, marmarising +marmelize, marmelise +marmelized, marmelised +marmelizes, marmelises +marmelizing, marmelising +marshaled, marshalled +marshaling, marshalling +marsupialization's, marsupialisation's +marsupialization, marsupialisation +marsupializations, marsupialisations +marsupialize, marsupialise +marsupialized, marsupialised +marsupializes, marsupialises +marsupializing, marsupialising +Marte's, Martae's +Marte, Martae +martialization's, martialisation's +martialization, martialisation +martializations, martialisations +martialize, martialise +martializes, martialises +martyrization's, martyrisation's +martyrization, martyrisation +martyrizations, martyrisations +martyrize, martyrise +martyrized, martyrised +martyrizer, martyriser +martyrizers, martyrisers +martyrizes, martyrises +martyrizing, martyrising +marveled, marvelled +marveler, marveller +marveling, marvelling +marvelous, marvellous +marvelouser, marvellouser +marvelousest, marvellousest +marvelouslier, marvellouslier +marvelousliest, marvellousliest +marvelously, marvellously +marvelousness's, marvellousness's +marvelousness, marvellousness +marvelousnesses, marvellousnesses +masculinization's, masculinisation's +masculinization, masculinisation +masculinizations, masculinisations +masculinize, masculinise +masculinized, masculinised +masculinizes, masculinises +masculinizing, masculinising +materialization's, materialisation's +materialization, materialisation +materializations, materialisations +materialize, materialise +materialized, materialised +materializer's, materialiser's +materializer, materialiser +materializers, materialisers +materializes, materialises +materializing, materialising +maternalize, maternalise +maternalized, maternalised +maternalizes, maternalises +maternalizing, maternalising +maters, matres +mathematicize, mathematicise +mathematicized, mathematicised +mathematicizes, mathematicises +mathematicizing, mathematicising +mathematization's, mathematisation's +mathematization, mathematisation +mathematizations, mathematisations +mathematize, mathematise +mathematized, mathematised +mathematizes, mathematises +mathematizing, mathematising +matronize, matronise +matronized, matronised +matronizes, matronises +matronizing, matronising +matte, mat +Matthean, Matthaean +maudlinize, maudlinise +maudlinizes, maudlinises +mauger, maugre +maven's, mavin's +maven, mavin +mavens, mavins +maximization's, maximisation's +maximization, maximisation +maximizations, maximisations +maximize, maximise +maximized, maximised +maximizer's, maximiser's +maximizer, maximiser +maximizers, maximisers +maximizes, maximises +maximizing, maximising +mazurka's, mazourka's +mazurka, mazourka +mazurkas, mazourkas +meager, meagre +meagerly, meagrely +meagerness's, meagreness's +meagerness, meagreness +meagernesses, meagrenesses +meagerrer, meagrer +meagerrest, meagrest +meandrine, maeandrine +meandriniform, maeandriniform +meanie's, meany's +meanie, meany +mechanicalization's, mechanicalisation's +mechanicalization, mechanicalisation +mechanicalizations, mechanicalisations +mechanicalize, mechanicalise +mechanicalizes, mechanicalises +mechanizable, mechanisable +mechanization's, mechanisation's +mechanization, mechanisation +mechanizations, mechanisations +mechanize, mechanise +mechanized, mechanised +mechanizer's, mechaniser's +mechanizer, mechaniser +mechanizers, mechanisers +mechanizes, mechanises +mechanizing, mechanising +meck, moeck +Med's, Moed's +Med, Moed +medaled, medalled +medaling, medalling +medalist's, medallist's +medalist, medallist +medalists, medallists +medalize, medalise +medalizes, medalises +medialization's, medialisation's +medialization, medialisation +medializations, medialisations +medialize, medialise +medializes, medialises +mediatization's, mediatisation's +mediatization, mediatisation +mediatizations, mediatisations +mediatize, mediatise +mediatized, mediatised +mediatizes, mediatises +mediatizing, mediatising +medicalization, medicalisation +medicalizations, medicalisations +medicalize, medicalise +medicalized, medicalised +medicalizes, medicalises +medicalizing, medicalising +medieval's, mediaeval's +medieval, mediaeval +medievalism's, mediaevalism's +medievalism, mediaevalism +medievalisms, mediaevalisms +medievally, mediaevally +medievals, mediaevals +Mediterraneanization's, Mediterraneanisation's +Mediterraneanization, Mediterraneanisation +Mediterraneanizations, Mediterraneanisations +Mediterraneanize's, Mediterraneanise's +Mediterraneanize, Mediterraneanise +Mediterraneanizes, Mediterraneanises +mediumization's, mediumisation's +mediumization, mediumisation +mediumizations, mediumisations +mediumize, mediumise +mediumizes, mediumises +megagram, megagramme +megagrams, megagrammes +megameter, megametre +megameters, megametres +megbote, maegbote +megerg, megaerg +melanemia, melanaemia +melanemic, melanaemic +melanization, melanisation +melanize, melanise +melanized, melanised +melanizes, melanises +melanizing, melanising +mele, meloe +melena, melaena +melenic, melaenic +Melie's, Meliae's +Melie, Meliae +meline, melinae +melitemia, melitaemia +melithemia, melithaemia +mellon, moellon +melodization, melodisation +melodize, melodise +melodized, melodised +melodizer's, melodiser's +melodizer, melodiser +melodizes, melodises +melodizing, melodising +melodramatization, melodramatisation +melodramatize, melodramatise +melodramatized, melodramatised +melodramatizes, melodramatises +melodramatizing, melodramatising +memorialization's, memorialisation's +memorialization, memorialisation +memorializations, memorialisations +memorialize, memorialise +memorialized, memorialised +memorializer's, memorialiser's +memorializer, memorialiser +memorializers, memorialisers +memorializes, memorialises +memorializing, memorialising +memorizable's, memorisable's +memorizable, memorisable +memorizables, memorisables +memorization's, memorisation's +memorization, memorisation +memorizations, memorisations +memorize, memorise +memorized, memorised +memorizer's, memoriser's +memorizer, memoriser +memorizers, memorisers +memorizes, memorises +memorizing, memorising +Mendelize's, Mendelise's +Mendelize, Mendelise +Mendelizes, Mendelises +meningorrhea, meningorrhoea +menorrhea, menorrhoea +menorrheas, menorrhoeas +menorrheic, menorrhoeic +mense, mensae +mentalization's, mentalisation's +mentalization, mentalisation +mentalizations, mentalisations +mentalize, mentalise +mentalizes, mentalises +meow's, miaow's +meow, miaow +meowed, miaowed +meowing, miaowing +meows, miaows +mephitine, mephitinae +Mera's, Maera's +Mera, Maera +mercerization's, mercerisation's +mercerization, mercerisation +mercerizations, mercerisations +mercerize, mercerise +mercerized, mercerised +mercerizer's, merceriser's +mercerizer, merceriser +mercerizers, mercerisers +mercerizes, mercerises +mercerizing, mercerising +merchandiser's, merchandizer's +merchandiser, merchandizer +merchandisers, merchandizers +mercurialization's, mercurialisation's +mercurialization, mercurialisation +mercurializations, mercurialisations +mercurialize, mercurialise +mercurialized, mercurialised +mercurializes, mercurialises +mercurializing, mercurialising +mercurize, mercurise +mercurized, mercurised +mercurizes, mercurises +mercurizing, mercurising +Meroe's, Meroae's +Meroe, Meroae +mesmerizabilities, mesmerisabilities +mesmerizability's, mesmerisability's +mesmerizability, mesmerisability +mesmerizable's, mesmerisable's +mesmerizable, mesmerisable +mesmerizables, mesmerisables +mesmerization's, mesmerisation's +mesmerization, mesmerisation +mesmerizations, mesmerisations +mesmerize, mesmerise +mesmerized, mesmerised +mesmerizer's, mesmeriser's +mesmerizer, mesmeriser +mesmerizers, mesmerisers +mesmerizes, mesmerises +mesmerizing, mesmerising +mesoglea, mesogloea +mesogleal, mesogloeal +mesogleas, mesogloeas +mesprize, mesprise +mesprizes, mesprises +mesquite's, mesquit's +mesquite, mesquit +mesquites, mesquits +metabolizable's, metabolisable's +metabolizable, metabolisable +metabolizables, metabolisables +metabolize, metabolise +metabolized, metabolised +metabolizes, metabolises +metabolizing, metabolising +metacenter's, metacentre's +metacenter, metacentre +metacenters, metacentres +metagrabolize, metagrabolise +metagrabolized, metagrabolised +metagrabolizes, metagrabolises +metagrabolizing, metagrabolising +metagrobolize, metagrobolise +metagrobolized, metagrobolised +metagrobolizes, metagrobolises +metagrobolizing, metagrobolising +metaled, metalled +metaling, metalling +metallisation's, metallization's +metallisation, metallization +metallisations, metallizations +metallise, metallize +metallised, metallized +metallises, metallizes +metallising, metallizing +metamerization's, metamerisation's +metamerization, metamerisation +metamerizations, metamerisations +metamerized's, metamerised's +metamerized, metamerised +metamerizeds, metameriseds +metaphonize, metaphonise +metaphonizes, metaphonises +metaphorize, metaphorise +metaphorizes, metaphorises +metaphysicize, metaphysicise +metaphysicizes, metaphysicises +metastasize, metastasise +metastasized, metastasised +metastasizes, metastasises +metastasizing, metastasising +metathesize, metathesise +metathesized, metathesised +metathesizes, metathesises +metathesizing, metathesising +meteorization's, meteorisation's +meteorization, meteorisation +meteorizations, meteorisations +meteorize, meteorise +meteorizes, meteorises +metergram, metregram +meterless, metreless +metership, metreship +metestrus's, metoestrus's +metestrus, metoestrus +methadone's, methadon's +methadone, methadon +methadones, methadons +methemoglobin, methaemoglobin +methodization's, methodisation's +methodization, methodisation +methodizations, methodisations +methodize, methodise +methodized, methodised +methodizer's, methodiser's +methodizer, methodiser +methodizers, methodisers +methodizes, methodises +methodizing, methodising +metope, metopae +metricize, metricise +metricized, metricised +metricizes, metricises +metricizing, metricising +metrize, metrise +metropolitanization, metropolitanisation +metropolitanize, metropolitanise +metropolitanized, metropolitanised +metropolitanizes, metropolitanises +metropolitanizing, metropolitanising +Mexicanize's, Mexicanise's +Mexicanize, Mexicanise +Mexicanizes, Mexicanises +micelle, micellae +micresthete, micraesthete +microcolorimeter, microcolourimeter +microcolorimetric, microcolourimetric +microcolorimetrically, microcolourimetrically +microcolorimetry, microcolourimetry +microgram, microgramme +micrograms, nanogrammes +microliter's, microlitre's +microliter, microlitre +microliters, microlitres +micromillimeter's, micromillimetre's +micromillimeter, micromillimetre +micromillimeters, micromillimetres +microminiaturization's, microminiaturisation's +microminiaturization, microminiaturisation +microminiaturizations, microminiaturisations +microminiaturize, microminiaturise +microminiaturized, microminiaturised +microminiaturizer, microminiaturiser +microminiaturizers, microminiaturisers +microminiaturizes, microminiaturises +microminiaturizing, microminiaturising +micronization's, micronisation's +micronization, micronisation +micronizations, micronisations +micronize, micronise +micronizes, micronises +micropaleontologies, micropalaeontologies +micropaleontologist, micropalaeontologist +micropaleontologists, micropalaeontologists +micropaleontology's, micropalaeontology's +micropaleontology, micropalaeontology +micropolarization's, micropolarisation's +micropolarization, micropolarisation +micropolarizations, micropolarisations +microscopize, microscopise +microscopizes, microscopises +microspheric, microsphaeric +Midlandize's, Midlandise's +Midlandize, Midlandise +Midlandizes, Midlandises +midsize, midsized +midwifed, midwived +midwifing, midwiving +migniardize, migniardise +militarization's, militarisation's +militarization, militarisation +militarizations, militarisations +militarize, militarise +militarized, militarised +militarizes, militarises +militarizing, militarising +milligram's, milligramme's +milligram, milligramme +milligrams, milligrammes +milliliter's, millilitre's +milliliter, millilitre +milliliters, millilitres +millimeter's, millimetre's +millimeter, millimetre +millimeters, millimetres +millionaire's, millionnaire's +millionaire, millionnaire +millionaires, millionnaires +millionize, millionise +millionizes, millionises +millipede's, millepede's +millipede, millepede +millipedes, millepedes +milometer's, mileometer's +milometer, mileometer +milometers, mileometers +Miltonize's, Miltonise's +Miltonize, Miltonise +Miltonized's, Miltonised's +Miltonized, Miltonised +Miltonizes, Miltonises +Miltonizing's, Miltonising's +Miltonizing, Miltonising +mineralizable's, mineralisable's +mineralizable, mineralisable +mineralizables, mineralisables +mineralization's, mineralisation's +mineralization, mineralisation +mineralizations, mineralisations +mineralize, mineralise +mineralized, mineralised +mineralizer's, mineraliser's +mineralizer, mineraliser +mineralizers, mineralisers +mineralizes, mineralises +mineralizing, mineralising +mineralogize, mineralogise +mineralogized, mineralogised +mineralogizes, mineralogises +mineralogizing, mineralogising +miniaturization's, miniaturisation's +miniaturization, miniaturisation +miniaturizations, miniaturisations +miniaturize, miniaturise +miniaturized, miniaturised +miniaturizes, miniaturises +miniaturizing, miniaturising +minibuses, minibusses +minimization's, minimisation's +minimization, minimisation +minimizations, minimisations +minimize, minimise +minimized, minimised +minimizer's, minimiser's +minimizer, minimiser +minimizers, minimisers +minimizes, minimises +minimizing, minimising +minuscule's, miniscule's +minuscule, miniscule +minuscules, miniscules +miraculize, miraculise +miraculized, miraculised +miraculizes, miraculises +miraculizing, miraculising +mirrorize, mirrorise +mirrorizes, mirrorises +misadvize, misadvise +misalphabetize, misalphabetise +misalphabetizes, misalphabetises +misanthropize, misanthropise +misanthropized, misanthropised +misanthropizes, misanthropises +misanthropizing, misanthropising +misauthorization's, misauthorisation's +misauthorization, misauthorisation +misauthorizations, misauthorisations +misauthorize, misauthorise +misauthorizes, misauthorises +misbaptize, misbaptise +misbaptizes, misbaptises +misbehavior's, misbehaviour's +misbehavior, misbehaviour +misbehaviors, misbehaviours +miscanonize, miscanonise +miscanonizes, miscanonises +mischaracterization's, mischaracterisation's +mischaracterization, mischaracterisation +mischaracterizations, mischaracterisations +mischaracterize, mischaracterise +mischaracterizes, mischaracterises +miscolor's, miscolour's +miscolor, miscolour +miscoloration, miscolouration +miscolored, miscoloured +miscoloring, miscolouring +miscolors, miscolours +misdemeanor's, misdemeanour's +misdemeanor, misdemeanour +misdemeanors, misdemeanours +misemphasize, misemphasise +misemphasizes, misemphasises +misjudgment's, misjudgement's +misjudgment, misjudgement +misjudgments, misjudgements +mislabeled, mislabelled +mislabeling, mislabelling +mislabor's, mislabour's +mislabor, mislabour +mislabored, mislaboured +mislaboring, mislabouring +mislabors, mislabours +misopedia, misopaedia +misopedism, misopaedism +misopedist's, misopaedist's +misopedist, misopaedist +misorganization's, misorganisation's +misorganization, misorganisation +misorganizations, misorganisations +misorganize, misorganise +misorganizes, misorganises +misprizal, misprisal +misprize, misprise +misprized, misprised +misprizer, mispriser +misprizes, misprises +misprizing, misprising +misrealize, misrealise +misrealizes, misrealises +misrecognize, misrecognise +misrecognizes, misrecognises +misrouting, misrouteing +missilery's, missilry's +missilery, missilry +missionarize, missionarise +missionarized, missionarised +missionarizes, missionarises +missionarizing, missionarising +missionization, missionisation +missionize, missionise +missionized, missionised +missionizer, missioniser +missionizers, missionisers +missionizes, missionises +missionizing, missionising +missus's, missis's +missus, missis +missuses, missises +miter's, mitre's +miter, mitre +mitered, mitred +miterer's, mitrer's +miterer, mitrer +miterflower, mitreflower +mitering, mitring +miters, mitres +miterwort's, mitrewort's +miterwort, mitrewort +miterworts, mitreworts +mithridatize, mithridatise +mithridatized, mithridatised +mithridatizes, mithridatises +mithridatizing, mithridatising +mize, mise +mobilizable's, mobilisable's +mobilizable, mobilisable +mobilizabler, mobilisabler +mobilizables, mobilisables +mobilizablest, mobilisablest +mobilization's, mobilisation's +mobilization, mobilisation +mobilizations, mobilisations +mobilize, mobilise +mobilized, mobilised +mobilizer's, mobiliser's +mobilizer, mobiliser +mobilizers, mobilisers +mobilizes, mobilises +mobilizing, mobilising +modalize, modalise +modalizes, modalises +modeled, modelled +modeler's, modeller's +modeler, modeller +modelers, modellers +modeling's, modelling's +modeling, modelling +modelings, modellings +modernizable's, modernisable's +modernizable, modernisable +modernizables, modernisables +modernization's, modernisation's +modernization, modernisation +modernizations, modernisations +modernize, modernise +modernized, modernised +modernizer's, moderniser's +modernizer, moderniser +modernizers, modernisers +modernizes, modernises +modernizing, modernising +modularization, modularisation +modularize, modularise +modularized, modularised +modularizes, modularises +modularizing, modularising +moggy's, moggie's +moggy, moggie +Mohammedanization's, Mohammedanisation's +Mohammedanization, Mohammedanisation +Mohammedanizations, Mohammedanisations +Mohammedanize's, Mohammedanise's +Mohammedanize, Mohammedanise +Mohammedanized's, Mohammedanised's +Mohammedanized, Mohammedanised +Mohammedanizes, Mohammedanises +Mohammedanizing's, Mohammedanising's +Mohammedanizing, Mohammedanising +moisturization, moisturisation +moisturize, moisturise +moisturized, moisturised +moisturizer's, moisturiser's +moisturizer, moisturiser +moisturizers, moisturisers +moisturizes, moisturises +moisturizing, moisturising +molarization, molarisation +molarizations, molarisations +mold's, mould's +mold, mould +molded, moulded +molder's, moulder's +molder, moulder +moldered, mouldered +moldering, mouldering +molders, moulders +moldier, mouldier +moldiest, mouldiest +molding's, moulding's +molding, moulding +moldings, mouldings +molds, moulds +moldy, mouldy +molluscan, molluskan +mollusk's, mollusc's +mollusk, mollusc +mollusks, molluscs +Molochize's, Molochise's +Molochize, Molochise +molochize, molochise +molochized, molochised +Molochizes, Molochises +molochizes, molochises +molochizing, molochising +molt's, moult's +molt, moult +molted, moulted +molting, moulting +molts, moults +mommy's, mommie's +mommy, mommie +monarchize, monarchise +monarchized, monarchised +monarchizer, monarchiser +monarchizers, monarchisers +monarchizes, monarchises +monarchizing, monarchising +monasticize, monasticise +monasticizes, monasticises +monecian, monoecian +monestrous, monoestrous +monetization's, monetisation's +monetization, monetisation +monetizations, monetisations +monetize, monetise +monetized, monetised +monetizes, monetises +monetizing, monetising +moneyed, monied +Mongolize's, Mongolise's +Mongolize, Mongolise +Mongolized's, Mongolised's +Mongolized, Mongolised +Mongolizes, Mongolises +Mongolizing's, Mongolising's +Mongolizing, Mongolising +mongrelization's, mongrelisation's +mongrelization, mongrelisation +mongrelizations, mongrelisations +mongrelize, mongrelise +mongrelized, mongrelised +mongrelizer, mongreliser +mongrelizes, mongrelises +mongrelizing, mongrelising +moniker's, monicker's +moniker, monicker +monikers, monickers +monochordize, monochordise +monochordizes, monochordises +monoecious, monecious +monologist's, monologuist's +monologist, monologuist +monologists, monologuists +monologize, monologise +monologized, monologised +monologizes, monologises +monologizing, monologising +monologue's, monolog's +monologue, monolog +monologues, monologs +monologuize, monologuise +monologuized, monologuised +monologuizes, monologuises +monologuizing, monologuising +monometalism, monometallism +monometalist, monometallist +monophthongize, monophthongise +monophthongized, monophthongised +monophthongizes, monophthongises +monophthongizing, monophthongising +monopolizable's, monopolisable's +monopolizable, monopolisable +monopolizables, monopolisables +monopolization's, monopolisation's +monopolization, monopolisation +monopolizations, monopolisations +monopolize, monopolise +monopolized, monopolised +monopolizer's, monopoliser's +monopolizer, monopoliser +monopolizers, monopolisers +monopolizes, monopolises +monopolizing, monopolising +monotonize, monotonise +monotonizes, monotonises +monumentalization's, monumentalisation's +monumentalization, monumentalisation +monumentalizations, monumentalisations +monumentalize, monumentalise +monumentalized, monumentalised +monumentalizes, monumentalises +monumentalizing, monumentalising +moralization's, moralisation's +moralization, moralisation +moralizations, moralisations +moralize, moralise +moralized, moralised +moralizer's, moraliser's +moralizer, moraliser +moralizers, moralisers +moralizes, moralises +moralizing, moralising +moralizinglies, moralisinglies +moralizingly, moralisingly +Moravianized's, Moravianised's +Moravianized, Moravianised +Moravianizeds, Moravianiseds +morbidize, morbidise +morbidizes, morbidises +Morea's, Moraea's +Morea, Moraea +morne, mourne +morningly, mourningly +morphinization's, morphinisation's +morphinization, morphinisation +morphinizations, morphinisations +morphinize, morphinise +morphinizes, morphinises +morseled, morselled +morseling, morselling +morselization's, morselisation's +morselization, morselisation +morselizations, morselisations +morselize, morselise +morselizes, morselises +mortalize, mortalise +mortalized, mortalised +mortalizes, mortalises +mortalizing, mortalising +mortarize, mortarise +mortarizes, mortarises +mortgagor's, mortgager's +mortgagor, mortgager +mortgagors, mortgagers +mortise's, mortice's +mortise, mortice +mortised, morticed +mortises, mortices +mortising, morticing +morule, morulae +Moslemize's, Moslemise's +Moslemize, Moslemise +Moslemizes, Moslemises +motorization's, motorisation's +motorization, motorisation +motorizations, motorisations +motorize, motorise +motorized, motorised +motorizes, motorises +motorizing, motorising +mousy, mousey +movability, moveability +movable's, moveable's +movable, moveable +movableness, moveableness +movablenesses, moveablenesses +movables, moveables +movably, moveably +mucorrhea, mucorrhoea +mucose, mucosae +mujahedin's, mujahedeen's +mujahedin, mujahedeen +multicolor's, multicolour's +multicolor, multicolour +multicolored, multicoloured +multicoloredder, multicolouredder +multicoloreddest, multicoloureddest +multicolorous, multicolourous +multicolors, multicolours +multifibered's, multifibred's +multifibered, multifibred +multifibereds, multifibreds +multileveled, multilevelled +multiplexer's, multiplexor's +multiplexer, multiplexor +multiplexers, multiplexors +municipalization's, municipalisation's +municipalization, municipalisation +municipalizations, municipalisations +municipalize, municipalise +municipalized, municipalised +municipalizer, municipaliser +municipalizers, municipalisers +municipalizes, municipalises +municipalizing, municipalising +murena, muraena +murenas, muraenas +muscularize, muscularise +muscularizes, muscularises +museumize, museumise +museumizes, museumises +musicalization's, musicalisation's +musicalization, musicalisation +musicalizations, musicalisations +musicalize, musicalise +musicalized, musicalised +musicalizes, musicalises +musicalizing, musicalising +Muslim's, Moslem's +Muslim, Moslem +mustache's, moustache's +mustache, moustache +mustached, moustached +mustaches, moustaches +mustachio's, moustachio's +mustachio, moustachio +mustachioed, moustachioed +mutagenize, mutagenise +mutagenized, mutagenised +mutagenizes, mutagenises +mutagenizing, mutagenising +mutualization's, mutualisation's +mutualization, mutualisation +mutualizations, mutualisations +mutualize, mutualise +mutualized, mutualised +mutualizes, mutualises +mutualizing, mutualising +mycohemia, mycohaemia +myelinization's, myelinisation's +myelinization, myelinisation +myelinizations, myelinisations +myelocele, myelocoele +myelocythemia, myelocythaemia +mylonitization, mylonitisation +mylonitizations, mylonitisations +mylonitize, mylonitise +mylonitized, mylonitised +mylonitizes, mylonitises +mylonitizing, mylonitising +myna's, mynah's +myna, mynah +mynas, mynahes +myocele, myocoele +myohematin, myohaematin +myrialiter, myrialitre +myriameter, myriametre +mysticize, mysticise +mysticizes, mysticises +mythicization, mythicisation +mythicize, mythicise +mythicized, mythicised +mythicizer's, mythiciser's +mythicizer, mythiciser +mythicizers, mythicisers +mythicizes, mythicises +mythicizing, mythicising +mythize, mythise +mythized, mythised +mythizes, mythises +mythizing, mythising +mythologization's, mythologisation's +mythologization, mythologisation +mythologizations, mythologisations +mythologize, mythologise +mythologized, mythologised +mythologizer's, mythologiser's +mythologizer, mythologiser +mythologizers, mythologisers +mythologizes, mythologises +mythologizing, mythologising +mythopeic, mythopoeic +mythopeist, mythopoeist +mythopoetize, mythopoetise +mythopoetized, mythopoetised +mythopoetizing, mythopoetising +myxameba, myxamoeba +myxedema's, myxoedema's +myxedema, myxoedema +myxedemas, myxoedemas +myxedematous, myxoedematous +myxedemic, myxoedemic +myxemia, myxaemia +naan's, nan's +naan, nan +naans, nans +Nabateans, Nabataeans +Nabathean's, Nabathaean's +Nabathean, Nabathaean +nakedize, nakedise +nakedizes, nakedises +nanization, nanisation +nanizations, nanisations +nanogram, nanogramme +nanograms, nanogrammes +nanometer's, nanometre's +nanometer, nanometre +nanometers, nanometres +napea, napaea +naphthalize, naphthalise +naphthalized, naphthalised +naphthalizes, naphthalises +naphthalizing, naphthalising +Napoleonize's, Napoleonise's +Napoleonize, Napoleonise +Napoleonizes, Napoleonises +narc's, nark's +narc, nark +narcotization's, narcotisation's +narcotization, narcotisation +narcotizations, narcotisations +narcotize, narcotise +narcotized, narcotised +narcotizes, narcotises +narcotizing, narcotising +narcs, narks +nasalization's, nasalisation's +nasalization, nasalisation +nasalizations, nasalisations +nasalize, nasalise +nasalized, nasalised +nasalizes, nasalises +nasalizing, nasalising +nationalization's, nationalisation's +nationalization, nationalisation +nationalizations, nationalisations +nationalize, nationalise +nationalized, nationalised +nationalizer's, nationaliser's +nationalizer, nationaliser +nationalizers, nationalisers +nationalizes, nationalises +nationalizing, nationalising +naturalization's, naturalisation's +naturalization, naturalisation +naturalizations, naturalisations +naturalize, naturalise +naturalized, naturalised +naturalizer's, naturaliser's +naturalizer, naturaliser +naturalizers, naturalisers +naturalizes, naturalises +naturalizing, naturalising +naturize, naturise +naturizes, naturises +nebularization's, nebularisation's +nebularization, nebularisation +nebularizations, nebularisations +nebularize, nebularise +nebularizes, nebularises +nebulization's, nebulisation's +nebulization, nebulisation +nebulizations, nebulisations +nebulize, nebulise +nebulized, nebulised +nebulizer's, nebuliser's +nebulizer, nebuliser +nebulizers, nebulisers +nebulizes, nebulises +nebulizing, nebulising +necremia, necraemia +necrotize, necrotise +necrotized, necrotised +necrotizes, necrotises +necrotizing, necrotising +nectarize, nectarise +nectarized, nectarised +nectarizes, nectarises +nectarizing, nectarising +neebor, neebour +neencephalon, neoencephalon +neer, nere +negligee's, neglig's +negligee, neglig +negligees, negligs +Negritize's, Negritise's +Negritize, Negritise +Negritized's, Negritised's +Negritized, Negritised +Negritizing's, Negritising's +Negritizing, Negritising +Negroization's, Negroisation's +Negroization, Negroisation +Negroizations, Negroisations +Negroize's, Negroise's +Negroize, Negroise +Negroized's, Negroised's +Negroized, Negroised +Negroizes, Negroises +Negroizing's, Negroising's +Negroizing, Negroising +neighbor's, neighbour's +neighbor, neighbour +neighbored, neighboured +neighborer's, neighbourer's +neighborer, neighbourer +neighborers, neighbourers +neighboress, neighbouress +neighborhood's, neighbourhood's +neighborhood, neighbourhood +neighborhoods, neighbourhoods +neighboring, neighbouring +neighborings, neighbourings +neighborless, neighbourless +neighborlesser, neighbourlesser +neighborlesses, neighbourlesses +neighborlessest, neighbourlessest +neighborlier, neighbourlier +neighborliest, neighbourliest +neighborlike's, neighbourlike's +neighborlike, neighbourlike +neighborlikes, neighbourlikes +neighborliness's, neighbourliness's +neighborliness, neighbourliness +neighborlinesses, neighbourlinesses +neighborly, neighbourly +neighbors, neighbours +neighborship's, neighbourship's +neighborship, neighbourship +neighborships, neighbourships +Neogea's, Neogaea's +Neogea, Neogaea +Neogeal's, Neogaeal's +Neogeal, Neogaeal +Neogean, Neogaean +Neogeic's, Neogaeic's +Neogeic, Neogaeic +neologization, neologisation +neologize, neologise +neologized, neologised +neologizes, neologises +neologizing, neologising +neopaganize, neopaganise +neopaganized, neopaganised +neopaganizes, neopaganises +neopaganizing, neopaganising +neoterize, neoterise +neoterized, neoterised +neoterizes, neoterises +neoterizing, neoterising +nephrectomize, nephrectomise +nephrectomized, nephrectomised +nephrectomizing, nephrectomising +nephrocele, nephrocoele +nephrotomize, nephrotomise +nesslerize, nesslerise +nesslerized, nesslerised +nesslerizing, nesslerising +net's, nett's +net, nett +nets, netts +neurepithelium, neuroepithelium +neurocele, neurocoele +neurocelian, neurocoelian +neuronal, neuronic +neuroticize, neuroticise +neuroticizes, neuroticises +neutralization's, neutralisation's +neutralization, neutralisation +neutralizations, neutralisations +neutralize, neutralise +neutralized, neutralised +neutralizer's, neutraliser's +neutralizer, neutraliser +neutralizers, neutralisers +neutralizes, neutralises +neutralizing, neutralising +neves, naeves +nevoid, naevoid +Newmanize's, Newmanise's +Newmanize, Newmanise +Newmanized's, Newmanised's +Newmanized, Newmanised +Newmanizes, Newmanises +Newmanizing's, Newmanising's +Newmanizing, Newmanising +newspaperized's, newspaperised's +newspaperized, newspaperised +newspaperizeds, newspaperiseds +nickeled, nickelled +nickeling, nickelling +nickelization's, nickelisation's +nickelization, nickelisation +nickelizations, nickelisations +nickelize, nickelise +nickelized, nickelised +nickelizes, nickelises +nickelizing, nickelising +nicotinize, nicotinise +nicotinized, nicotinised +nicotinizes, nicotinises +nicotinizing, nicotinising +nielled, nielloed +niger, nigre +niggardize, niggardise +niggardized, niggardised +niggardizes, niggardises +niggardizing, niggardising +night's, nite's +night, nite +nightie's, nighty's +nightie, nighty +nightingalize, nightingalise +nightingalizes, nightingalises +nights, nites +Nipponize's, Nipponise's +Nipponize, Nipponise +Nipponizes, Nipponises +niter's, nitre's +niter, nitre +niters, nitres +nitridization's, nitridisation's +nitridization, nitridisation +nitridizations, nitridisations +nitridize, nitridise +nitridizes, nitridises +nitrogenization's, nitrogenisation's +nitrogenization, nitrogenisation +nitrogenizations, nitrogenisations +nitrogenize, nitrogenise +nitrogenized, nitrogenised +nitrogenizes, nitrogenises +nitrogenizing, nitrogenising +nitroglycerin's, nitroglycerine's +nitroglycerin, nitroglycerine +nitroglycerins, nitroglycerines +nodalize, nodalise +nodalized, nodalised +nodalizes, nodalises +nodalizing, nodalising +nodulize, nodulise +nodulizes, nodulises +Noemon's, Noaemon's +Noemon, Noaemon +nomadization's, nomadisation's +nomadization, nomadisation +nomadizations, nomadisations +nomadize, nomadise +nomadized, nomadised +nomadizes, nomadises +nomadizing, nomadising +nominalization, nominalisation +nominalizations, nominalisations +nominalize, nominalise +nominalized, nominalised +nominalizes, nominalises +nominalizing, nominalising +nonacknowledgment's, nonacknowledgement's +nonacknowledgment, nonacknowledgement +nonacknowledgments, nonacknowledgements +nonanaesthetised, nonanaesthetized +nonanemic, nonanaemic +nonapostatizing's, nonapostatising's +nonapostatizing, nonapostatising +nonapostatizings, nonapostatisings +noncanonization's, noncanonisation's +noncanonization, noncanonisation +noncanonizations, noncanonisations +noncartelized's, noncartelised's +noncartelized, noncartelised +noncartelizeds, noncarteliseds +noncatechizable's, noncatechisable's +noncatechizable, noncatechisable +noncatechizables, noncatechisables +noncivilized's, noncivilised's +noncivilized, noncivilised +noncivilizeds, nonciviliseds +noncolor's, noncolour's +noncolor, noncolour +noncolorabilities, noncolourabilities +noncolorability's, noncolourability's +noncolorability, noncolourability +noncolorable's, noncolourable's +noncolorable, noncolourable +noncolorableness's, noncolourableness's +noncolorableness, noncolourableness +noncolorables, noncolourables +noncolorablies, noncolourablies +noncolorably, noncolourably +noncolored, noncoloured +noncolorer, noncolourer +noncolorers, noncolourers +noncolorfast, noncolourfast +noncoloring, noncolouring +noncolorings, noncolourings +noncolors, noncolours +noncrystallizable's, noncrystallisable's +noncrystallizable, noncrystallisable +noncrystallizables, noncrystallisables +noncrystallized's, noncrystallised's +noncrystallized, noncrystallised +noncrystallizeds, noncrystalliseds +noncrystallizing's, noncrystallising's +noncrystallizing, noncrystallising +noncrystallizings, noncrystallisings +nondemobilization's, nondemobilisation's +nondemobilization, nondemobilisation +nondemobilizations, nondemobilisations +nondialyzing's, nondialysing's +nondialyzing, nondialysing +nondialyzings, nondialysings +nondimensionalize, nondimensionalise +nondimensionalized, nondimensionalised +nonecumenic, nonoecumenic +nonecumenical, nonoecumenical +nonencyclopedic, nonencyclopaedic +nonesthetic, nonaesthetic +nonesthetical, nonaesthetical +nonesthetically, nonaesthetically +nonfavorite's, nonfavourite's +nonfavorite, nonfavourite +nonfavorites, nonfavourites +nonflavored, nonflavoured +nonfulfillment's, nonfulfilment's +nonfulfillment, nonfulfilment +nonfulfillments, nonfulfilments +nongalvanized's, nongalvanised's +nongalvanized, nongalvanised +nongalvanizeds, nongalvaniseds +nongelatinizing's, nongelatinising's +nongelatinizing, nongelatinising +nongelatinizings, nongelatinisings +nonhydrolyzable's, nonhydrolysable's +nonhydrolyzable, nonhydrolysable +nonhydrolyzables, nonhydrolysables +nonimmunized's, nonimmunised's +nonimmunized, nonimmunised +nonimmunizeds, nonimmuniseds +nonionized's, nonionised's +nonionized, nonionised +nonionizeds, nonioniseds +nonionizing's, nonionising's +nonionizing, nonionising +nonionizings, nonionisings +nonlocalized's, nonlocalised's +nonlocalized, nonlocalised +nonlocalizeds, nonlocaliseds +nonmagnetizable's, nonmagnetisable's +nonmagnetizable, nonmagnetisable +nonmagnetizables, nonmagnetisables +nonnitrogenized's, nonnitrogenised's +nonnitrogenized, nonnitrogenised +nonnitrogenizeds, nonnitrogeniseds +nonorganization's, nonorganisation's +nonorganization, nonorganisation +nonorganizations, nonorganisations +nonoxidizable's, nonoxidisable's +nonoxidizable, nonoxidisable +nonoxidizables, nonoxidisables +nonoxidizing's, nonoxidising's +nonoxidizing, nonoxidising +nonoxidizings, nonoxidisings +nonparlor's, nonparlour's +nonparlor, nonparlour +nonparlors, nonparlours +nonpenalized's, nonpenalised's +nonpenalized, nonpenalised +nonpenalizeds, nonpenaliseds +nonphosphorized's, nonphosphorised's +nonphosphorized, nonphosphorised +nonphosphorizeds, nonphosphoriseds +nonpolarizable's, nonpolarisable's +nonpolarizable, nonpolarisable +nonpolarizables, nonpolarisables +nonpolarized, nonpolarised +nonpolarizing's, nonpolarising's +nonpolarizing, nonpolarising +nonpolarizings, nonpolarisings +nonrationalized's, nonrationalised's +nonrationalized, nonrationalised +nonrationalizeds, nonrationaliseds +nonrealization's, nonrealisation's +nonrealization, nonrealisation +nonrealizations, nonrealisations +nonrecognized's, nonrecognised's +nonrecognized, nonrecognised +nonrecognizeds, nonrecogniseds +nonschematized's, nonschematised's +nonschematized, nonschematised +nonschematizeds, nonschematiseds +nonsensitized's, nonsensitised's +nonsensitized, nonsensitised +nonsensitizeds, nonsensitiseds +nonspecialized's, nonspecialised's +nonspecialized, nonspecialised +nonspecializeds, nonspecialiseds +nonstandardized's, nonstandardised's +nonstandardized, nonstandardised +nonstandardizeds, nonstandardiseds +nonstylized's, nonstylised's +nonstylized, nonstylised +nonstylizeds, nonstyliseds +nonsuccor, nonsuccour +nonsympathizer's, nonsympathiser's +nonsympathizer, nonsympathiser +nonsympathizers, nonsympathisers +nonsynthesized's, nonsynthesised's +nonsynthesized, nonsynthesised +nonsynthesizeds, nonsynthesiseds +nontemporizing's, nontemporising's +nontemporizing, nontemporising +nontemporizings, nontemporisings +nonutilized's, nonutilised's +nonutilized, nonutilised +nonutilizeds, nonutiliseds +nonvisualized's, nonvisualised's +nonvisualized, nonvisualised +nonvisualizeds, nonvisualiseds +nonvolatilized's, nonvolatilised's +nonvolatilized, nonvolatilised +nonvolatilizeds, nonvolatiliseds +nonvulcanizable's, nonvulcanisable's +nonvulcanizable, nonvulcanisable +nonvulcanizables, nonvulcanisables +norice, nourice +normalizable, normalisable +normalization's, normalisation's +normalization, normalisation +normalizations, normalisations +normalize, normalise +normalized, normalised +normalizer's, normaliser's +normalizer, normaliser +normalizers, normalisers +normalizes, normalises +normalizing, normalising +Normanization's, Normanisation's +Normanization, Normanisation +Normanizations, Normanisations +Normanize, Normanise +normanize, normanise +Normanized, Normanised +normanized, normanised +Normanizer's, Normaniser's +Normanizer, Normaniser +Normanizers, Normanisers +Normanizes, Normanises +normanizes, normanises +Normanizing, Normanising +normanizing, normanising +Northernize's, Northernise's +Northernize, Northernise +northernize, northernise +northernized, northernised +northernizes, northernises +northernizing, northernising +nosies, noseys +nosize, nosise +nosohemia, nosohaemia +nosy's, nosey's +nosy, nosey +notarization, notarisation +notarizations, notarisations +notarize, notarise +notarized, notarised +notarizes, notarises +notarizing, notarising +noter, notre +nothingize, nothingise +nothingizes, nothingises +Notogea's, Notogaea's +Notogea, Notogaea +nounize, nounise +nounizes, nounises +novelization's, novelisation's +novelization, novelisation +novelizations, novelisations +novelize, novelise +novelized, novelised +novelizer's, noveliser's +novelizer, noveliser +novelizers, novelisers +novelizes, novelises +novelizing, novelising +novene, novenae +nuclearization, nuclearisation +nuclearizations, nuclearisations +nuclearize, nuclearise +nuclearized, nuclearised +nuclearizes, nuclearises +nuclearizing, nuclearising +numskull's, numbskull's +numskull, numbskull +numskulls, numbskulls +nuptialize, nuptialise +nuptializes, nuptialises +nympheum, nymphaeum +Obe's, Oboe's +Obe, Oboe +obelize, obelise +obelized, obelised +obelizes, obelises +obelizing, obelising +objectivize, objectivise +objectivized, objectivised +objectivizes, objectivises +objectivizing, objectivising +objectization's, objectisation's +objectization, objectisation +objectizations, objectisations +objectize, objectise +objectizes, objectises +oblivionize, oblivionise +oblivionizes, oblivionises +Occidentalization's, Occidentalisation's +Occidentalization, Occidentalisation +Occidentalizations, Occidentalisations +Occidentalize, Occidentalise +occidentalize, occidentalise +Occidentalized, Occidentalised +occidentalized, occidentalised +Occidentalizes, Occidentalises +occidentalizes, occidentalises +Occidentalizing, Occidentalising +occidentalizing, occidentalising +ocher's, ochre's +ocher, ochre +ochered, ochred +ochering, ochring +ocherish, ochreish +ocherous, ochreous +ocherouser, ochreouser +ocherousest, ochreousest +ocherrer, ochrer +ocherrest, ochrest +ochers, ochres +ochery, ochrey +octet's, octette's +octet, octette +octets, octettes +Ocyrrhoe's, Ocyrrhoae's +Ocyrrhoe, Ocyrrhoae +odor's, odour's +odor, odour +odored, odoured +odorful, odourful +odorfuller, odourfuller +odorfullest, odourfullest +odorize, odorise +odorized, odorised +odorizer, odoriser +odorizes, odorises +odorizing, odorising +odorless, odourless +odorlesser, odourlesser +odorlesses, odourlesses +odorlessest, odourlessest +odors, odours +oesophagi, oesophaguses +offense's, offence's +offense, offence +offenseless, offenceless +offenselesser, offencelesser +offenselesses, offencelesses +offenselessest, offencelessest +offenselessly, offencelessly +offenses, offences +officialization's, officialisation's +officialization, officialisation +officializations, officialisations +officialize, officialise +officializes, officialises +OK's, okay's +OK, okay +OKed, okayed +OKing, okaying +OKs, okays +oleomargarine's, oleomargarin's +oleomargarine, oleomargarin +oleomargarines, oleomargarins +oligemia, oligaemia +oligocythemia, oligocythaemia +olpe, olpae +Olympianize's, Olympianise's +Olympianize, Olympianise +Olympianizes, Olympianises +omber's, ombre's +omber, ombre +ombers, ombres +omelet's, omelette's +omelet, omelette +omelets, omelettes +oneyer, oneyre +oneyers, oneyres +onionized's, onionised's +onionized, onionised +onionizeds, onioniseds +ontologize, ontologise +ooglea, oogloea +oophorectomize, oophorectomise +oophorectomized, oophorectomised +oophorectomizes, oophorectomises +oophorectomizing, oophorectomising +opaled, opalled +opalize, opalise +opalized, opalised +opalizes, opalises +operationalization, operationalisation +operationalizations, operationalisations +operationalize, operationalise +operationalized, operationalised +operatize, operatise +operatized, operatised +operatizes, operatises +operatizing, operatising +opiniaster, opiniastre +opiniater, opiniatre +optimalization, optimalisation +optimalizations, optimalisations +optimalize, optimalise +optimalized, optimalised +optimalizes, optimalises +optimalizing, optimalising +optimization's, optimisation's +optimization, optimisation +optimizations, optimisations +optimize, optimise +optimized, optimised +optimizer's, optimiser's +optimizer, optimiser +optimizers, optimisers +optimizes, optimises +optimizing, optimising +optionalize, optionalise +optionalizes, optionalises +oralization's, oralisation's +oralization, oralisation +oralizations, oralisations +oralize, oralise +oralizes, oralises +orang, ourang +orangize, orangise +orangizes, orangises +orangs, ourangs +orangutan's, orangutang's +orangutan, orangutang +orangutans, orangutangs +oratorize, oratorise +oratorizes, oratorises +orchester, orchestre +organdy's, organdie's +organdy, organdie +organizabilities, organisabilities +organizability's, organisability's +organizability, organisability +organizable's, organisable's +organizable, organisable +organizabler, organisabler +organizables, organisables +organizablest, organisablest +organization's, organisation's +organization, organisation +organizational's, organisational's +organizational, organisational +organizationaler, organisationaler +organizationalest, organisationalest +organizationallier, organisationallier +organizationalliest, organisationalliest +organizationally, organisationally +organizationals, organisationals +organizationist's, organisationist's +organizationist, organisationist +organizationists, organisationists +organizations, organisations +organize, organise +organized, organised +organizer's, organiser's +organizer, organiser +organizers, organisers +organizes, organises +organizing, organising +orientalization's, orientalisation's +orientalization, orientalisation +orientalizations, orientalisations +Orientalize, Orientalise +orientalize, orientalise +Orientalized, Orientalised +orientalized, orientalised +orientalizes, orientalises +Orientalizing, Orientalising +orientalizing, orientalising +orientization's, orientisation's +orientization, orientisation +orientizations, orientisations +orientize, orientise +orientizes, orientises +ornamentalize, ornamentalise +ornamentalizes, ornamentalises +orologies, ourologies +orology, ourology +orphanize, orphanise +orphanizes, orphanises +orsel, oursel +orthocenter's, orthocentre's +orthocenter, orthocentre +orthocenters, orthocentres +orthogonalization's, orthogonalisation's +orthogonalization, orthogonalisation +orthogonalize, orthogonalise +orthogonalized, orthogonalised +orthogonalizes, orthogonalises +orthogonalizing, orthogonalising +orthographize, orthographise +orthographized, orthographised +orthographizing, orthographising +orthopedia, orthopaedia +orthopedic's, orthopaedic's +orthopedic, orthopaedic +orthopedical, orthopaedical +orthopedicallier, orthopaedicallier +orthopedicalliest, orthopaedicalliest +orthopedically, orthopaedically +orthopedicer, orthopaedicer +orthopedicest, orthopaedicest +orthopedics's, orthopaedics's +orthopedics, orthopaedics +orthopedies, orthopaedies +orthopedist's, orthopaedist's +orthopedist, orthopaedist +orthopedists, orthopaedists +orthopedy, orthopaedy +orthopnea, orthopnoea +orthopneic, orthopnoeic +osteopedion, osteopaedion +ostracizable's, ostracisable's +ostracizable, ostracisable +ostracizables, ostracisables +ostracization's, ostracisation's +ostracization, ostracisation +ostracizations, ostracisations +ostracize, ostracise +ostracized, ostracised +ostracizer's, ostraciser's +ostracizer, ostraciser +ostracizers, ostracisers +ostracizes, ostracises +ostracizing, ostracising +othematoma, othaematoma +otorrhea, otorrhoea +Ottomanization's, Ottomanisation's +Ottomanization, Ottomanisation +Ottomanizations, Ottomanisations +Ottomanize's, Ottomanise's +Ottomanize, Ottomanise +Ottomanizes, Ottomanises +outcaviled, outcavilled +outcaviling, outcavilling +outclamor's, outclamour's +outclamor, outclamour +outclamors, outclamours +outerness, outreness +outhumor's, outhumour's +outhumor, outhumour +outhumored, outhumoured +outhumoring, outhumouring +outhumors, outhumours +outhyperbolize, outhyperbolise +outhyperbolizes, outhyperbolises +outlabor's, outlabour's +outlabor, outlabour +outlabors, outlabours +outluster, outlustre +outmaneuver, outmanoeuvre +outmaneuvered, outmanoeuvred +outmaneuvering, outmanoeuvring +outmaneuvers, outmanoeuvres +outrivaled, outrivalled +outrivaling, outrivalling +outsavor's, outsavour's +outsavor, outsavour +outsavoring, outsavouring +outsavors, outsavours +outsplendor's, outsplendour's +outsplendor, outsplendour +outsplendors, outsplendours +outtyrannize, outtyrannise +outtyrannizes, outtyrannises +ovalization's, ovalisation's +ovalization, ovalisation +ovalizations, ovalisations +ovalize, ovalise +ovalizes, ovalises +ovariectomized, ovariectomised +overagonize, overagonise +overagonizes, overagonises +overanalyze, overanalyse +overanalyzes, overanalyses +overbrutalize, overbrutalise +overbrutalizes, overbrutalises +overcapitalization's, overcapitalisation's +overcapitalization, overcapitalisation +overcapitalizations, overcapitalisations +overcapitalize, overcapitalise +overcapitalized, overcapitalised +overcapitalizes, overcapitalises +overcapitalizing, overcapitalising +overcentralization's, overcentralisation's +overcentralization, overcentralisation +overcentralizations, overcentralisations +overcentralize, overcentralise +overcentralizes, overcentralises +overcivilization's, overcivilisation's +overcivilization, overcivilisation +overcivilizations, overcivilisations +overcivilize, overcivilise +overcivilizes, overcivilises +overclamor's, overclamour's +overclamor, overclamour +overclamors, overclamours +overcolor's, overcolour's +overcolor, overcolour +overcoloration's, overcolouration's +overcoloration, overcolouration +overcoloring, overcolouring +overcolors, overcolours +overcriticize, overcriticise +overcriticizes, overcriticises +overdoctrinize, overdoctrinise +overdoctrinizes, overdoctrinises +overdramatize, overdramatise +overdramatized, overdramatised +overdramatizes, overdramatises +overdramatizing, overdramatising +overemotionalize, overemotionalise +overemotionalizes, overemotionalises +overemphasize, overemphasise +overemphasized, overemphasised +overemphasizer, overemphasiser +overemphasizers, overemphasisers +overemphasizes, overemphasises +overemphasizing, overemphasising +overfavor's, overfavour's +overfavor, overfavour +overfavorable's, overfavourable's +overfavorable, overfavourable +overfavorables, overfavourables +overfavorablies, overfavourablies +overfavorably, overfavourably +overfavors, overfavours +overfertilization, overfertilisation +overgeneralize, overgeneralise +overgeneralized, overgeneralised +overgeneralizes, overgeneralises +overgeneralizing, overgeneralising +overhonor's, overhonour's +overhonor, overhonour +overhonors, overhonours +overhumanize, overhumanise +overhumanizes, overhumanises +overindustrialization's, overindustrialisation's +overindustrialization, overindustrialisation +overindustrializations, overindustrialisations +overindustrialize, overindustrialise +overindustrializes, overindustrialises +overjudgment's, overjudgement's +overjudgment, overjudgement +overjudgments, overjudgements +overlabor's, overlabour's +overlabor, overlabour +overlabored, overlaboured +overlaboring, overlabouring +overlabors, overlabours +overnationalization's, overnationalisation's +overnationalization, overnationalisation +overnationalizations, overnationalisations +overrapturize, overrapturise +overrapturizes, overrapturises +overrationalize, overrationalise +overrationalizes, overrationalises +oversentimentalize, oversentimentalise +oversentimentalizes, oversentimentalises +oversize, oversized +overspecialization's, overspecialisation's +overspecialization, overspecialisation +overspecializations, overspecialisations +overspecialize, overspecialise +overspecialized, overspecialised +overspecializes, overspecialises +overspecializing, overspecialising +oversystematize, oversystematise +oversystematizes, oversystematises +overunionized's, overunionised's +overunionized, overunionised +overunionizeds, overunioniseds +overurbanization's, overurbanisation's +overurbanization, overurbanisation +overurbanizations, overurbanisations +overutilization, overutilisation +overwomanize, overwomanise +overwomanizes, overwomanises +ower, owre +owercome, owrecome +owerword, owreword +oxalemia, oxalaemia +oxidizabilities, oxidisabilities +oxidizability's, oxidisability's +oxidizability, oxidisability +oxidizable's, oxidisable's +oxidizable, oxidisable +oxidizables, oxidisables +oxidization's, oxidisation's +oxidization, oxidisation +oxidizations, oxidisations +oxidize, oxidise +oxidized, oxidised +oxidizement's, oxidisement's +oxidizement, oxidisement +oxidizements, oxidisements +oxidizer's, oxidiser's +oxidizer, oxidiser +oxidizers, oxidisers +oxidizes, oxidises +oxidizing, oxidising +oxidizings, oxidisings +oxygenizable's, oxygenisable's +oxygenizable, oxygenisable +oxygenizables, oxygenisables +oxygenize, oxygenise +oxygenized, oxygenised +oxygenizement's, oxygenisement's +oxygenizement, oxygenisement +oxygenizements, oxygenisements +oxygenizer's, oxygeniser's +oxygenizer, oxygeniser +oxygenizers, oxygenisers +oxygenizes, oxygenises +oxygenizing, oxygenising +oxyhematin, oxyhaematin +oxyhemoglobin, oxyhaemoglobin +oxyhemoglobins, oxyhaemoglobins +ozena, ozaena +ozena, ozoena +ozonization's, ozonisation's +ozonization, ozonisation +ozonizations, ozonisations +ozonize, ozonise +ozonized, ozonised +ozonizer's, ozoniser's +ozonizer, ozoniser +ozonizers, ozonisers +ozonizes, ozonises +ozonizing, ozonising +pachyemia, pachyaemia +pachyhemia, pachyhaemia +packetization, packetisation +packetize, packetise +packetized, packetised +packetizer's, packetiser's +packetizer, packetiser +packetizers, packetisers +packetizes, packetises +packetizing, packetising +paeanize, paeanise +paeanizes, paeanises +paganization's, paganisation's +paganization, paganisation +paganizations, paganisations +paganize, paganise +paganized, paganised +paganizer's, paganiser's +paganizer, paganiser +paganizers, paganisers +paganizes, paganises +paganizing, paganising +pagine, paginae +pajama's, pyjama's +pajama, pyjama +pajamaed, pyjamased +pajamas's, pyjamas's +pajamas, pyjamas +palame, palamae +palatalization's, palatalisation's +palatalization, palatalisation +palatalizations, palatalisations +palatalize, palatalise +palatalized, palatalised +palatalizes, palatalises +palatalizing, palatalising +palatization's, palatisation's +palatization, palatisation +palatizations, palatisations +palatize, palatise +palatizes, palatises +paleanthropic, palaeanthropic +Palearctic, Palaearctic +paleencephalon's, palaeencephalon's +paleencephalon, palaeencephalon +paleentomology, palaeentomology +paleethnologic, palaeethnologic +paleethnological, palaeethnological +paleethnologist, palaeethnologist +paleethnology, palaeethnology +paleichthyologist, palaeichthyologist +paleichthyology, palaeichthyology +paleoalchemical, palaeoalchemical +paleoanthropic, palaeoanthropic +paleoanthropography, palaeoanthropography +paleoanthropological, palaeoanthropological +paleoanthropologies, palaeoanthropologies +paleoanthropologist, palaeoanthropologist +paleoanthropologists, palaeoanthropologists +paleoanthropology, palaeoanthropology +Paleoanthropus's, Palaeoanthropus's +Paleoanthropus, Palaeoanthropus +paleoatavism, palaeoatavism +paleoatavistic, palaeoatavistic +paleobiogeography, palaeobiogeography +paleobiologic, palaeobiologic +paleobiological, palaeobiological +paleobiologies, palaeobiologies +paleobiologist's, palaeobiologist's +paleobiologist, palaeobiologist +paleobiologists, palaeobiologists +paleobiology's, palaeobiology's +paleobiology, palaeobiology +paleobotanic, palaeobotanic +paleobotanical, palaeobotanical +paleobotanically, palaeobotanically +paleobotanies, palaeobotanies +paleobotanist, palaeobotanist +paleobotanists, palaeobotanists +paleobotany's, palaeobotany's +paleobotany, palaeobotany +paleoceanography, palaeoceanography +paleochorology, palaeochorology +paleoclimatic, palaeoclimatic +paleoclimatologic, palaeoclimatologic +paleoclimatological, palaeoclimatological +paleoclimatologies, palaeoclimatologies +paleoclimatologist's, palaeoclimatologist's +paleoclimatologist, palaeoclimatologist +paleoclimatologists, palaeoclimatologists +paleoclimatology's, palaeoclimatology's +paleoclimatology, palaeoclimatology +Paleoconcha's, Palaeoconcha's +Paleoconcha, Palaeoconcha +paleocosmic, palaeocosmic +paleocosmology, palaeocosmology +paleocrystal, palaeocrystal +paleocrystallic, palaeocrystallic +paleocrystalline, palaeocrystalline +paleocrystic, palaeocrystic +paleocyclic, palaeocyclic +paleodendrologic, palaeodendrologic +paleodendrological, palaeodendrological +paleodendrologically, palaeodendrologically +paleodendrologist, palaeodendrologist +paleodendrology, palaeodendrology +paleoecologic, palaeoecologic +paleoecological, palaeoecological +paleoecologies, palaeoecologies +paleoecologist's, palaeoecologist's +paleoecologist, palaeoecologist +paleoecologists, palaeoecologists +paleoecology's, palaeoecology's +paleoecology, palaeoecology +paleoencephalon's, palaeoencephalon's +paleoencephalon, palaeoencephalon +paleoentomologic, palaeoentomologic +paleoentomological, palaeoentomological +paleoentomologist's, palaeoentomologist's +paleoentomologist, palaeoentomologist +paleoeremology, palaeoeremology +paleoethnic, palaeoethnic +paleoethnography, palaeoethnography +paleoethnologic, palaeoethnologic +paleoethnological, palaeoethnological +paleoethnologist, palaeoethnologist +paleoethnology, palaeoethnology +paleofauna, palaeofauna +paleogenesis's, palaeogenesis's +paleogenesis, palaeogenesis +paleogenetic, palaeogenetic +paleogeographer, palaeogeographer +paleogeographers, palaeogeographers +paleogeographic, palaeogeographic +paleogeographical, palaeogeographical +paleogeographically, palaeogeographically +paleogeographies, palaeogeographies +paleogeography, palaeogeography +paleogeology, palaeogeology +paleoglaciology, palaeoglaciology +paleoglyph, palaeoglyph +paleograph, palaeograph +paleographic, palaeographic +paleographical, palaeographical +paleographically, palaeographically +paleographist, palaeographist +paleoherpetologist, palaeoherpetologist +paleoherpetology, palaeoherpetology +paleohistology, palaeohistology +paleohydrography, palaeohydrography +paleoichthyology, palaeoichthyology +paleolatry, palaeolatry +paleolimnology, palaeolimnology +paleolith's, palaeolith's +paleolith, palaeolith +paleolithic, palaeolithic +Paleolithic, Palaeolithic +paleolithical, palaeolithical +paleolithist, palaeolithist +paleolithoid, palaeolithoid +paleoliths, palaeoliths +paleolithy, palaeolithy +paleological, palaeological +paleologist's, palaeologist's +paleologist, palaeologist +paleology, palaeology +paleomagnetism's, palaeomagnetism's +paleomagnetism, palaeomagnetism +paleomagnetisms, palaeomagnetisms +paleometallic, palaeometallic +paleometeorological, palaeometeorological +paleometeorology, palaeometeorology +paleontographic, palaeontographic +paleontographical, palaeontographical +paleontographies, palaeontographies +paleontography's, palaeontography's +paleontography, palaeontography +paleontol, palaeontol +paleontologic, palaeontologic +paleontological, palaeontological +paleontologically, palaeontologically +paleontologist's, palaeontologist's +paleontologist, palaeontologist +paleontologists, palaeontologists +paleontology's, palaeontology's +paleontology, palaeontology +paleopathologic, palaeopathologic +paleopathological, palaeopathological +paleopathologies, palaeopathologies +paleopathologist, palaeopathologist +paleopathologists, palaeopathologists +paleopathology, palaeopathology +paleopedology, palaeopedology +paleophysiography, palaeophysiography +paleophysiology, palaeophysiology +paleophytic, palaeophytic +paleophytological, palaeophytological +paleophytologist, palaeophytologist +paleophytology, palaeophytology +paleoplain, palaeoplain +paleopotamology, palaeopotamology +paleopsychic, palaeopsychic +paleopsychological, palaeopsychological +paleopsychology, palaeopsychology +paleornithological, palaeornithological +paleornithology, palaeornithology +paleostriatal, palaeostriatal +paleostriatum, palaeostriatum +paleostylic, palaeostylic +paleostyly, palaeostyly +paleotechnic, palaeotechnic +paleothalamus, palaeothalamus +Paleotropical's, Palaeotropical's +Paleotropical, Palaeotropical +paleovolcanic, palaeovolcanic +paleozoic, palaeozoic +paleozoologic, palaeozoologic +paleozoological, palaeozoological +paleozoologies, palaeozoologies +paleozoologist's, palaeozoologist's +paleozoologist, palaeozoologist +paleozoologists, palaeozoologists +paleozoology's, palaeozoology's +paleozoology, palaeozoology +palestra's, palaestra's +palestra, palaestra +palestrae, palaestrae +palestral, palaestral +palestras, palaestras +palestrian, palaestrian +palestric, palaestric +paletiology, palaetiology +palladiumize, palladiumise +palladiumizes, palladiumises +palletization's, palletisation's +palletization, palletisation +palletizations, palletisations +palletize, palletise +palletized, palletised +palletizer's, palletiser's +palletizer, palletiser +palletizers, palletisers +palletizes, palletises +palletizing, palletising +pamperize, pamperise +pamperizes, pamperises +pamphletize, pamphletise +pamphletizes, pamphletises +panderize, panderise +panderizes, panderises +pandora, pandoura +panegyrize, panegyrise +panegyrized, panegyrised +panegyrizes, panegyrises +panegyrizing, panegyrising +paneled, panelled +paneling's, panelling's +paneling, panelling +panelings, panellings +panelist's, panellist's +panelist, panellist +panelists, panellists +panelized, panelised +panellisation, panellization +panesthesia, panaesthesia +panesthesias, panaesthesias +panesthetic, panaesthetic +pangea, pangaea +pannier's, panier's +pannier, panier +panniers, paniers +panomphean, panomphaean +pantheonization's, pantheonisation's +pantheonization, pantheonisation +pantheonizations, pantheonisations +pantheonize, pantheonise +pantheonizes, pantheonises +pantie's, panty's +pantie, panty +papalization's, papalisation's +papalization, papalisation +papalizations, papalisations +papalize, papalise +papalized, papalised +papalizer, papaliser +papalizers, papalisers +papalizes, papalises +papalizing, papalising +papilledema, papilloedema +papule, papulae +parabolization's, parabolisation's +parabolization, parabolisation +parabolize, parabolise +parabolized, parabolised +parabolizes, parabolises +parabolizing, parabolising +paraffinize, paraffinise +paraffinizes, paraffinises +paragraphize, paragraphise +paragraphizes, paragraphises +parakeet's, parrakeet's +parakeet, parrakeet +parakeets, parrakeets +parallelization's, parallelisation's +parallelization, parallelisation +parallelizations, parallelisations +parallelize, parallelise +parallelized, parallelised +parallelizer, paralleliser +parallelizers, parallelisers +parallelizes, parallelises +parallelizing, parallelising +paralogize, paralogise +paralogized, paralogised +paralogizes, paralogises +paralogizing, paralogising +paralyzation's, paralysation's +paralyzation, paralysation +paralyzations, paralysations +paralyze, paralyse +paralyzed, paralysed +paralyzedlies, paralysedlies +paralyzedly, paralysedly +paralyzer's, paralyser's +paralyzer, paralyser +paralyzers, paralysers +paralyzes, paralyses +paralyzing, paralysing +paralyzinglies, paralysinglies +paralyzingly, paralysingly +Paramecium's, Paramoecium's +Paramecium, Paramoecium +parameterizable, parameterisable +parameterization's, parameterisation's +parameterization, parameterisation +parameterizations, parameterisations +parameterize, parameterise +parameterized, parameterised +parameterizes, parameterises +parameterizing, parameterising +parametrizable, parametrisable +parametrization's, parametrisation's +parametrization, parametrisation +parametrizations, parametrisations +parametrize, parametrise +parametrized, parametrised +parametrizes, parametrises +parametrizing, parametrising +paraselene, paraselenae +parasitemia, parasitaemia +parasitization, parasitisation +parasitize, parasitise +parasitized, parasitised +parasitizes, parasitises +parasitizing, parasitising +parathyroidectomize, parathyroidectomise +parathyroidectomized, parathyroidectomised +parathyroidectomizes, parathyroidectomises +parathyroidectomizing, parathyroidectomising +paratragedia, paratragoedia +parceled, parcelled +parceler, parceller +parceling's, parcelling's +parceling, parcelling +parchmentize, parchmentise +parchmentized, parchmentised +parchmentizes, parchmentises +parchmentizing, parchmentising +parecious, paroecious +pareciously, paroeciously +pareciousness, paroeciousness +parecism, paroecism +parecy, paroecy +pareneses, paraeneses +parenesis, paraenesis +parenetic, paraenetic +parenetical, paraenetical +parenthesization, parenthesisation +parenthesize, parenthesise +parenthesized, parenthesised +parenthesizes, parenthesises +parenthesizing, parenthesising +paresthesia's, paraesthesia's +paresthesia, paraesthesia +paresthesias, paraesthesias +paresthetic, paraesthetic +parfocalization, parfocalisation +parfocalize, parfocalise +Parisianization's, Parisianisation's +Parisianization, Parisianisation +Parisianizations, Parisianisations +Parisianize's, Parisianise's +Parisianize, Parisianise +Parisianizes, Parisianises +parlor's, parlour's +parlor, parlour +parlorish, parlourish +parlormaid, parlourmaid +parlors, parlours +parmigiana, parmigiano +parochialization's, parochialisation's +parochialization, parochialisation +parochializations, parochialisations +parochialize, parochialise +parochialized, parochialised +parochializes, parochialises +parochializing, parochialising +parrotize, parrotise +parrotizes, parrotises +parsonize, parsonise +parsonizes, parsonises +partialize, partialise +partialized, partialised +partializes, partialises +partializing, partialising +particolored, particoloured +particoloredder, particolouredder +particoloreddest, particoloureddest +particularization's, particularisation's +particularization, particularisation +particularizations, particularisations +particularize, particularise +particularized, particularised +particularizer's, particulariser's +particularizer, particulariser +particularizes, particularises +particularizing, particularising +partisan's, partizan's +partisan's, partizan's +partisan, partizan +partisan, partizan +partisanize, partisanise +partisanizes, partisanises +partisans, partizans +partisans, partizans +Pasiphae's, Pasiphaae's +Pasiphae, Pasiphaae +passades, passadoes +passivization, passivisation +passivize, passivise +passivized, passivised +passivizes, passivises +passivizing, passivising +pasteurization's, pasteurisation's +pasteurization, pasteurisation +pasteurizations, pasteurisations +pasteurize, pasteurise +pasteurized, pasteurised +pasteurizer's, pasteuriser's +pasteurizer, pasteuriser +Pasteurizers, Pasteurisers +pasteurizers, pasteurisers +pasteurizes, pasteurises +pasteurizing, pasteurising +pastoralize, pastoralise +pastoralizes, pastoralises +pastorize, pastorise +pastorizes, pastorises +paternalize, paternalise +paternalizes, paternalises +patine, patinae +patined, patinaed +patrialization, patrialisation +patrializations, patrialisations +patrialize, patrialise +patrialized, patrialised +patrializes, patrialises +patrializing, patrialising +patrices, patricoes +patronizable's, patronisable's +patronizable, patronisable +patronizabler, patronisabler +patronizables, patronisables +patronizablest, patronisablest +patronization's, patronisation's +patronization, patronisation +patronizations, patronisations +patronize, patronise +patronized, patronised +patronizer's, patroniser's +patronizer, patroniser +patronizers, patronisers +patronizes, patronises +patronizing's, patronising's +patronizing, patronising +patronizinglier, patronisinglier +patronizingliest, patronisingliest +patronizingly, patronisingly +patronizings, patronisings +patte, pattae +patternize, patternise +patternizes, patternises +Paulinize's, Paulinise's +Paulinize, Paulinise +Paulinizes, Paulinises +pauperization's, pauperisation's +pauperization, pauperisation +pauperizations, pauperisations +pauperize, pauperise +pauperized, pauperised +pauperizer's, pauperiser's +pauperizer, pauperiser +pauperizers, pauperisers +pauperizes, pauperises +pauperizing, pauperising +Pavior's, Paviour's +pavior's, paviour's +Pavior, Paviour +pavior, paviour +paviors, paviours +pawpaw's, papaw's +pawpaw, papaw +pawpaws, papaws +Paynize's, Paynise's +Paynize, Paynise +Paynizes, Paynises +pe, poe +pearlization, pearlisation +pearlize, pearlise +pearlized, pearlised +pearlizes, pearlises +pearlizing, pearlising +peasantize, peasantise +peasantizes, peasantises +pectization's, pectisation's +pectization, pectisation +pectizations, pectisations +pectize, pectise +pectized, pectised +pectizes, pectises +pectizing, pectising +peculiarize, peculiarise +peculiarized, peculiarised +peculiarizes, peculiarises +peculiarizing, peculiarising +pedagogism, paedagogism +pedagogue's, pedagog's +pedagogue, pedagog +pedagogues, pedagogs +pedaled, pedalled +pedaler's, pedaller's +pedaler, pedaller +pedalers, pedallers +pedaling, pedalling +pedanticize, pedanticise +pedanticized, pedanticised +pedanticizes, pedanticises +pedanticizing, pedanticising +pedantize, pedantise +pedantized, pedantised +pedantizes, pedantises +pedantizing, pedantising +pedatrophia, paedatrophia +pedatrophy, paedatrophy +peddler's, pedlar's +peddler, pedlar +peddlers, pedlars +pederast's, paederast's +pederast, paederast +pederastic, paederastic +pederastically, paederastically +pederasts, paederasts +pedestaled, pedestalled +pedestaling, pedestalling +pedestrianization's, pedestrianisation's +pedestrianization, pedestrianisation +pedestrianizations, pedestrianisations +pedestrianize, pedestrianise +pedestrianized, pedestrianised +pedestrianizes, pedestrianises +pedestrianizing, pedestrianising +pediatric, paediatric +pediatrics, paediatrics +pediatrist's, paediatrician's +pediatrist, paediatrician +pediatrists, paediatricians +pediatry, paediatry +pedobaptism's, paedobaptism's +pedobaptism, paedobaptism +pedobaptist's, paedobaptist's +pedobaptist, paedobaptist +pedodontic, paedodontic +pedodontics, paedodontics +pedogeneses, paedogeneses +pedogenesis, paedogenesis +pedogenetic, paedogenetic +pedogenic, paedogenic +pedological, paedological +pedologies, paedologies +pedologist, paedologist +pedologists, paedologists +pedology's, paedology's +pedology, paedology +pedometrical, paedometrical +pedomorphic, paedomorphic +pedomorphism, paedomorphism +pedomorphisms, paedomorphisms +pedomorphoses, paedomorphoses +pedomorphosis, paedomorphosis +pedophile, paedophile +pedophiles, paedophiles +pedophilia, paedophilia +pedophiliac, paedophiliac +pedophiliacs, paedophiliacs +pedophilias, paedophilias +pedophilic, paedophilic +pedotribe, paedotribe +pedotrophic, paedotrophic +pedotrophist, paedotrophist +pedotrophy, paedotrophy +peize, peise +peized, peised +peizes, peises +peizing, peising +Pekingese's, Pekinese's +Pekingese, Pekinese +pelletization's, pelletisation's +pelletization, pelletisation +pelletizations, pelletisations +pelletize, pelletise +pelletized, pelletised +pelletizer, pelletiser +pelletizes, pelletises +pelletizing, pelletising +pelorized, pelorised +pemmicanization's, pemmicanisation's +pemmicanization, pemmicanisation +pemmicanizations, pemmicanisations +pemmicanize's, pemmicanise's +pemmicanize, pemmicanise +pemmicanizes, pemmicanises +penalizable's, penalisable's +penalizable, penalisable +penalizabler, penalisabler +penalizables, penalisables +penalizablest, penalisablest +penalization's, penalisation's +penalization, penalisation +penalizations, penalisations +penalize, penalise +penalized, penalised +penalizes, penalises +penalizing, penalising +penciled, pencilled +penciler's, penciller's +penciler, penciller +pencilers, pencillers +penciling, pencilling +pencilings, pencillings +penelopize, penelopise +penelopized, penelopised +penelopizes, penelopises +penelopizing, penelopising +penlight's, penlite's +penlight, penlite +penlights, penlites +penne, pennae +pense, pensae +peptizable's, peptisable's +peptizable, peptisable +peptizables, peptisables +peptization's, peptisation's +peptization, peptisation +peptizations, peptisations +peptize, peptise +peptized, peptised +peptizer, peptiser +peptizers, peptisers +peptizes, peptises +peptizing, peptising +peptonemia, peptonaemia +peptonization's, peptonisation's +peptonization, peptonisation +peptonizations, peptonisations +peptonize, peptonise +peptonized, peptonised +peptonizer's, peptoniser's +peptonizer, peptoniser +peptonizes, peptonises +peptonizing, peptonising +peracid, preacid +peracidity, preacidity +peract, preact +peracute, preacute +perambulatory, preambulatory +perces, preces +perchlorethane, perchloroethane +perchlorethylene, perchloroethylene +perchloric, prechloric +perclose, preclose +percompound, precompound +percurrent, precurrent +percussionize, percussionise +percussionizes, percussionises +perdicine, perdicinae +perdiligent, prediligent +perdy, predy +perea, peraea +perennialize, perennialise +perennializes, perennialises +pereon, peraeon +pereopod, peraeopod +pereopods, peraeopods +perfectivize, perfectivise +perfectivizes, perfectivises +perfervor's, perfervour's +perfervor, perfervour +perfervors, perfervours +perfet, prefet +perfoliation, prefoliation +perfoliations, prefoliations +performant, preformant +performative, preformative +perhazard, prehazard +pericecal, pericaecal +pericecitis, pericaecitis +pericenter, pericentre +perichete, perichaete +pericope, pericopae +periesophageal, perioesophageal +periled, perilled +periling, perilling +periodicalize, periodicalise +periodicalizes, periodicalises +periodization's, periodisation's +periodization, periodisation +periodizations, periodisations +periodize, periodise +periodized, periodised +periodizes, periodises +periodizing, periodising +perjink, prejink +perlection, prelection +perlingual, prelingual +perlingually, prelingually +permissable, premissable +permixture, premixture +pernasal, prenasal +peroral, preoral +perorally, preorally +perotic, preotic +peroxidize, peroxidise +peroxidized, peroxidised +peroxidizement's, peroxidisement's +peroxidizement, peroxidisement +peroxidizements, peroxidisements +peroxidizes, peroxidises +peroxidizing, peroxidising +perperfect, preperfect +Perse's, Persae's +Perse, Persae +perse, prese +Persianization's, Persianisation's +Persianization, Persianisation +Persianizations, Persianisations +Persianize's, Persianise's +Persianize, Persianise +Persianized's, Persianised's +Persianized, Persianised +Persianizes, Persianises +Persianizing's, Persianising's +Persianizing, Persianising +Persicize's, Persicise's +Persicize, Persicise +Persicized's, Persicised's +Persicized, Persicised +Persicizes, Persicises +Persicizing's, Persicising's +Persicizing, Persicising +persolve, presolve +personalization's, personalisation's +personalization, personalisation +personalizations, personalisations +personalize, personalise +personalized, personalised +personalizes, personalises +personalizing, personalising +personization's, personisation's +personization, personisation +personizations, personisations +personize, personise +personized, personised +personizes, personises +personizing, personising +perst, prest +Peruvianize's, Peruvianise's +Peruvianize, Peruvianise +Peruvianizes, Peruvianises +perv, prev +perve, preve +perved, preved +perves, preves +perviable, previable +perving, preving +perviousness, previousness +perviousnesses, previousnesses +petaled, petalled +petling, poetling +Petrarchize's, Petrarchise's +Petrarchize, Petrarchise +Petrarchized's, Petrarchised's +Petrarchized, Petrarchised +Petrarchizes, Petrarchises +Petrarchizing's, Petrarchising's +Petrarchizing, Petrarchising +petrolization's, petrolisation's +petrolization, petrolisation +petrolizations, petrolisations +petrolize, petrolise +petrolizes, petrolises +phacochere, phacochoere +phacocherine, phacochoerine +Phaenna's, Phaaenna's +Phaenna, Phaaenna +phagedena, phagedaena +phagedenas, phagedaenas +phagedenic, phagedaenic +phagedenical, phagedaenical +phagedenous, phagedaenous +phagocytize, phagocytise +phagocytizes, phagocytises +phalanxes, phalanx +phantomize, phantomise +phantomizer, phantomiser +phantomizers, phantomisers +phantomizes, phantomises +Pharisean's, Pharisaean's +Pharisean, Pharisaean +pharmacopeian, pharmacopoeian +pharmacopoeia's, pharmacopeia's +pharmacopoeia, pharmacopeia +pharmacopoeial, pharmacopeial +pharmacopoeias, pharmacopeias +phelonion, phaelonion +phelonions, phaelonions +phenicia, phoenicia +phenicopter, phoenicopter +phenogam, phaenogam +phenogams, phaenogams +phenogenesis, phaenogenesis +phenogenetic, phaenogenetic +phenolization's, phenolisation's +phenolization, phenolisation +phenolizations, phenolisations +phenolize, phenolise +phenolizes, phenolises +phenological, phaenological +phenologies, phaenologies +phenology, phaenology +phenomenalization's, phenomenalisation's +phenomenalization, phenomenalisation +phenomenalizations, phenomenalisations +phenomenalize, phenomenalise +phenomenalized, phenomenalised +phenomenalizes, phenomenalises +phenomenalizing, phenomenalising +phenomenism, phaenomenism +phenomenize, phenomenise +phenomenized, phenomenised +phenomenizes, phenomenises +phenomenizing, phenomenising +phenozygous, phaenozygous +pheophyl, phaeophyl +pheophyll, phaeophyll +pheophytin, phaeophytin +phiale, phialae +philanthropize, philanthropise +philanthropized, philanthropised +philanthropizes, philanthropises +philanthropizing, philanthropising +Philippize's, Philippise's +Philippize, Philippise +Philippized's, Philippised's +Philippized, Philippised +Philippizes, Philippises +Philippizing's, Philippising's +Philippizing, Philippising +Philistinize's, Philistinise's +Philistinize, Philistinise +Philistinized's, Philistinised's +Philistinized, Philistinised +Philistinizes, Philistinises +Philistinizing's, Philistinising's +Philistinizing, Philistinising +philopena, philopoena +philopenas, philopoenas +philosophization's, philosophisation's +philosophization, philosophisation +philosophizations, philosophisations +philosophize, philosophise +philosophized, philosophised +philosophizer's, philosophiser's +philosophizer, philosophiser +philosophizers, philosophisers +philosophizes, philosophises +philosophizing, philosophising +philter's, philtre's +philter, philtre +philters, philtres +phlebotomization's, phlebotomisation's +phlebotomization, phlebotomisation +phlebotomizations, phlebotomisations +phlebotomize, phlebotomise +phlebotomized, phlebotomised +phlebotomizes, phlebotomises +phlebotomizing, phlebotomising +phleum, phloeum +phlyctena's, phlyctaena's +phlyctena, phlyctaena +phlyctenae, phlyctaenae +phlyctenula, phlyctaenula +Phocean, Phocaean +phonemicization, phonemicisation +phonemicizations, phonemicisations +phonemicize, phonemicise +phonemicized, phonemicised +phonemicizes, phonemicises +phonemicizing, phonemicising +phoneticization's, phoneticisation's +phoneticization, phoneticisation +phoneticizations, phoneticisations +phoneticize, phoneticise +phoneticized, phoneticised +phoneticizes, phoneticises +phoneticizing, phoneticising +phonetization, phonetisation +phonetizations, phonetisations +phonetize, phonetise +phonetized, phonetised +phonetizes, phonetises +phonetizing, phonetising +phorrhea, phorrhoea +phosphatization's, phosphatisation's +phosphatization, phosphatisation +phosphatizations, phosphatisations +phosphatize, phosphatise +phosphatized, phosphatised +phosphatizes, phosphatises +phosphatizing, phosphatising +phosphorize, phosphorise +phosphorized, phosphorised +phosphorizes, phosphorises +phosphorizing, phosphorising +photesthesis, photaesthesis +photesthesis, photoesthesis +photocatalyzer's, photocatalyser's +photocatalyzer, photocatalyser +photocatalyzers, photocatalysers +photoesthetic, photoaesthetic +photographize, photographise +photographizes, photographises +photoionization's, photoionisation's +photoionization, photoionisation +photoionizations, photoionisations +photoisomerization's, photoisomerisation's +photoisomerization, photoisomerisation +photoisomerizations, photoisomerisations +photolabeled, photolabelled +photolabeler, photolabeller +photolabeling, photolabelling +photolyzable, photolysable +photolyze, photolyse +photolyzed, photolysed +photolyzes, photolyses +photolyzing, photolysing +photopolymerization's, photopolymerisation's +photopolymerization, photopolymerisation +photopolymerizations, photopolymerisations +photosensitization's, photosensitisation's +photosensitization, photosensitisation +photosensitizations, photosensitisations +photosensitize, photosensitise +photosensitized, photosensitised +photosensitizer's, photosensitiser's +photosensitizer, photosensitiser +photosensitizers, photosensitisers +photosensitizes, photosensitises +photosensitizing, photosensitising +photosynthesize, photosynthesise +photosynthesized, photosynthesised +photosynthesizes, photosynthesises +photosynthesizing, photosynthesising +phrenologize, phrenologise +phrenologized, phrenologised +phrenologizes, phrenologises +phrenologizing, phrenologising +Phylactolema's, Phylactolaema's +Phylactolema, Phylactolaema +Phylactolemata's, Phylactolaemata's +Phylactolemata, Phylactolaemata +phytoecology, phytooecology +phytohemagglutinin, phytohaemagglutinin +piarhemic, piarhaemic +piaster's, piastre's +piaster, piastre +piasters, piastres +picogram's, picogramme's +picogram, picogramme +picograms, picogrammes +picometer's, picometre's +picometer, picometre +picometers, picometres +pictorialization's, pictorialisation's +pictorialization, pictorialisation +pictorializations, pictorialisations +pictorialize, pictorialise +pictorialized, pictorialised +pictorializes, pictorialises +pictorializing, pictorialising +picturization's, picturisation's +picturization, picturisation +picturizations, picturisations +picturize, picturise +picturized, picturised +picturizes, picturises +picturizing, picturising +pidginization's, pidginisation's +pidginization, pidginisation +pidginizations, pidginisations +pidginize, pidginise +pidginized, pidginised +pidginizes, pidginises +pidginizing, pidginising +piggyback's, pickaback's +piggyback, pickaback +piggybacking, pickabacking +piggybacks, pickabacks +pigmean, pigmaean +pigmentize, pigmentise +pigmentizes, pigmentises +pilau's, pilaff's +pilau, pilaff +pilaus, pilaffs +pilgrimize, pilgrimise +pilgrimized, pilgrimised +pilgrimizes, pilgrimises +pilgrimizing, pilgrimising +pillarize, pillarise +pillarizes, pillarises +pillorize, pillorise +pillorized, pillorised +pillorizes, pillorises +pillorizing, pillorising +pillowbeer, pillowbere +Pindarize's, Pindarise's +Pindarize, Pindarise +Pindarized's, Pindarised's +Pindarized, Pindarised +Pindarizes, Pindarises +Pindarizing's, Pindarising's +Pindarizing, Pindarising +piney, piny +pinkie's, pinky's +pinkie, pinky +pinnule, pinnulae +pinochle's, pinocle's +pinochle, pinocle +pinyon's, piÒon's +pinyon, piÒon +pinyons, piÒons +piratize, piratise +piratizes, piratises +piroshki's, pirozhki's +piroshki, pirozhki +piscine, piscinae +pistoled, pistolled +pistoling, pistolling +pixie's, pixy's +pixie, pixy +pixieish, pixyish +pizes, pises +pizzazz's, pizazz's +pizzazz, pizazz +pizzazzes, pizazzes +Placean's, Placaean's +Placean, Placaean +placebos, placeboes +plage, plagae +plagiarization's, plagiarisation's +plagiarization, plagiarisation +plagiarizations, plagiarisations +plagiarize, plagiarise +plagiarized, plagiarised +plagiarizer's, plagiariser's +plagiarizer, plagiariser +plagiarizers, plagiarisers +plagiarizes, plagiarises +plagiarizing, plagiarising +Plante's, Plantae's +Plante, Plantae +plantule, plantulae +plasmapheresis, plasmaphaeresis +plasmolyze, plasmolyse +plasmolyzed, plasmolysed +plasmolyzes, plasmolyses +plasmolyzing, plasmolysing +plasticization's, plasticisation's +plasticization, plasticisation +plasticizations, plasticisations +plasticize, plasticise +plasticized, plasticised +plasticizer's, plasticiser's +plasticizer, plasticiser +plasticizers, plasticisers +plasticizes, plasticises +plasticizing, plasticising +platea, plataea +platinization's, platinisation's +platinization, platinisation +platinizations, platinisations +platinize, platinise +platinized, platinised +platinizes, platinises +platinizing, platinising +platitudinization's, platitudinisation's +platitudinization, platitudinisation +platitudinizations, platitudinisations +platitudinize, platitudinise +platitudinized, platitudinised +platitudinizer's, platitudiniser's +platitudinizer, platitudiniser +platitudinizes, platitudinises +platitudinizing, platitudinising +Platonization's, Platonisation's +Platonization, Platonisation +platonization, platonisation +Platonize, Platonise +platonize, platonise +Platonized, Platonised +platonized, platonised +Platonizer's, Platoniser's +Platonizer, Platoniser +Platonizes, Platonises +platonizes, platonises +Platonizing, Platonising +platonizing, platonising +platycelian, platycoelian +platycelous, platycoelous +plebeianization's, plebeianisation's +plebeianization, plebeianisation +plebeianize, plebeianise +plebeianized, plebeianised +plebeianizes, plebeianises +plebeianizing, plebeianising +pleuroperitoneal, pleuroperitonaeal +plow's, plough's +plow, plough +plowable, ploughable +plowboy's, ploughboy's +plowboy, ploughboy +plowboys, ploughboys +plowed, ploughed +plower's, plougher's +plower, plougher +plowers, ploughers +plowhead, ploughhead +plowing's, ploughing's +plowing, ploughing +plowman's, ploughman's +plowman, ploughman +plowmen, ploughmen +plows, ploughs +plowshare's, ploughshare's +plowshare, ploughshare +plowshares, ploughshares +plumule, plumulae +pluralization's, pluralisation's +pluralization, pluralisation +pluralizations, pluralisations +pluralize, pluralise +pluralized, pluralised +pluralizer's, pluraliser's +pluralizer, pluraliser +pluralizers, pluralisers +pluralizes, pluralises +pluralizing, pluralising +poeticization, poeticisation +poeticize, poeticise +poeticized, poeticised +poeticizes, poeticises +poeticizing, poeticising +poetization's, poetisation's +poetization, poetisation +poetizations, poetisations +poetize, poetise +poetized, poetised +poetizer's, poetiser's +poetizer, poetiser +poetizers, poetisers +poetizes, poetises +poetizing, poetising +pogromize, pogromise +pogromizes, pogromises +poky, pokey +polarizabilities, polarisabilities +polarizability's, polarisability's +polarizability, polarisability +polarizable's, polarisable's +polarizable, polarisable +polarizables, polarisables +polarization's, polarisation's +polarization, polarisation +polarizations, polarisations +polarize, polarise +polarized, polarised +polarizer's, polariser's +polarizer, polariser +polarizers, polarisers +polarizes, polarises +polarizing, polarising +polemicize, polemicise +polemicized, polemicised +polemicizes, polemicises +polemicizing, polemicising +polemize, polemise +polemized, polemised +polemizes, polemises +polemizing, polemising +policize, policise +policizer, policiser +policizers, policisers +policizes, policises +poliencephalitis's, polioencephalitis's +poliencephalitis, polioencephalitis +poliencephalomyelitis, polioencephalomyelitis +politicalize, politicalise +politicalizes, politicalises +politicization's, politicisation's +politicization, politicisation +politicizations, politicisations +politicize, politicise +politicized, politicised +politicizer, politiciser +politicizers, politicisers +politicizes, politicises +politicizing, politicising +politize, politise +politizes, politises +pollack's, pollock's +pollack, pollock +pollenizer, polleniser +pollinize, pollinise +pollinized, pollinised +pollinizer, polliniser +pollinizes, pollinises +pollinizing, pollinising +polliwog's, pollywog's +polliwog, pollywog +polliwogs, pollywogs +Polonization's, Polonisation's +Polonization, Polonisation +polonize, polonise +polonized, polonised +polonizes, polonises +polonizing, polonising +polychetous, polychaetous +polychromatize, polychromatise +polychromatizes, polychromatises +polychromize, polychromise +polychromizes, polychromises +polycythemia, polycythaemia +polycythemias, polycythaemias +polycythemic, polycythaemic +polydemonism, polydaemonism +polydemonisms, polydaemonisms +polydemonist's, polydaemonist's +polydemonist, polydaemonist +polyemia, polyaemia +polyemic, polyaemic +polyestrous, polyoestrous +polygamize, polygamise +polygamizes, polygamises +polyhemia, polyhaemia +polyhemic, polyhaemic +polymerization's, polymerisation's +polymerization, polymerisation +polymerizations, polymerisations +polymerize, polymerise +polymerized, polymerised +polymerizes, polymerises +polymerizing, polymerising +polypnea, polypnoea +polypneic, polypnoeic +polysulphurization's, polysulphurisation's +polysulphurization, polysulphurisation +polysulphurizations, polysulphurisations +polytetrafluorethylene, polytetrafluoroethylene +polytetrafluorethylenes, polytetrafluoroethylenes +pomerium, pomoerium +pomme, pommae +pommeled, pommelled +pommeling, pommelling +popliteal, poplitaeal +popularization's, popularisation's +popularization, popularisation +popularizations, popularisations +popularize, popularise +popularized, popularised +popularizer's, populariser's +popularizer, populariser +popularizers, popularisers +popularizes, popularises +popularizing, popularising +porcelainization's, porcelainisation's +porcelainization, porcelainisation +porcelainizations, porcelainisations +porcelainize, porcelainise +porcelainized, porcelainised +porcelainizes, porcelainises +porcelainizing, porcelainising +porcellanize, porcellanise +porcellanized, porcellanised +porcellanizes, porcellanises +porcellanizing, porcellanising +porer, pourer +porers, pourers +poringly, pouringly +porphyrization's, porphyrisation's +porphyrization, porphyrisation +porte, portae +portionize, portionise +portionizes, portionises +positivize, positivise +positivizes, positivises +postcecal, postcaecal +postcenal, postcoenal +posterize, posterise +posterizes, posterises +postfetal, postfoetal +postilion's, postillion's +postilion, postillion +postilions, postillions +postmedieval, postmediaeval +postsynchronization, postsynchronisation +posturize, posturise +posturized, posturised +posturizes, posturises +posturizing, posturising +potentialization's, potentialisation's +potentialization, potentialisation +potentializations, potentialisations +potentialize, potentialise +potentializes, potentialises +potentize, potentise +potentized, potentised +potentizes, potentises +potentizing, potentising +pouder, poudre +pouders, poudres +pouffe's, pouf's +pouffe, pouf +pouffes, poufs +poulder, pouldre +poulders, pouldres +powderization's, powderisation's +powderization, powderisation +powderizations, powderisations +powderize, powderise +powderizer, powderiser +powderizers, powderisers +powderizes, powderises +powellize, powellise +powellized, powellised +powellizes, powellises +powellizing, powellising +practicer's, practiser's +practicer, practiser +practicers, practisers +praenomen's, prenomen's +praenomen, prenomen +praenomens, prenomens +pragmatization, pragmatisation +pragmatizations, pragmatisations +pragmatize, pragmatise +pragmatized, pragmatised +pragmatizer, pragmatiser +pragmatizers, pragmatisers +pragmatizes, pragmatises +pragmatizing, pragmatising +preabdomen, praeabdomen +preacetabular, praeacetabular +preacherize, preacherise +preacherizes, preacherises +preacknowledgment's, preacknowledgement's +preacknowledgment, preacknowledgement +preacknowledgments, preacknowledgements +preanal, praeanal +preanesthetic's, preanaesthetic's +preanesthetic, preanaesthetic +preanesthetics, preanaesthetics +preapprize, preapprise +preapprized, preapprised +preapprizing, preapprising +preauthorize, preauthorise +prebaptize, prebaptise +prebaptizes, prebaptises +precancelation, precancellation +precava, praecava +precavae, praecavae +precipe, praecipe +precipes, praecipes +precisionize, precisionise +precisionizes, precisionises +precivilization's, precivilisation's +precivilization, precivilisation +precivilizations, precivilisations +precocial, praecocial +precolor's, precolour's +precolor, precolour +precolorable's, precolourable's +precolorable, precolourable +precolorabler, precolourabler +precolorables, precolourables +precolorablest, precolourablest +precoloration's, precolouration's +precoloration, precolouration +precolorations, precolourations +precolored, precoloured +precoloring, precolouring +precolorings, precolourings +precolors, precolours +preconization's, preconisation's +preconization, preconisation +preconizations, preconisations +preconize, preconise +preconized, preconised +preconizer's, preconiser's +preconizer, preconiser +preconizers, preconisers +preconizes, preconises +preconizing, preconising +precoracoid, praecoracoid +precordia, praecordia +precordial, praecordial +precordium, praecordium +precornu, praecornu +precox, praecox +precriticize, precriticise +precriticizes, precriticises +precuneus, praecuneus +predial, praedial +predialist, praedialist +prediality, praediality +predials, praedials +preemptor's, preaemptor's +preemptor, preaemptor +preesophageal, praeesophageal +preesophageal, preoesophageal +preestival, preaestival +preexistent, preaexistent +prefavor's, prefavour's +prefavor, prefavour +prefavorable's, prefavourable's +prefavorable, prefavourable +prefavorables, prefavourables +prefavorablies, prefavourablies +prefavorably, prefavourably +prefavorite's, prefavourite's +prefavorite, prefavourite +prefavorites, prefavourites +prefavors, prefavours +prefectorial, praefectorial +prefertilization's, prefertilisation's +prefertilization, prefertilisation +prefertilizations, prefertilisations +prefertilize, prefertilise +prefertilizes, prefertilises +preflavor's, preflavour's +preflavor, preflavour +preflavoring, preflavouring +preflavorings, preflavourings +preflavors, preflavours +prefloration, praefloration +prefoliation, praefoliation +pregalvanize, pregalvanise +pregalvanizes, pregalvanises +prehallux, praehallux +prehumor's, prehumour's +prehumor, prehumour +prehumors, prehumours +preinitialize, preinitialise +preinitialized, preinitialised +preinitializes, preinitialises +preinitializing, preinitialising +prejudgment's, prejudgement's +prejudgment, prejudgement +prejudgments, prejudgements +prelabor's, prelabour's +prelabor, prelabour +prelabors, prelabours +prelabrum, praelabrum +prelatize, prelatise +prelatized, prelatised +prelatizes, prelatises +prelatizing, prelatising +prelect, praelect +prelected, praelected +prelecting, praelecting +prelection's, praelection's +prelection, praelection +prelector, praelector +prelectorship, praelectorship +prelectress, praelectress +prelects, praelects +prelocalization's, prelocalisation's +prelocalization, prelocalisation +prelocalizations, prelocalisations +preludium, praeludium +preludize, preludise +preludizes, preludises +premaxilla, praemaxilla +premial, proemial +premillennialize, premillennialise +premillennialized, premillennialised +premillennializing, premillennialising +premonopolize, premonopolise +premonopolizes, premonopolises +premunire, praemunire +prenarial, praenarial +preneural, praeneural +prenomina, praenomina +prenominal, praenominal +preoffense's, preoffence's +preoffense, preoffence +preoffenses, preoffences +preoperculum, praeoperculum +preorganization's, preorganisation's +preorganization, preorganisation +preorganizations, preorganisations +preorganize, preorganise +preorganizes, preorganises +preoxidize, preoxidise +preoxidized, preoxidised +preoxidizes, preoxidises +preoxidizing, preoxidising +prepaleolithic, prepalaeolithic +prepositor, praepositor +prepositure, praepositure +preposter, praeposter +prepostor's, praepostor's +prepostor, praepostor +prepostors, praepostors +preppy's, preppie's +preppy, preppie +preprogram, preprogramme +prepubis, praepubis +prerealization's, prerealisation's +prerealization, prerealisation +prerealizations, prerealisations +prerealize, prerealise +prerealizes, prerealises +prerecognize, prerecognise +prerecognizes, prerecognises +Presbyterianize's, Presbyterianise's +Presbyterianize, Presbyterianise +Presbyterianized's, Presbyterianised's +Presbyterianized, Presbyterianised +Presbyterianizes, Presbyterianises +Presbyterianizing's, Presbyterianising's +Presbyterianizing, Presbyterianising +prescutum, praescutum +presidium's, praesidium's +presidium, praesidium +prespecialize, prespecialise +prespecializes, prespecialises +presphenoid, praesphenoid +presplendor's, presplendour's +presplendor, presplendour +presplendors, presplendours +pressurization's, pressurisation's +pressurization, pressurisation +pressurizations, pressurisations +pressurize, pressurise +pressurized, pressurised +pressurizer, pressuriser +pressurizers, pressurisers +pressurizes, pressurises +pressurizing, pressurising +prestandardization's, prestandardisation's +prestandardization, prestandardisation +prestandardizations, prestandardisations +prestandardize, prestandardise +prestandardizes, prestandardises +presternal, praesternal +presternum, praesternum +prestomium, praestomium +presympathize, presympathise +presympathizes, presympathises +presystolic, praesystolic +pretaxation, praetaxation +pretense's, pretence's +pretense, pretence +pretenses, pretences +pretensive, pretencive +preterit's, preterite's +preterit, preterite +preterits, preterites +pretexta's, praetexta's +pretexta, praetexta +pretextae, praetextae +pretorial, praetorial +Pretorians, Praetorians +pretorium, praetorium +Pretorius's, Praetorius's +Pretorius, Praetorius +pretorship, praetorship +preutilizable's, preutilisable's +preutilizable, preutilisable +preutilizables, preutilisables +preutilization's, preutilisation's +preutilization, preutilisation +preutilizations, preutilisations +preutilize, preutilise +preutilizes, preutilises +preventable, preventible +previze, previse +prezygapophysis, praezygapophysis +pricey, pricy +primeval, primaeval +primevally, primaevally +prioritization's, prioritisation's +prioritization, prioritisation +prioritizations, prioritisations +prioritize, prioritise +prioritized, prioritised +prioritizer, prioritiser +prioritizers, prioritisers +prioritizes, prioritises +prioritizing, prioritising +prioritizings, prioritisings +priorization, priorisation +priorizations, priorisations +priorize, priorise +priorized, priorised +priorizes, priorises +priorizing, priorising +privatization's, privatisation's +privatization, privatisation +privatizations, privatisations +privatize, privatise +privatized, privatised +privatizer, privatiser +privatizers, privatisers +privatizes, privatises +privatizing, privatising +prizable, prisable +proadvertizing, proadvertising +problemize, problemise +problemizes, problemises +processionize, processionise +processionizes, processionises +Procrusteanize's, Procrusteanise's +Procrusteanize, Procrusteanise +Procrusteanizes, Procrusteanises +proctodea, proctodaea +proctodeal, proctodaeal +proctodeum's, proctodaeum's +proctodeum, proctodaeum +proctodeums, proctodaeums +proctorization's, proctorisation's +proctorization, proctorisation +proctorizations, proctorisations +proctorize, proctorise +proctorized, proctorised +proctorizes, proctorises +proctorizing, proctorising +prodigalize, prodigalise +prodigalized, prodigalised +prodigalizes, prodigalises +prodigalizing, prodigalising +productize, productise +productized, productised +productizer, productiser +productizers, productisers +productizes, productises +productizing, productising +proemium, prooemium +profanize, profanise +profanizes, profanises +profer, profre +professionalization's, professionalisation's +professionalization, professionalisation +professionalizations, professionalisations +professionalize, professionalise +professionalized, professionalised +professionalizes, professionalises +professionalizing, professionalising +professionize, professionise +professionizes, professionises +programmer's, programer's +programmer, programer +programmers, programers +proindustrialization, proindustrialisation +projectization, projectisation +projectizations, projectisations +prokaryote's, procaryote's +prokaryote, procaryote +prokaryotes, procaryotes +prokaryotic, procaryotic +proletarianization's, proletarianisation's +proletarianization, proletarianisation +proletarianizations, proletarianisations +proletarianize, proletarianise +proletarianized, proletarianised +proletarianizes, proletarianises +proletarianizing, proletarianising +proletarize, proletarise +proletarized, proletarised +proletarizing, proletarising +prologize, prologise +prologized, prologised +prologizes, prologises +prologizing, prologising +prologue's, prolog's +prologue, prolog +prologues, prologs +prologuize, prologuise +prologuized, prologuised +prologuizer's, prologuiser's +prologuizer, prologuiser +prologuizers, prologuisers +prologuizes, prologuises +prologuizing, prologuising +prolusionize, prolusionise +prolusionizes, prolusionises +pronominalization, pronominalisation +pronominalize, pronominalise +propagandize, propagandise +propagandized, propagandised +propagandizes, propagandises +propagandizing, propagandising +propellant's, propellent's +propellant, propellent +propellants, propellents +prophetize, prophetise +prophetizes, prophetises +propositionize, propositionise +propositionizes, propositionises +propretor's, propraetor's +propretor, propraetor +propretorial, propraetorial +propretorian, propraetorian +propretors, propraetors +propylitization, propylitisation +propylitizations, propylitisations +propylitize, propylitise +propylitized, propylitised +propylitizes, propylitises +propylitizing, propylitising +proselytization's, proselytisation's +proselytization, proselytisation +proselytizations, proselytisations +proselytize, proselytise +proselytized, proselytised +proselytizer's, proselytiser's +proselytizer, proselytiser +proselytizers, proselytisers +proselytizes, proselytises +proselytizing, proselytising +proseuche, proseuchae +prosocele, prosocoele +prosopopeial, prosopopoeial +prosopopoeia, prosopopeia +prosopopoeias, prosopopeias +prostatorrhea, prostatorrhoea +protectionize, protectionise +protectionizes, protectionises +proteide, proteidae +Protestantize's, Protestantise's +Protestantize, Protestantise +Protestantized's, Protestantised's +Protestantized, Protestantised +Protestantizes, Protestantises +Protestantizing's, Protestantising's +Protestantizing, Protestantising +protester's, protestor's +protester, protestor +protesters, protestors +Prothoenor's, Prothoaenor's +Prothoenor, Prothoaenor +protoarcheology, protoarchaeology +protocoled, protocolled +protocoling, protocolling +protocolization's, protocolisation's +protocolization, protocolisation +protocolizations, protocolisations +protocolize, protocolise +protocolized, protocolised +protocolizes, protocolises +protocolizing, protocolising +proverbialize, proverbialise +proverbialized, proverbialised +proverbializes, proverbialises +proverbializing, proverbialising +proverbize, proverbise +proverbizes, proverbises +provincialization's, provincialisation's +provincialization, provincialisation +provincializations, provincialisations +provincialize, provincialise +provincialized, provincialised +provincializes, provincialises +provincializing, provincialising +Prussianization's, Prussianisation's +prussianization's, prussianisation's +Prussianization, Prussianisation +prussianization, prussianisation +Prussianizations, Prussianisations +Prussianize, Prussianise +prussianize, prussianise +Prussianized, Prussianised +prussianized, prussianised +Prussianizer's, Prussianiser's +prussianizer's, prussianiser's +Prussianizer, Prussianiser +prussianizer, prussianiser +Prussianizers, Prussianisers +Prussianizes, Prussianises +prussianizes, prussianises +Prussianizing, Prussianising +prussianizing, prussianising +psalmodize, psalmodise +psalmodized, psalmodised +psalmodizes, psalmodises +psalmodizing, psalmodising +pseudelephant, pseudoelephant +pseudembryo, pseudoembryo +pseudembryonic, pseudoembryonic +pseudesthesia, pseudaesthesia +pseudhemal, pseudhaemal +pseudoanemia's, pseudoanaemia's +pseudoanemia, pseudoanaemia +pseudoanemias, pseudoanaemias +pseudoanemic, pseudoanaemic +pseudoanemics, pseudoanaemics +pseudocele, pseudocoele +pseudocelom, pseudocoelom +pseudoedema's, pseudooedema's +pseudoedema, pseudooedema +pseudoedemas, pseudooedemas +pseudographize, pseudographise +pseudographizes, pseudographises +pseudolunule, pseudolunulae +psychoanalyze, psychoanalyse +psychoanalyzed, psychoanalysed +psychoanalyzer's, psychoanalyser's +psychoanalyzer, psychoanalyser +psychoanalyzers, psychoanalysers +psychoanalyzes, psychoanalyses +psychoanalyzing, psychoanalysing +psychologization, psychologisation +psychologize, psychologise +psychologized, psychologised +psychologizes, psychologises +psychologizing, psychologising +Ptolemean's, Ptolemaean's +Ptolemean, Ptolemaean +ptyalize, ptyalise +ptyalized, ptyalised +ptyalizes, ptyalises +ptyalizing, ptyalising +publice, publicae +publicize, publicise +publicized, publicised +publicizes, publicises +publicizing, publicising +puebloization's, puebloisation's +puebloization, puebloisation +puebloizations, puebloisations +puebloize, puebloise +puebloizes, puebloises +puers, pures +pulicide, pulicidae +Pullmanize's, Pullmanise's +Pullmanize, Pullmanise +Pullmanizes, Pullmanises +pulpitize, pulpitise +pulpitizes, pulpitises +pulverizable's, pulverisable's +pulverizable, pulverisable +pulverizabler, pulverisabler +pulverizables, pulverisables +pulverizablest, pulverisablest +pulverization's, pulverisation's +pulverization, pulverisation +pulverizations, pulverisations +pulverize, pulverise +pulverized, pulverised +pulverizer's, pulveriser's +pulverizer, pulveriser +pulverizers, pulverisers +pulverizes, pulverises +pulverizing, pulverising +pulvilized, pulvilised +pummeled, pummelled +pummeler, pummeller +pummeling, pummelling +pumpkin's, punkin's +pumpkin, punkin +pumpkins, punkins +pupilize, pupilise +pupilizes, pupilises +puppetize, puppetise +puppetizes, puppetises +Puritanize's, Puritanise's +Puritanize, Puritanise +puritanize, puritanise +puritanized, puritanised +Puritanizer's, Puritaniser's +Puritanizer, Puritaniser +Puritanizers, Puritanisers +Puritanizes, Puritanises +puritanizes, puritanises +puritanizing, puritanising +pyemia's, pyaemia's +pyemia, pyaemia +pyemias, pyaemias +pyemic, pyaemic +pygmean, pygmaean +pygmies, pigmies +pygmy's, pigmy's +pygmy, pigmy +pyorrhea's, pyorrhoea's +pyorrhea, pyorrhoea +pyorrheal, pyorrhoeal +pyorrhealer, pyorrhoealer +pyorrhealest, pyorrhoealest +pyorrheas, pyorrhoeas +pyorrheic, pyorrhoeic +pyramidize, pyramidise +pyramidizes, pyramidises +Pyrenean, Pyrenaean +Pyreneus's, Pyrenaeus's +Pyreneus, Pyrenaeus +pyridinize, pyridinise +pyridinizes, pyridinises +pyritization's, pyritisation's +pyritization, pyritisation +pyritizations, pyritisations +pyritize, pyritise +pyritized, pyritised +pyritizes, pyritises +pyritizing, pyritising +pyrolyzable, pyrolysable +pyrolyzate's, pyrolysate's +pyrolyzate, pyrolysate +pyrolyzates, pyrolysates +pyrolyze's, pyrolyse's +pyrolyze, pyrolyse +pyrolyzed, pyrolysed +pyrolyzer, pyrolyser +pyrolyzes, pyrolyses +pyrolyzing, pyrolysing +Pythagoreanize's, Pythagoreanise's +Pythagoreanize, Pythagoreanise +Pythagoreanizes, Pythagoreanises +pythonine, pythoninae +pythonize, pythonise +pythonizes, pythonises +quadriphonic, quadrophonic +quadriphonics, quadrophonics +quaestor's, questor's +quaestor, questor +quaestors, questors +quahog's, quahaug's +quahog, quahaug +quahogs, quahaugs +Quakerization's, Quakerisation's +Quakerization, Quakerisation +Quakerizations, Quakerisations +Quakerize's, Quakerise's +Quakerize, Quakerise +Quakerizes, Quakerises +quantization's, quantisation's +quantization, quantisation +quantizations, quantisations +quantize, quantise +quantized, quantised +quantizer's, quantiser's +quantizer, quantiser +quantizers, quantisers +quantizes, quantises +quantizing, quantising +quarreled, quarrelled +quarreler's, quarreller's +quarreler, quarreller +quarrelers, quarrellers +quarreling, quarrelling +quarrelous, quarrellous +quarterization's, quarterisation's +quarterization, quarterisation +quarterizations, quarterisations +quartet's, quartette's +quartet, quartette +quartets, quartettes +quaters, quatres +que, quae +querele, querelae +questionaries, quaestionaries +questionary, quaestionary +questorial, quaestorial +questorship's, quaestorship's +questorship, quaestorship +queuing, queueing +quininize, quininise +quininizes, quininises +quintessentialize, quintessentialise +quintessentialized, quintessentialised +quintessentializes, quintessentialises +quintessentializing, quintessentialising +quintet's, quintette's +quintet, quintette +quintets, quintettes +Quran's, Qur'an's +Quran, Qur'an +Quranic, Qur'anic +Qurans, Qur'ans +raccoon's, racoon's +raccoon, racoon +raccoons, racoons +racemization's, racemisation's +racemization, racemisation +racemizations, racemisations +racemize, racemise +racemized, racemised +racemizes, racemises +racemizing, racemising +racialization's, racialisation's +racialization, racialisation +racializations, racialisations +racialize, racialise +racializes, racialises +Radborne's, Radbourne's +Radborne, Radbourne +radialization's, radialisation's +radialization, radialisation +radializations, radialisations +radialize, radialise +radialized, radialised +radializes, radialises +radializing, radialising +radicalization's, radicalisation's +radicalization, radicalisation +radicalizations, radicalisations +radicalize, radicalise +radicalized, radicalised +radicalizes, radicalises +radicalizing, radicalising +radiopasteurization, radiopasteurisation +radiosensitize, radiosensitise +radiosensitized, radiosensitised +radiosensitizes, radiosensitises +radiosensitizing, radiosensitising +radiosterilization, radiosterilisation +radiosterilize, radiosterilise +radiosterilized, radiosterilised +radiosterilizes, radiosterilises +radiosterilizing, radiosterilising +radiumization's, radiumisation's +radiumization, radiumisation +radiumizations, radiumisations +radiumize, radiumise +radiumizes, radiumises +rajah's, raja's +rajah, raja +rajahs, rajas +Rame's, Ramae's +Rame, Ramae +ramekin's, ramequin's +ramekin, ramequin +ramekins, ramequins +rampier, rampire +rancor's, rancour's +rancor, rancour +rancors, rancours +randomization's, randomisation's +randomization, randomisation +randomizations, randomisations +randomize, randomise +randomized, randomised +randomizer's, randomiser's +randomizer, randomiser +randomizers, randomisers +randomizes, randomises +randomizing, randomising +ranee's, rani's +ranee, rani +ranees, ranis +raphe, raphae +raphide, raphidae +rapturize, rapturise +rapturized, rapturised +rapturizes, rapturises +rapturizing, rapturising +rascalize, rascalise +rascalizes, rascalises +rationalizable's, rationalisable's +rationalizable, rationalisable +rationalizables, rationalisables +rationalization's, rationalisation's +rationalization, rationalisation +rationalizations, rationalisations +rationalize, rationalise +rationalized, rationalised +rationalizer's, rationaliser's +rationalizer, rationaliser +rationalizers, rationalisers +rationalizes, rationalises +rationalizing, rationalising +ratite, ratitae +ratline's, ratlin's +ratlines, ratlins +raveler's, raveller's +raveler, raveller +ravelers, ravellers +reacclimatization's, reacclimatisation's +reacclimatization, reacclimatisation +reacclimatizations, reacclimatisations +reacclimatize, reacclimatise +reacclimatized, reacclimatised +reacclimatizes, reacclimatises +reacclimatizing, reacclimatising +reactualize, reactualise +reactualizes, reactualises +readvertize, readvertise +readvertized, readvertised +readvertizing, readvertising +realisticize, realisticise +realisticizes, realisticises +realizabilities, realisabilities +realizability's, realisability's +realizability, realisability +realizable, realisable +realizableness's, realisableness's +realizableness, realisableness +realizabler, realisabler +realizables, realisables +realizablest, realisablest +realizablies, realisablies +realizably, realisably +realization's, realisation's +realization, realisation +realizations, realisations +realize, realise +realized, realised +realizer's, realiser's +realizer, realiser +realizers, realisers +realizes, realises +realizing's, realising's +realizing, realising +realizingly, realisingly +realizings, realisings +reanalyze, reanalyse +reanalyzed, reanalysed +reanalyzer, reanalyser +reanalyzers, reanalysers +reanalyzes, reanalyses +reanalyzing, reanalysing +reanimalize, reanimalise +reanimalizes, reanimalises +reapologize, reapologise +reapologizes, reapologises +reauthorization's, reauthorisation's +reauthorization, reauthorisation +reauthorizations, reauthorisations +reauthorize, reauthorise +reauthorizes, reauthorises +rebaptization's, rebaptisation's +rebaptization, rebaptisation +rebaptizations, rebaptisations +rebaptize, rebaptise +rebaptized, rebaptised +rebaptizes, rebaptises +rebaptizing, rebaptising +rebourbonize, rebourbonise +rebourbonizes, rebourbonises +rebrutalize, rebrutalise +rebrutalizes, rebrutalises +recanalization, recanalisation +recapitalization's, recapitalisation's +recapitalization, recapitalisation +recapitalizations, recapitalisations +recapitalize, recapitalise +recapitalized, recapitalised +recapitalizes, recapitalises +recapitalizing, recapitalising +recarbonization's, recarbonisation's +recarbonization, recarbonisation +recarbonizations, recarbonisations +recarbonize, recarbonise +recarbonizer, recarboniser +recarbonizers, recarbonisers +recarbonizes, recarbonises +recategorized, recategorised +recausticize, recausticise +recausticizes, recausticises +recentralization's, recentralisation's +recentralization, recentralisation +recentralizations, recentralisations +recentralize, recentralise +recentralizes, recentralises +recercele, recercelae +reciprocalize, reciprocalise +reciprocalizes, reciprocalises +recivilization's, recivilisation's +recivilization, recivilisation +recivilizations, recivilisations +recivilize, recivilise +recivilizes, recivilises +recognizability, recognisability +recognizable, recognisable +recognizabler, recognisabler +recognizablest, recognisablest +recognizably, recognisably +recognizance's, recognisance's +recognizance, recognisance +recognizances, recognisances +recognize, recognise +recognized, recognised +recognizedlies, recognisedlies +recognizedly, recognisedly +recognizer's, recogniser's +recognizer, recogniser +recognizers, recognisers +recognizes, recognises +recognizing, recognising +recognizinglies, recognisinglies +recognizingly, recognisingly +recolonization's, recolonisation's +recolonization, recolonisation +recolonizations, recolonisations +recolonize, recolonise +recolonized, recolonised +recolonizes, recolonises +recolonizing, recolonising +recolor's, recolour's +recolor, recolour +recoloration's, recolouration's +recoloration, recolouration +recolorations, recolourations +recolored, recoloured +recoloring, recolouring +recolors, recolours +reconceptualization, reconceptualisation +reconceptualizing, reconceptualising +reconnoiter's, reconnoitre's +reconnoiter, reconnoitre +reconnoitered, reconnoitred +reconnoiterer's, reconnoitrer's +reconnoiterer, reconnoitrer +reconnoiterers, reconnoitrers +reconnoitering, reconnoitring +reconnoiters, reconnoitres +recriticize, recriticise +recriticizes, recriticises +recrystallization's, recrystallisation's +recrystallization, recrystallisation +recrystallizations, recrystallisations +recrystallize, recrystallise +recrystallized, recrystallised +recrystallizes, recrystallises +recrystallizing, recrystallising +redialed, redialled +redialer, redialler +redialing, redialling +redisseize, redisseise +redisseizin, redisseisin +reedified, reaedified +reedifies, reaedifies +reedify, reaedify +reedifying, reaedifying +reemphasize, reemphasise +reemphasized, reemphasised +reemphasizer, reemphasiser +reemphasizers, reemphasisers +reemphasizes, reemphasises +reemphasizing, reemphasising +reentrance's, reaentrance's +reentrance, reaentrance +reexportation's, reaexportation's +reexportation, reaexportation +reexporter's, reaexporter's +reexporter, reaexporter +refavor's, refavour's +refavor, refavour +refavors, refavours +refertilization's, refertilisation's +refertilization, refertilisation +refertilizations, refertilisations +refertilize, refertilise +refertilizes, refertilises +reflectorize's, reflectorise's +reflectorize, reflectorise +reflectorized, reflectorised +reflectorizes, reflectorises +reflectorizing, reflectorising +reforestization's, reforestisation's +reforestization, reforestisation +reforestize, reforestise +reforestizes, reforestises +reformades, reformadoes +refueled, refuelled +refueling, refuelling +regalize, regalise +regalizes, regalises +regalvanization's, regalvanisation's +regalvanization, regalvanisation +regalvanizations, regalvanisations +regalvanize, regalvanise +regalvanizes, regalvanises +reges, regoes +regionalization's, regionalisation's +regionalization, regionalisation +regionalizations, regionalisations +regionalize, regionalise +regionalized, regionalised +regionalizes, regionalises +regionalizing, regionalising +regularization's, regularisation's +regularization, regularisation +regularizations, regularisations +regularize, regularise +regularized, regularised +regularizer's, regulariser's +regularizer, regulariser +regularizers, regularisers +regularizes, regularises +regularizing, regularising +regulize, regulise +regulized, regulised +regulizes, regulises +regulizing, regulising +reharmonization, reharmonisation +reharmonize, reharmonise +reharmonizes, reharmonises +Rehm's, Roehm's +Rehm, Roehm +rehonor's, rehonour's +rehonor, rehonour +rehonors, rehonours +rehumanization's, rehumanisation's +rehumanization, rehumanisation +rehumanize, rehumanise +rehumanizes, rehumanises +rehybridize, rehybridise +rehybridizes, rehybridises +reindustrialization, reindustrialisation +reindustrializations, reindustrialisations +reindustrialize, reindustrialise +reindustrialized, reindustrialised +reindustrializes, reindustrialises +reindustrializing, reindustrialising +reinforce, reenforce +reinforceable, reenforceable +reinforced, reenforced +reinforces, reenforces +reinforcing, reenforcing +reinitialization, reinitialisation +reinitialize, reinitialise +reinitialized, reinitialised +reinitializes, reinitialises +reinitializing, reinitialising +reitemize, reitemise +reitemizes, reitemises +rejuvenize, rejuvenise +rejuvenized, rejuvenised +rejuvenizes, rejuvenises +rejuvenizing, rejuvenising +relabeled, relabelled +relabeler, relabeller +relabelers, relabellers +relabeling, relabelling +relativization's, relativisation's +relativization, relativisation +relativizations, relativisations +relativize, relativise +relativized, relativised +relativizes, relativises +relativizing, relativising +religionize, religionise +religionized, religionised +religionizes, religionises +religionizing, religionising +remagnetization's, remagnetisation's +remagnetization, remagnetisation +remagnetizations, remagnetisations +remagnetize, remagnetise +remagnetizes, remagnetises +rematerialize, rematerialise +rematerialized, rematerialised +rematerializes, rematerialises +rememorize, rememorise +rememorizes, rememorises +remilitarization's, remilitarisation's +remilitarization, remilitarisation +remilitarizations, remilitarisations +remilitarize, remilitarise +remilitarized, remilitarised +remilitarizes, remilitarises +remilitarizing, remilitarising +remineralization's, remineralisation's +remineralization, remineralisation +remineralizations, remineralisations +remineralize, remineralise +remineralized, remineralised +remineralizes, remineralises +remineralizing, remineralising +remobilization's, remobilisation's +remobilization, remobilisation +remobilizations, remobilisations +remobilize, remobilise +remobilizes, remobilises +remodeled, remodelled +remodeling, remodelling +remold, remould +remolded, remoulded +remolding, remoulding +remolds, remoulds +remonetization's, remonetisation's +remonetization, remonetisation +remonetizations, remonetisations +remonetize, remonetise +remonetized, remonetised +remonetizes, remonetises +remonetizing, remonetising +remoralization, remoralisation +remoralizations, remoralisations +remoralize, remoralise +remoralized, remoralised +remoralizes, remoralises +remoralizing, remoralising +renationalize, renationalise +renationalized, renationalised +renationalizes, renationalises +renationalizing, renationalising +rencounter, rencontre +Renferd's, Renfred's +Renferd, Renfred +renormalization's, renormalisation's +renormalization, renormalisation +renormalizations, renormalisations +renormalize, renormalise +renormalized, renormalised +renormalizes, renormalises +renormalizing, renormalising +reobjectivization's, reobjectivisation's +reobjectivization, reobjectivisation +reobjectivizations, reobjectivisations +reobjectivize, reobjectivise +reobjectivizes, reobjectivises +reorganization's, reorganisation's +reorganization, reorganisation +reorganizational, reorganisational +reorganizationist's, reorganisationist's +reorganizationist, reorganisationist +reorganizationists, reorganisationists +reorganizations, reorganisations +reorganize, reorganise +reorganized, reorganised +reorganizer's, reorganiser's +reorganizer, reorganiser +reorganizers, reorganisers +reorganizes, reorganises +reorganizing, reorganising +reoxidize, reoxidise +reoxidized, reoxidised +reoxidizes, reoxidises +reoxidizing, reoxidising +reoxygenize, reoxygenise +reoxygenizes, reoxygenises +repaganization's, repaganisation's +repaganization, repaganisation +repaganizations, repaganisations +repaganize, repaganise +repaganizer, repaganiser +repaganizers, repaganisers +repaganizes, repaganises +repatronize, repatronise +repatronizes, repatronises +repellent's, repellant's +repellent, repellant +repellents, repellants +repersonalize, repersonalise +rephosphorization's, rephosphorisation's +rephosphorization, rephosphorisation +rephosphorizations, rephosphorisations +rephosphorize, rephosphorise +rephosphorizes, rephosphorises +repolymerization's, repolymerisation's +repolymerization, repolymerisation +repolymerizations, repolymerisations +repolymerize, repolymerise +repolymerizes, repolymerises +repopularize, repopularise +reprivatization's, reprivatisation's +reprivatization, reprivatisation +reprivatizations, reprivatisations +reprivatize, reprivatise +reprivatized, reprivatised +reprivatizes, reprivatises +reprivatizing, reprivatising +reprized, reprised +reprogram, reprogramme +reprograms, reprogrammes +republicanization's, republicanisation's +republicanization, republicanisation +republicanizations, republicanisations +republicanize, republicanise +republicanized, republicanised +republicanizer's, republicaniser's +republicanizer, republicaniser +republicanizers, republicanisers +republicanizes, republicanises +republicanizing, republicanising +repulverize, repulverise +repulverizes, repulverises +reroyalize, reroyalise +reroyalizes, reroyalises +reseize, reseise +reseizer, reseiser +resensitization's, resensitisation's +resensitization, resensitisation +resensitizations, resensitisations +resensitize, resensitise +resensitizes, resensitises +resepulcher, resepulchre +resepulchers, resepulchres +reshes, reshoes +resinize, resinise +resinized, resinised +resinizes, resinises +resinizing, resinising +resolemnize, resolemnise +resolemnizes, resolemnises +respectabilize, respectabilise +respectabilized, respectabilised +respectabilizes, respectabilises +respectabilizing, respectabilising +restandardization's, restandardisation's +restandardization, restandardisation +restandardizations, restandardisations +restandardize, restandardise +restandardizes, restandardises +restaurateur's, restauranteur's +restaurateur, restauranteur +restaurateurs, restauranteurs +resterilize, resterilise +resterilizes, resterilises +restigmatize, restigmatise +restigmatizes, restigmatises +resurrectionize, resurrectionise +resurrectionized, resurrectionised +resurrectionizes, resurrectionises +resurrectionizing, resurrectionising +resymbolization's, resymbolisation's +resymbolization, resymbolisation +resymbolizations, resymbolisations +resymbolize, resymbolise +resymbolizes, resymbolises +resynchronization's, resynchronisation's +resynchronization, resynchronisation +resynchronizations, resynchronisations +resynchronize, resynchronise +resynchronized, resynchronised +resynchronizes, resynchronises +resynchronizing, resynchronising +resynthesize, resynthesise +resynthesizes, resynthesises +retinize, retinise +retinizes, retinises +retinule, retinulae +retranquilize, retranquilise +retranquilizes, retranquilises +retrocecal, retrocaecal +reutilization's, reutilisation's +reutilization, reutilisation +reutilize, reutilise +reutilized, reutilised +reutilizes, reutilises +reutilizing, reutilising +revalorization's, revalorisation's +revalorization, revalorisation +revalorizations, revalorisations +revalorize, revalorise +revalorized, revalorised +revalorizes, revalorises +revalorizing, revalorising +revaporization's, revapourisation's +revaporization, revapourisation +revaporizations, revapourisations +revaporize, revaporise +revaporizes, revaporises +revelationize, revelationise +revelationizes, revelationises +reveled, revelled +reveler's, reveller's +reveler, reveller +revelers, revellers +reveling, revelling +revelings, revellings +reverie's, revery's +reverie, revery +revigor, revigour +revisualization's, revisualisation's +revisualization, revisualisation +revisualizations, revisualisations +revisualize, revisualise +revisualizes, revisualises +revitalization's, revitalisation's +revitalization, revitalisation +revitalizations, revitalisations +revitalize, revitalise +revitalized, revitalised +revitalizer, revitaliser +revitalizers, revitalisers +revitalizes, revitalises +revitalizing, revitalising +revivalize, revivalise +revivalizes, revivalises +revocable, revokable +revolatilize, revolatilise +revolatilizes, revolatilises +revolutionize, revolutionise +revolutionized, revolutionised +revolutionizement's, revolutionisement's +revolutionizement, revolutionisement +revolutionizements, revolutionisements +revolutionizer's, revolutioniser's +revolutionizer, revolutioniser +revolutionizers, revolutionisers +revolutionizes, revolutionises +revolutionizing, revolutionising +Rexford's, Rexfourd's +Rexford, Rexfourd +rhaphe, rhaphae +rhapsodize, rhapsodise +rhapsodized, rhapsodised +rhapsodizes, rhapsodises +rhapsodizing, rhapsodising +rheadine, rhoeadine +rhebosis, rhaebosis +Rhetian's, Rhaetian's +Rhetian, Rhaetian +Rhetic, Rhaetic +rhetorize, rhetorise +rhetorized, rhetorised +rhetorizes, rhetorises +rhetorizing, rhetorising +rheumatize, rheumatise +rheumatized, rheumatised +rheumatizes, rheumatises +rheumatizing, rheumatising +rhinocele, rhinocoele +rhinocelian, rhinocoelian +rhinorrhea, rhinorrhoea +rhinorrheal, rhinorrhoeal +rhodanize, rhodanise +rhodanized, rhodanised +rhodanizes, rhodanises +rhodanizing, rhodanising +rhotacize, rhotacise +rhotacized, rhotacised +rhotacizes, rhotacises +rhotacizing, rhotacising +rhythmicize, rhythmicise +rhythmicizes, rhythmicises +rhythmizable's, rhythmisable's +rhythmizable, rhythmisable +rhythmizables, rhythmisables +rhythmization's, rhythmisation's +rhythmization, rhythmisation +rhythmizations, rhythmisations +rhythmize, rhythmise +rhythmized, rhythmised +rhythmizes, rhythmises +rhythmizing, rhythmising +rickshaw's, ricksha's +rickshaw, ricksha +rickshaws, rickshas +ridiculize, ridiculise +ridiculizes, ridiculises +rigidize, rigidise +rigidized, rigidised +rigidizes, rigidises +rigidizing, rigidising +rigmarole's, rigamarole's +rigmarole, rigamarole +rigmaroles, rigamaroles +rigor's, rigour's +rigor, rigour +rigorism's, rigourism's +rigorism, rigourism +rigorist's, rigourist's +rigorist, rigourist +rigoristic, rigouristic +rigors, rigours +riotize, riotise +riotizes, riotises +riposte's, ripost's +riposte, ripost +ripostes, riposts +ritornelle, ritournelle +ritornelles, ritournelles +ritualization's, ritualisation's +ritualization, ritualisation +ritualizations, ritualisations +ritualize, ritualise +ritualized, ritualised +ritualizes, ritualises +ritualizing, ritualising +rivaled, rivalled +rivaless's, rivalless's +rivaless, rivalless +rivalesses, rivallesses +rivaling, rivalling +rivalize, rivalise +rivalized, rivalised +rivalizes, rivalises +rivalizing, rivalising +robotization's, robotisation's +robotization, robotisation +robotizations, robotisations +robotize, robotise +robotized, robotised +robotizes, robotises +robotizing, robotising +roed, rooed +Roentgen, Rˆntgen +roentgenize, roentgenise +roer, rore +Romania's, Roumania's +Romania, Roumania +Romanias, Roumanias +Romanization's, Romanisation's +Romanization, Romanisation +Romanizations, Romanisations +Romanize, Romanise +romanize, romanise +Romanized, Romanised +romanized, romanised +Romanizer's, Romaniser's +Romanizer, Romaniser +Romanizers, Romanisers +Romanizes, Romanises +romanizes, romanises +Romanizing, Romanising +romanizing, romanising +romanticization's, romanticisation's +romanticization, romanticisation +romanticizations, romanticisations +romanticize, romanticise +romanticized, romanticised +romanticizes, romanticises +romanticizing, romanticising +ropy, ropey +routinization's, routinisation's +routinization, routinisation +routinizations, routinisations +routinize, routinise +routinized, routinised +routinizes, routinises +routinizing, routinising +roweled, rowelled +roweling, rowelling +royalization's, royalisation's +royalization, royalisation +royalizations, royalisations +royalize, royalise +royalized, royalised +royalizes, royalises +royalizing, royalising +rubberization, rubberisation +rubberize, rubberise +rubberized, rubberised +rubberizes, rubberises +rubberizing, rubberising +ruble's, rouble's +ruble, rouble +rubles, roubles +rubricize, rubricise +rubricizes, rubricises +ruffianize, ruffianise +ruffianizes, ruffianises +ruggedization's, ruggedisation's +ruggedization, ruggedisation +ruggedizations, ruggedisations +ruggedize, ruggedise +ruggedized, ruggedised +ruggedizes, ruggedises +ruggedizing, ruggedising +rumor's, rumour's +rumor, rumour +rumored, rumoured +rumorer's, rumourer's +rumorer, rumourer +rumorers, rumourers +rumoring, rumouring +rumormonger's, rumourmonger's +rumormonger, rumourmonger +rumormongers, rumourmongers +rumors, rumours +ruralization's, ruralisation's +ruralization, ruralisation +ruralizations, ruralisations +ruralize, ruralise +ruralized, ruralised +ruralizes, ruralises +ruralizing, ruralising +Russianization's, Russianisation's +Russianization, Russianisation +russianization, russianisation +Russianizations, Russianisations +Russianize, Russianise +russianize, russianise +Russianized, Russianised +Russianizes, Russianises +Russianizing, Russianising +rusticize, rusticise +rusticized, rusticised +rusticizes, rusticises +rusticizing, rusticising +Sabbathize's, Sabbathise's +Sabbathize, Sabbathise +Sabbathizes, Sabbathises +sabbatize, sabbatise +sabbatized, sabbatised +sabbatizes, sabbatises +sabbatizing, sabbatising +Sabean, Sabaean +Sabeans, Sabaeans +saber's, sabre's +saber, sabre +saberbill, sabrebill +sabered, sabred +sabering, sabring +saberlike's, sabrelike's +saberlike, sabrelike +saberlikes, sabrelikes +sabers, sabres +sabertooth, sabretooth +saccharization, saccharisation +saccharizations, saccharisations +saccharize, saccharise +saccharized, saccharised +saccharizes, saccharises +saccharizing, saccharising +sacerdotalize, sacerdotalise +sacerdotalized, sacerdotalised +sacerdotalizes, sacerdotalises +sacerdotalizing, sacerdotalising +sacralization's, sacralisation's +sacralization, sacralisation +sacralizations, sacralisations +sacralize, sacralise +sacralized, sacralised +sacralizes, sacralises +sacralizing, sacralising +sacramentize, sacramentise +sacramentizes, sacramentises +Safier's, Safire's +Safier, Safire +sailorizing's, sailorising's +sailorizing, sailorising +sailorizings, sailorisings +sake's, saki's +sake, saki +sakes, sakis +salable, saleable +salabler, saleabler +salablest, saleablest +salinization, salinisation +salinize, salinise +salinizes, salinises +saltiers, saltires +saltierwise, saltirewise +saltpeter's, saltpetre's +saltpeter, saltpetre +saltpeters, saltpetres +sanctuarize, sanctuarise +sanctuarized, sanctuarised +sanctuarizes, sanctuarises +sanctuarizing, sanctuarising +sandaled, sandalled +sandaling, sandalling +Sanferd's, Sanfred's +Sanferd, Sanfred +Sanforize, Sanforise +Sanforizes, Sanforises +Sanforizing, Sanforising +sanitization's, sanitisation's +sanitization, sanitisation +sanitizations, sanitisations +sanitize, sanitise +sanitized, sanitised +sanitizer's, sanitiser's +sanitizer, sanitiser +sanitizers, sanitisers +sanitizes, sanitises +sanitizing, sanitising +Sanskritize's, Sanskritise's +Sanskritize, Sanskritise +sapientize, sapientise +sapientizes, sapientises +sapor, sapour +sapors, sapours +sapremia's, sapraemia's +sapremia, sapraemia +sapremias, sapraemias +sapremic, sapraemic +sarcine, sarcinae +sari's, saree's +sari, saree +saris, sarees +Sassanide, Sassanidae +satanize, satanise +satanizes, satanises +satellitize, satellitise +satellitized, satellitised +satellitizes, satellitises +satellitizing, satellitising +satinize, satinise +satinizes, satinises +satirizable's, satirisable's +satirizable, satirisable +satirizables, satirisables +satirization, satirisation +satirize, satirise +satirized, satirised +satirizer's, satiriser's +satirizer, satiriser +satirizers, satirisers +satirizes, satirises +satirizing, satirising +sative, sativae +savable, saveable +savagize, savagise +savagizes, savagises +savanna's, savannah's +savanna, savannah +savannas, savannahes +savior's, saviour's +savior, saviour +savioress, saviouress +saviorhood's, saviourhood's +saviorhood, saviourhood +saviorhoods, saviourhoods +saviors, saviours +saviorship's, saviourship's +saviorship, saviourship +saviorships, saviourships +savor's, savour's +savor, savour +savored, savoured +savorer's, savourer's +savorer, savourer +savorers, savourers +savorier, savourier +savories, savouries +savoriest, savouriest +savorilies, savourilies +savorily, savourily +savoriness's, savouriness's +savoriness, savouriness +savorinesses, savourinesses +savoring, savouring +savoringlier, savouringlier +savoringlies, savouringlies +savoringliest, savouringliest +savoringly, savouringly +savorless, savourless +savorlesser, savourlesser +savorlesses, savourlesses +savorlessest, savourlessest +savorly, savourly +savorous, savourous +savorouser, savourouser +savorousest, savourousest +savors, savours +savory's, savoury's +savory, savoury +Saxonization's, Saxonisation's +Saxonization, Saxonisation +Saxonizations, Saxonisations +Saxonize's, Saxonise's +Saxonize, Saxonise +Saxonized's, Saxonised's +Saxonized, Saxonised +Saxonizes, Saxonises +Saxonizing's, Saxonising's +Saxonizing, Saxonising +scalawag's, scallywag's +scalawag, scallywag +scalawags, scallywags +scallop's, scollop's +scallop, scollop +scalloped, scolloped +scalloping, scolloping +scallops, scollops +scandaled, scandalled +scandaling, scandalling +scandalization's, scandalisation's +scandalization, scandalisation +scandalizations, scandalisations +scandalize, scandalise +scandalized, scandalised +scandalizer's, scandaliser's +scandalizer, scandaliser +scandalizers, scandalisers +scandalizes, scandalises +scandalizing, scandalising +scaped, scapaed +scary, scarey +scena, scaena +scenarioization's, scenarioisation's +scenarioization, scenarioisation +scenarioizations, scenarioisations +scenarioize, scenarioise +scenarioizes, scenarioises +scenarization's, scenarisation's +scenarization, scenarisation +scenarizations, scenarisations +scenarize, scenarise +scenarized, scenarised +scenarizes, scenarises +scenarizing, scenarising +scepter's, sceptre's +scepter, sceptre +scepterdom, sceptredom +sceptered, sceptred +sceptering, sceptring +scepterless, sceptreless +scepterlesses, sceptrelesses +scepters, sceptres +Scevor's, Scevour's +Scevor, Scevour +schedulize, schedulise +schedulizes, schedulises +schemata, schemas +schematization's, schematisation's +schematization, schematisation +schematizations, schematisations +schematize, schematise +schematized, schematised +schematizer, schematiser +schematizers, schematisers +schematizes, schematises +schematizing, schematising +schillerization, schillerisation +schillerizations, schillerisations +schillerize, schillerise +schillerized, schillerised +schillerizes, schillerises +schillerizing, schillerising +schismatize, schismatise +schismatized, schismatised +schismatizes, schismatises +schismatizing, schismatising +schistocelia, schistocoelia +schlemiel's, shlemiel's +schlemiel, shlemiel +schlemiels, shlemiels +schlepped, shlepped +schlepping, shlepping +schmaltzy, schmalzy +schmalz's, shmaltz's +schmalz, shmaltz +schmalzes, shmaltzes +schmo's, schmoe's +schmo, schmoe +schnapps's, schnaps's +schnapps, schnaps +schtick's, shtik's +scientize, scientise +scientized, scientised +scientizes, scientises +scientizing, scientising +sclere, sclerae +sclerotization's, sclerotisation's +sclerotization, sclerotisation +sclerotize, sclerotise +sclerotized, sclerotised +sclerotizes, sclerotises +sclerotizing, sclerotising +scorse, scourse +scorsed, scoursed +scorses, scourses +scorsing, scoursing +Scotticize's, Scotticise's +Scotticize, Scotticise +Scotticized's, Scotticised's +Scotticized, Scotticised +Scotticizes, Scotticises +Scotticizing's, Scotticising's +Scotticizing, Scotticising +scripturalize, scripturalise +scripturalizes, scripturalises +scrod's, schrod's +scrod, schrod +scrods, schrods +scrunchy's, scrunchie's +scrunchy, scrunchie +scrutinization's, scrutinisation's +scrutinization, scrutinisation +scrutinizations, scrutinisations +scrutinize, scrutinise +scrutinized, scrutinised +scrutinizer's, scrutiniser's +scrutinizer, scrutiniser +scrutinizers, scrutinisers +scrutinizes, scrutinises +scrutinizing, scrutinising +scrutinizinglies, scrutinisinglies +scrutinizingly, scrutinisingly +se, sae +se, soe +seborrhea's, seborrhoea's +seborrhea, seborrhoea +seborrheas, seborrhoeas +seborrheic, seborrhoeic +sectarianization, sectarianisation +sectarianize, sectarianise +sectarianized, sectarianised +sectarianizes, sectarianises +sectarianizing, sectarianising +sectionalization's, sectionalisation's +sectionalization, sectionalisation +sectionalizations, sectionalisations +sectionalize, sectionalise +sectionalized, sectionalised +sectionalizes, sectionalises +sectionalizing, sectionalising +sectionization, sectionisation +sectionizations, sectionisations +sectionize, sectionise +sectionized, sectionised +sectionizes, sectionises +sectionizing, sectionising +sectorization, sectorisation +sectorizations, sectorisations +sectorize, sectorise +sectorized, sectorised +sectorizes, sectorises +sectorizing, sectorising +secularization's, secularisation's +secularization, secularisation +secularizations, secularisations +secularize, secularise +secularized, secularised +secularizer's, seculariser's +secularizer, seculariser +secularizers, secularisers +secularizes, secularises +secularizing, secularising +seculum, saeculum +seculums, saeculums +securitization, securitisation +securitizations, securitisations +securitize, securitise +securitized, securitised +securitizes, securitises +securitizing, securitising +Seed's, Saeed's +Seed, Saeed +seizable, seisable +seizer's, seiser's +seizer, seiser +seizers, seisers +seizin's, seisin's +seizin, seisin +seizings, seisings +seizins, seisins +selle, sellae +selvage's, selvedge's +selvage, selvedge +selvages, selvedges +Semenov's, Semaenov's +Semenov, Semaenov +semianesthetic, semianaesthetic +semicarbonize, semicarbonise +semicarbonizes, semicarbonises +semicivilization's, semicivilisation's +semicivilization, semicivilisation +semicivilizations, semicivilisations +semicivilized's, semicivilised's +semicivilized, semicivilised +semicivilizeds, semiciviliseds +semifossilized's, semifossilised's +semifossilized, semifossilised +semifossilizeds, semifossiliseds +semihonor's, semihonour's +semihonor, semihonour +semihonors, semihonours +semihumanized's, semihumanised's +semihumanized, semihumanised +semihumanizeds, semihumaniseds +semimercerized's, semimercerised's +semimercerized, semimercerised +semimercerizeds, semimerceriseds +semimineralized's, semimineralised's +semimineralized, semimineralised +semimineralizeds, semimineraliseds +seminarize, seminarise +seminarizes, seminarises +seminationalization's, seminationalisation's +seminationalization, seminationalisation +seminationalizations, seminationalisations +semiorganized's, semiorganised's +semiorganized, semiorganised +semiorganizeds, semiorganiseds +semioxidized's, semioxidised's +semioxidized, semioxidised +semioxidizeds, semioxidiseds +semioxygenized's, semioxygenised's +semioxygenized, semioxygenised +semioxygenizeds, semioxygeniseds +semiprofessionalized's, semiprofessionalised's +semiprofessionalized, semiprofessionalised +semiprofessionalizeds, semiprofessionaliseds +semite, semitae +Semiticize's, Semiticise's +Semiticize, Semiticise +Semiticizes, Semiticises +Semitization's, Semitisation's +Semitization, Semitisation +Semitizations, Semitisations +Semitize's, Semitise's +Semitize, Semitise +Semitized's, Semitised's +Semitized, Semitised +Semitizes, Semitises +Semitizing's, Semitising's +Semitizing, Semitising +semivulcanized's, semivulcanised's +semivulcanized, semivulcanised +semivulcanizeds, semivulcaniseds +semper, sempre +senilize, senilise +senilizes, senilises +sensationalize, sensationalise +sensationalized, sensationalised +sensationalizes, sensationalises +sensationalizing, sensationalising +sensitization's, sensitisation's +sensitization, sensitisation +sensitizations, sensitisations +sensitize, sensitise +sensitized, sensitised +sensitizer's, sensitiser's +sensitizer, sensitiser +sensitizers, sensitisers +sensitizes, sensitises +sensitizing, sensitising +sensize, sensise +sensizes, sensises +sensualization's, sensualisation's +sensualization, sensualisation +sensualizations, sensualisations +sensualize, sensualise +sensualized, sensualised +sensualizes, sensualises +sensualizing, sensualising +sentimentalization's, sentimentalisation's +sentimentalization, sentimentalisation +sentimentalizations, sentimentalisations +sentimentalize, sentimentalise +sentimentalized, sentimentalised +sentimentalizer, sentimentaliser +sentimentalizers, sentimentalisers +sentimentalizes, sentimentalises +sentimentalizing, sentimentalising +sentineled, sentinelled +sentineling, sentinelling +sepaled, sepalled +sepaledder, sepalledder +sepaleddest, sepalleddest +Septembrizer's, Septembriser's +Septembrizer, Septembriser +Septembrizers, Septembrisers +septemia, septaemia +septet's, septette's +septet, septette +septets, septettes +septicemia's, septicaemia's +septicemia, septicaemia +septicemias, septicaemias +septicemic, septicaemic +septicization's, septicisation's +septicization, septicisation +septicizations, septicisations +septicolored, septicoloured +sepulcher's, sepulchre's +sepulcher, sepulchre +sepulchered, sepulchred +sepulchering, sepulchring +sepulchers, sepulchres +sepulchralize, sepulchralise +sepulchralizes, sepulchralises +sequentialize, sequentialise +sequentialized, sequentialised +sequentializes, sequentialises +sequentializing, sequentialising +serape's, sarape's +serape, sarape +serapes, sarapes +serenize, serenise +serenizes, serenises +serializability, serialisability +serializable, serialisable +serialization's, serialisation's +serialization, serialisation +serializations, serialisations +serialize, serialise +serialized, serialised +serializes, serialises +serializing, serialising +sericitization, sericitisation +sericitizations, sericitisations +sermonize, sermonise +sermonized, sermonised +sermonizer's, sermoniser's +sermonizer, sermoniser +sermonizers, sermonisers +sermonizes, sermonises +sermonizing, sermonising +serose, serosae +serpentinization's, serpentinisation's +serpentinization, serpentinisation +serpentinizations, serpentinisations +serpentinize, serpentinise +serpentinized, serpentinised +serpentinizes, serpentinises +serpentinizing, serpentinising +serpentize, serpentise +serpentized, serpentised +serpentizes, serpentises +serpentizing, serpentising +serre, serrae +servilize, servilise +servilizes, servilises +seta, saeta +setule, setulae +severalize, severalise +severalizes, severalises +severization's, severisation's +severization, severisation +severizations, severisations +severize, severise +severizes, severises +sextet's, sextette's +sextet, sextette +sextets, sextettes +sexualization's, sexualisation's +sexualization, sexualisation +sexualizations, sexualisations +sexualize, sexualise +sexualized, sexualised +sexualizes, sexualises +sexualizing, sexualising +Shakespearize's, Shakespearise's +Shakespearize, Shakespearise +Shakespearizes, Shakespearises +shammy's, chammy's +shammy, chammy +shareable, sharable +sharpie's, sharpy's +sharpie, sharpy +sheikdom's, sheikhdom's +sheikdom, sheikhdom +sheikdoms, sheikhdoms +shellac's, shellack's +shellac, shellack +shellacs, shellacks +shepherdize, shepherdise +shepherdizes, shepherdises +sher, shoer +sherardize, sherardise +sherardized, sherardised +sherardizes, sherardises +sherardizing, sherardising +sherbet's, sherbert's +sherbet, sherbert +sherbets, sherberts +Shere's, Shree's +Shere, Shree +shere, shree +shillelagh's, shillalah's +shillelagh, shillalah +shillelaghes, shillalahes +Shintoize's, Shintoise's +Shintoize, Shintoise +Shintoizes, Shintoises +Shkoder's, Shkodaer's +Shkoder, Shkodaer +shlep, shlepp +shlepp's, shlep's +shleps, shlepps +shlock, shlocky +shorty's, shortie's +shorty, shortie +shoveled, shovelled +shoveler's, shoveller's +shoveler, shoveller +shovelers, shovellers +shoveling, shovelling +shriveled, shrivelled +shriveling, shrivelling +shtik, schtick +shtiks, schticks +sialorrhea, sialorrhoea +siderealize, siderealise +siderealizes, siderealises +signaled, signalled +signaler's, signaller's +signaler, signaller +signalers, signallers +signaling, signalling +signalization, signalisation +signalize, signalise +signalized, signalised +signalizes, signalises +signalizing, signalising +siled, siloed +silicatization's, silicatisation's +silicatization, silicatisation +silicatizations, silicatisations +siliceous, silicious +silicidize, silicidise +silicidizes, silicidises +siliconize, siliconise +siliconizes, siliconises +silicule, siliculae +silique, siliquae +silverize, silverise +silverized, silverised +silverizer's, silveriser's +silverizer, silveriser +silverizers, silverisers +silverizes, silverises +silverizing, silverising +similarize, similarise +similarizes, similarises +similize, similise +similized, similised +similizes, similises +similizing, similising +simonize, simonise +Sine's, Sinae's +Sine, Sinae +singularization's, singularisation's +singularization, singularisation +singularizations, singularisations +singularize, singularise +singularized, singularised +singularizes, singularises +singularizing, singularising +sinicize, sinicise +sinicized, sinicised +sinicizes, sinicises +sinicizing, sinicising +siphon's, syphon's +siphon, syphon +siphoned, syphoned +siphoning, syphoning +siphonless, syphonless +siphonlesses, syphonlesses +siphonlike's, syphonlike's +siphonlike, syphonlike +siphonlikes, syphonlikes +siphonophore's, syphonophore's +siphonophore, syphonophore +siphonostele's, syphonostele's +siphonostele, syphonostele +siphonostelic, syphonostelic +siphonostely, syphonostely +siphons, syphons +sirenize, sirenise +sirenized, sirenised +sirenizes, sirenises +sirenizing, sirenising +sirree's, siree's +sirree, siree +sirrees, sirees +sisterize, sisterise +sisterizes, sisterises +sistern, sistren +sizable, sizeable +sizableness, sizeableness +sizably, sizeably +sizel, sisel +skeer, skere +skeletonization's, skeletonisation's +skeletonization, skeletonisation +skeletonizations, skeletonisations +skeletonize, skeletonise +skeletonized, skeletonised +skeletonizer's, skeletoniser's +skeletonizer, skeletoniser +skeletonizers, skeletonisers +skeletonizes, skeletonises +skeletonizing, skeletonising +skeptic's, sceptic's +skeptic, sceptic +skeptical, sceptical +skepticaler, scepticaler +skepticalest, scepticalest +skeptically, sceptically +skepticer, scepticer +skepticest, scepticest +skepticism's, scepticism's +skepticism, scepticism +skepticisms, scepticisms +skepticize, skepticise +skepticizes, skepticises +skeptics, sceptics +skillful, skilful +skillfully, skilfully +skillfulness's, skilfulness's +skillfulness, skilfulness +skulduggery's, skullduggery's +skulduggery, skullduggery +skyer, skyre +skyers, skyres +Slavicize's, Slavicise's +Slavicize, Slavicise +Slavicizes, Slavicises +Slavization's, Slavisation's +Slavization, Slavisation +Slavizations, Slavisations +Slavize's, Slavise's +Slavize, Slavise +Slavizes, Slavises +Slavonicize's, Slavonicise's +Slavonicize, Slavonicise +Slavonicized's, Slavonicised's +Slavonicized, Slavonicised +Slavonicizes, Slavonicises +Slavonicizing's, Slavonicising's +Slavonicizing, Slavonicising +Slavonize's, Slavonise's +Slavonize, Slavonise +Slavonized's, Slavonised's +Slavonized, Slavonised +Slavonizes, Slavonises +Slavonizing's, Slavonising's +Slavonizing, Slavonising +sle, slae +slenderize, slenderise +slenderized, slenderised +slenderizes, slenderises +slenderizing, slenderising +slier, slyer +sliest, slyest +sloganize, sloganise +sloganized, sloganised +sloganizes, sloganises +sloganizing, sloganising +sloganizings, sloganisings +sluggardize, sluggardise +sluggardized, sluggardised +sluggardizes, sluggardises +sluggardizing, sluggardising +slumberous, slumbrous +slyly, slily +smidge's, smidgin's +smidge, smidgin +smidges, smidgins +smolder's, smoulder's +smolder, smoulder +smoldered, smouldered +smoldering, smouldering +smolders, smoulders +smoothie's, smoothy's +smoothie, smoothy +sniveled, snivelled +sniveler's, sniveller's +sniveler, sniveller +snivelers, snivellers +sniveling, snivelling +snivelings, snivellings +snobsniveling, snobsnivelling +snorkeled, snorkelled +snorkeling, snorkelling +snowplow's, snowplough's +snowplow, snowplough +snowplows, snowploughs +snowshed, snowshoed +snuffcolored, snuffcoloured +soberize, soberise +soberized, soberised +soberizes, soberises +soberizing, soberising +sobriquet's, soubriquet's +sobriquet, soubriquet +sobriquets, soubriquets +socialization's, socialisation's +socialization, socialisation +socializations, socialisations +socialize, socialise +socialized, socialised +socializer's, socialiser's +socializer, socialiser +socializes, socialises +socializing, socialising +sockdologizing, sockdologising +Socratize's, Socratise's +Socratize, Socratise +Socratized's, Socratised's +Socratized, Socratised +Socratizes, Socratises +Socratizing's, Socratising's +Socratizing, Socratising +sodomize, sodomise +sodomized, sodomised +sodomizes, sodomises +sodomizing, sodomising +softy's, softie's +softy, softie +sol's, so's +sol, so +solarization's, solarisation's +solarization, solarisation +solarizations, solarisations +solarize, solarise +solarized, solarised +solarizes, solarises +solarizing, solarising +soldierize, soldierise +soldierizes, soldierises +solecize, solecise +solecized, solecised +solecizes, solecises +solecizing, solecising +solemnization's, solemnisation's +solemnization, solemnisation +solemnizations, solemnisations +solemnize, solemnise +solemnized, solemnised +solemnizer's, solemniser's +solemnizer, solemniser +solemnizers, solemnisers +solemnizes, solemnises +solemnizing, solemnising +soliloquization, soliloquisation +soliloquize, soliloquise +soliloquized, soliloquised +soliloquizer's, soliloquiser's +soliloquizer, soliloquiser +soliloquizers, soliloquisers +soliloquizes, soliloquises +soliloquizing's, soliloquising's +soliloquizing, soliloquising +soliloquizingly, soliloquisingly +soliloquizings, soliloquisings +solmization's, solmisation's +solmization, solmisation +solmizations, solmisations +solonization, solonisation +solonizations, solonisations +sols, sos +solubilization's, solubilisation's +solubilization, solubilisation +solubilizations, solubilisations +solubilize, solubilise +solubilized, solubilised +solubilizes, solubilises +solubilizing, solubilising +solutize, solutise +solutizer's, solutiser's +solutizer, solutiser +solutizers, solutisers +solutizes, solutises +somber, sombre +somberer, sombrer +somberest, sombrest +somberish, sombreish +somberly, sombrely +somberness's, sombreness's +somberness, sombreness +sombernesses, sombrenesses +somesthesia, somaesthesia +somesthesis, somaesthesis +somniloquize, somniloquise +somniloquized, somniloquised +somniloquizes, somniloquises +somniloquizing, somniloquising +sonantized's, sonantised's +sonantized, sonantised +sonantizeds, sonantiseds +sonnetization's, sonnetisation's +sonnetization, sonnetisation +sonnetize, sonnetise +sonnetized, sonnetised +sonnetizes, sonnetises +sonnetizing, sonnetising +sorbitization, sorbitisation +sorbitizations, sorbitisations +sorbitize, sorbitise +sorbitized, sorbitised +sorbitizes, sorbitises +sorbitizing, sorbitising +sord, sourd +sordine, sourdine +sordines, sourdines +sororize, sororise +sororized, sororised +sororizes, sororises +sororizing, sororising +sory, soury +souffled, soufflaed +soulter, soultre +southernize, southernise +southernized, southernised +southernizes, southernises +southernizing, southernising +Sovietization's, Sovietisation's +sovietization's, sovietisation's +Sovietization, Sovietisation +sovietization, sovietisation +sovietizations, sovietisations +Sovietize, Sovietise +sovietize, sovietise +Sovietized, Sovietised +sovietized, sovietised +sovietizes, sovietises +Sovietizing, Sovietising +sovietizing, sovietising +spacey, spacy +spanemia, spanaemia +spanemic, spanaemic +Spaniardization's, Spaniardisation's +Spaniardization, Spaniardisation +Spaniardizations, Spaniardisations +Spaniardize's, Spaniardise's +Spaniardize, Spaniardise +Spaniardizes, Spaniardises +spaniolize, spaniolise +spaniolized, spaniolised +spaniolizes, spaniolises +spaniolizing, spaniolising +Spanishize's, Spanishise's +Spanishize, Spanishise +Spanishizes, Spanishises +spanopnea, spanopnoea +sparers, sparres +Spartanize's, Spartanise's +Spartanize, Spartanise +Spartanizes, Spartanises +spatialization's, spatialisation's +spatialization, spatialisation +spatializations, spatialisations +spatialize, spatialise +spatializes, spatialises +specialization's, specialisation's +specialization, specialisation +specializations, specialisations +specialize, specialise +specialized, specialised +specializer's, specialiser's +specializer, specialiser +specializers, specialisers +specializes, specialises +specializing, specialising +specialties, specialities +specialty's, speciality's +specialty, speciality +specificize, specificise +specificizes, specificises +specimenize, specimenise +specimenizes, specimenises +specter's, spectre's +specter, spectre +spectered, spectred +specterlike's, spectrelike's +specterlike, spectrelike +specterlikes, spectrelikes +specters, spectres +spectrocolorimetry's, spectrocolourimetry's +spectrocolorimetry, spectrocolourimetry +speer's, spere's +speer, spere +spelean, spelaean +speleological, spelaeological +speleothem, spelaeothem +speleothems, spelaeothems +spermatorrhea, spermatorrhoea +spermatorrheas, spermatorrhoeas +speronares, speronaroes +sphenethmoid, sphenoethmoid +sphenethmoidal, sphenoethmoidal +spherocrystal, sphaerocrystal +spheroidization, spheroidisation +spheroidizations, spheroidisations +spheroidize, spheroidise +spheroidized, spheroidised +spheroidizes, spheroidises +spheroidizing, spheroidising +spherosome, sphaerosome +spick's, spik's +spick, spik +spicks, spiks +Spiers's, Spires's +Spiers, Spires +spilled, spilt +spinule, spinulae +spiraled, spiralled +spiraling, spiralling +spiralization's, spiralisation's +spiralization, spiralisation +spiralizations, spiralisations +spiralize, spiralise +spiralizes, spiralises +spirea's, spiraea's +spirea, spiraea +spireas, spiraeas +spiritize, spiritise +spiritizes, spiritises +spiritualization's, spiritualisation's +spiritualization, spiritualisation +spiritualizations, spiritualisations +spiritualize, spiritualise +spiritualized, spiritualised +spiritualizer's, spiritualiser's +spiritualizer, spiritualiser +spiritualizers, spiritualisers +spiritualizes, spiritualises +spiritualizing, spiritualising +spirochetal, spirochaetal +spirochete's, spirochaete's +spirochete, spirochaete +spirochetes, spirochaetes +spirochetoses, spirochaetoses +spirochetosis's, spirochaetosis's +spirochetosis, spirochaetosis +spirochetotic, spirochaetotic +splanchnocele, splanchnocoele +splendor's, splendour's +splendor, splendour +splendorproof, splendourproof +splendors, splendours +splenectomized, splenectomised +splenization, splenisation +splenizations, splenisations +spoiled, spoilt +sponge_cake's, spongecake's +sponge_cake, spongecake +sponge_cakes, spongecakes +spumoni's, spumone's +spumoni, spumone +spumonis, spumones +spyer, spyre +squame, squamae +squamule, squamulae +Squier's, Squire's +Squier, Squire +squirreled, squirrelled +squirreling, squirrelling +stabilizable, stabilisable +stabilization's, stabilisation's +stabilization, stabilisation +stabilizations, stabilisations +stabilizator, stabilisator +stabilizators, stabilisators +stabilize, stabilise +stabilized, stabilised +stabilizer's, stabiliser's +stabilizer, stabiliser +stabilizers, stabilisers +stabilizes, stabilises +stabilizing, stabilising +stagy, stagey +stallionize, stallionise +stallionizes, stallionises +stalwartize, stalwartise +stalwartizes, stalwartises +stammelcolor, stammelcolour +standardizable's, standardisable's +standardizable, standardisable +standardizables, standardisables +standardization's, standardisation's +standardization, standardisation +standardizations, standardisations +standardize, standardise +standardized, standardised +standardizer's, standardiser's +standardizer, standardiser +standardizers, standardisers +standardizes, standardises +standardizing, standardising +stanzes, stanzoes +stapedectomized, stapedectomised +staphyledema, staphyloedema +statisticize, statisticise +statisticizes, statisticises +stearrhea, stearrhoea +steatorrhea, steatorrhoea +steatorrheas, steatorrhoeas +stele, stelae +stenciled, stencilled +stenciler's, stenciller's +stenciler, stenciller +stencilers, stencillers +stenciling, stencilling +stencilize, stencilise +stenopeic, stenopaeic +stentor, stentour +stentors, stentours +stercoremia, stercoraemia +stere, stree +sterilizabilities, sterilisabilities +sterilizability's, sterilisability's +sterilizability, sterilisability +sterilizable's, sterilisable's +sterilizable, sterilisable +sterilizabler, sterilisabler +sterilizables, sterilisables +sterilizablest, sterilisablest +sterilization's, sterilisation's +sterilization, sterilisation +sterilizations, sterilisations +sterilize, sterilise +sterilized, sterilised +sterilizer's, steriliser's +sterilizer, steriliser +sterilizers, sterilisers +sterilizes, sterilises +sterilizing, sterilising +stert, stret +sties, styes +stigmatization's, stigmatisation's +stigmatization, stigmatisation +stigmatizations, stigmatisations +stigmatize, stigmatise +stigmatized, stigmatised +stigmatizer's, stigmatiser's +stigmatizer, stigmatiser +stigmatizers, stigmatisers +stigmatizes, stigmatises +stigmatizing, stigmatising +stilbestrol's, stilboestrol's +stilbestrol, stilboestrol +stilbestrols, stilboestrols +stimuli, stimuluses +stipule, stipulae +stockinette's, stockinet's +stockinette, stockinet +stockinettes, stockinets +stogie's, stogy's +stogie, stogy +stomatodeum, stomatodaeum +stomodea, stomodaea +stomodeal, stomodaeal +stomodeum's, stomodaeum's +stomodeum, stomodaeum +stomodeums, stomodaeums +stony, stoney +storier, stourier +stour, stoor +stower, stowre +stowers, stowres +straitjacket's, straightjacket's +straitjacket, straightjacket +straitjacketed, straightjacketed +straitjacketing, straightjacketing +straitjackets, straightjackets +strata, stratums +strobile, strobilae +strobilization's, strobilisation's +strobilization, strobilisation +strobilizations, strobilisations +structuralization's, structuralisation's +structuralization, structuralisation +structuralizations, structuralisations +structuralize, structuralise +structuralizes, structuralises +strychninization's, strychninisation's +strychninization, strychninisation +strychninizations, strychninisations +strychninize, strychninise +strychninizes, strychninises +stumor, stumour +sty's, stye's +sty, stye +stylization's, stylisation's +stylization, stylisation +stylizations, stylisations +stylize, stylise +stylized, stylised +stylizer's, styliser's +stylizer, styliser +stylizers, stylisers +stylizes, stylises +stylizing, stylising +stylopized, stylopised +stymie's, stymy's +stymie, stymy +stymied, stymyed +subarmor's, subarmour's +subarmor, subarmour +subarmors, subarmours +subcaliber, subcalibre +subcategorizing, subcategorising +subcenter, subcentre +subduer, subdure +suberate, subaerate +suberization's, suberisation's +suberization, suberisation +suberizations, suberisations +suberize, suberise +suberized, suberised +suberizes, suberises +suberizing, suberising +subesophageal, suboesophageal +subetheric, subaetheric +subflavor's, subflavour's +subflavor, subflavour +subflavors, subflavours +subitize, subitise +subitized, subitised +subitizes, subitises +subitizing, subitising +subjectivization's, subjectivisation's +subjectivization, subjectivisation +subjectivizations, subjectivisations +subjectivize, subjectivise +subjectivized, subjectivised +subjectivizes, subjectivises +subjectivizing, subjectivising +sublimize, sublimise +sublimized, sublimised +sublimizes, sublimises +sublimizing, sublimising +subminiaturization's, subminiaturisation's +subminiaturization, subminiaturisation +subminiaturize, subminiaturise +subminiaturized, subminiaturised +subminiaturizes, subminiaturises +subminiaturizing, subminiaturising +subpoena's, subpena's +subpoena, subpena +subpoenaed, subpenaed +subpoenaing, subpenaing +subpoenas, subpenas +subpulverizer's, subpulveriser's +subpulverizer, subpulveriser +subpulverizers, subpulverisers +subsidizable's, subsidisable's +subsidizable, subsidisable +subsidizables, subsidisables +subsidization's, subsidisation's +subsidization, subsidisation +subsidizations, subsidisations +subsidize, subsidise +subsidized, subsidised +subsidizer's, subsidiser's +subsidizer, subsidiser +subsidizers, subsidisers +subsidizes, subsidises +subsidizing, subsidising +subspecialize's, subspecialise's +subspecialize, subspecialise +subspecializes, subspecialises +subspecialties, subspecialities +subspecialty's, subspeciality's +subspecialty, subspeciality +substandardize, substandardise +substandardizes, substandardises +substantialize, substantialise +substantialized, substantialised +substantializes, substantialises +substantializing, substantialising +substantivize, substantivise +substantivized, substantivised +substantivizes, substantivises +substantivizing, substantivising +substerilization, substerilisation +subterraneanize, subterraneanise +subterraneanizes, subterraneanises +subtilization's, subtilisation's +subtilization, subtilisation +subtilizations, subtilisations +subtilize, subtilise +subtilized, subtilised +subtilizer, subtiliser +subtilizers, subtilisers +subtilizes, subtilises +subtilizing, subtilising +subtotaled, subtotalled +subtotaling, subtotalling +suburbanization's, suburbanisation's +suburbanization, suburbanisation +suburbanizations, suburbanisations +suburbanize, suburbanise +suburbanized, suburbanised +suburbanizes, suburbanises +suburbanizing, suburbanising +subvitalization's, subvitalisation's +subvitalization, subvitalisation +subvitalized's, subvitalised's +subvitalized, subvitalised +subvitalizedder, subvitalisedder +subvitalizeddest, subvitaliseddest +subvitalizeds, subvitaliseds +succor's, succour's +succor, succour +succorable's, succourable's +succorable, succourable +succorables, succourables +succored, succoured +succorer's, succourer's +succorer, succourer +succorers, succourers +succorful, succourful +succoring, succouring +succorless, succourless +succorlesses, succourlesses +succorrhea, succorrhoea +succors, succours +succube, succubae +suers, sures +suggestionize, suggestionise +suggestionizes, suggestionises +sulcalize, sulcalise +sulcalized, sulcalised +sulcalizes, sulcalises +sulcalizing, sulcalising +sulfate's, sulphate's +sulfate, sulphate +sulfates, sulphates +sulfatize, sulfatise +sulfatizes, sulfatises +sulfide's, sulphide's +sulfide, sulphide +sulfides, sulphides +sulfur's, sulphur's +sulfur, sulphur +sulfured, sulphured +sulfuric, sulphuric +sulfuring, sulphuring +sulfurous, sulphurous +sulfurs, sulphurs +sulphurisation's, sulphurization's +sulphurisation, sulphurization +sulphurisations, sulphurizations +sulphurise, sulphurize +sulphurised, sulphurized +sulphurises, sulphurizes +sulphurising, sulphurizing +sultanize, sultanise +sultanizes, sultanises +sumac's, sumach's +sumac, sumach +sumacs, sumaches +summarizable, summarisable +summarization's, summarisation's +summarization, summarisation +summarizations, summarisations +summarize, summarise +summarized, summarised +summarizer's, summariser's +summarizer, summariser +summarizers, summarisers +summarizes, summarises +summarizing, summarising +summerize, summerise +summerizes, summerises +superacknowledgment's, superacknowledgement's +superacknowledgment, superacknowledgement +superacknowledgments, superacknowledgements +supercanonization's, supercanonisation's +supercanonization, supercanonisation +supercanonizations, supercanonisations +supercarbonization's, supercarbonisation's +supercarbonization, supercarbonisation +supercarbonizations, supercarbonisations +supercarbonize, supercarbonise +supercarbonizes, supercarbonises +supercivilization's, supercivilisation's +supercivilization, supercivilisation +supercivilizations, supercivilisations +supercivilized's, supercivilised's +supercivilized, supercivilised +supercivilizeds, superciviliseds +superemphasize, superemphasise +superemphasizes, superemphasises +superfetation, superfoetation +superfetations, superfoetations +superficialize, superficialise +superficialized, superficialised +superficializes, superficialises +superficializing, superficialising +superhumanize, superhumanise +superhumanized, superhumanised +superhumanizes, superhumanises +superhumanizing, superhumanising +supernaturalize, supernaturalise +supernaturalized, supernaturalised +supernaturalizes, supernaturalises +supernaturalizing, supernaturalising +superorganization's, superorganisation's +superorganization, superorganisation +superorganizations, superorganisations +superorganize, superorganise +superorganizes, superorganises +supersensitization's, supersensitisation's +supersensitization, supersensitisation +supersensitizations, supersensitisations +supersensitize, supersensitise +supersensitized, supersensitised +supersensitizing, supersensitising +superspecialize, superspecialise +superspecializes, superspecialises +supersubtilized's, supersubtilised's +supersubtilized, supersubtilised +supersubtilizeds, supersubtiliseds +supersulphurize, supersulphurise +supersulphurizes, supersulphurises +surgerize, surgerise +surgerizes, surgerises +surprizal, surprisal +sursize, sursise +surveil, surveille +swab's, swob's +swab, swob +swabbed, swobbed +swabbing, swobbing +swabs, swobs +sweetbrier's, sweetbriar's +sweetbrier, sweetbriar +sweetbriers, sweetbriars +swiveled, swivelled +swiveling, swivelling +sycophantize, sycophantise +sycophantized, sycophantised +sycophantizes, sycophantises +sycophantizing, sycophantising +syllabize, syllabise +syllabized, syllabised +syllabizes, syllabises +syllabizing, syllabising +syllogization, syllogisation +syllogizations, syllogisations +syllogize, syllogise +syllogized, syllogised +syllogizer, syllogiser +syllogizers, syllogisers +syllogizes, syllogises +syllogizing, syllogising +sylvan, silvan +sylvanize, sylvanise +sylvanizes, sylvanises +sylviine, sylviinae +symboled, symbolled +symboling, symbolling +symbolization's, symbolisation's +symbolization, symbolisation +symbolizations, symbolisations +symbolize, symbolise +symbolized, symbolised +symbolizer's, symboliser's +symbolizer, symboliser +symbolizers, symbolisers +symbolizes, symbolises +symbolizing, symbolising +symmetrically, symmetricly +symmetricalness, symmetricness +symmetricalnesses, symmetricnesses +symmetrization's, symmetrisation's +symmetrization, symmetrisation +symmetrizations, symmetrisations +symmetrize, symmetrise +symmetrized, symmetrised +symmetrizes, symmetrises +symmetrizing, symmetrising +sympathize, sympathise +sympathized, sympathised +sympathizer's, sympathiser's +sympathizer, sympathiser +sympathizers, sympathisers +sympathizes, sympathises +sympathizing's, sympathising's +sympathizing, sympathising +sympathizinglier, sympathisinglier +sympathizingliest, sympathisingliest +sympathizingly, sympathisingly +sympathizings, sympathisings +symphonization's, symphonisation's +symphonization, symphonisation +symphonize, symphonise +symphonized, symphonised +symphonizing, symphonising +symptomatize, symptomatise +symptomatized, symptomatised +symptomatizes, symptomatises +symptomatizing, symptomatising +symptomize, symptomise +symptomizes, symptomises +synagogue's, synagog's +synagogue, synagog +synagogues, synagogs +synalepha, synaloepha +synalephas, synaloephas +synalephe, synaloephe +sync's, synch's +sync, synch +synced, synched +synchronizable's, synchronisable's +synchronizable, synchronisable +synchronizables, synchronisables +synchronization's, synchronisation's +synchronization, synchronisation +synchronizations, synchronisations +synchronize, synchronise +synchronized, synchronised +synchronizer's, synchroniser's +synchronizer, synchroniser +synchronizers, synchronisers +synchronizes, synchronises +synchronizing, synchronising +syncing, synching +syncretize, syncretise +syncretized, syncretised +syncretizes, syncretises +syncretizing, syncretising +syncs, synches +syndicalize, syndicalise +syndicalizes, syndicalises +synecious, synoecious +synecologies, synoecologies +synecology, synoecology +synereses, synaereses +syneresis's, synaeresis's +syneresis, synaeresis +synergize, synergise +synergized, synergised +synergizes, synergises +synergizing, synergising +synesthesia's, synaesthesia's +synesthesia, synaesthesia +synesthesias, synaesthesias +synesthetic, synaesthetic +synestheticer, synaestheticer +synestheticest, synaestheticest +synetic, synoetic +synoecize, synoecise +synoecized, synoecised +synoecizes, synoecises +synoecizing, synoecising +synonymize, synonymise +synonymized, synonymised +synonymizes, synonymises +synonymizing, synonymising +synopsize, synopsise +synopsized, synopsised +synopsizes, synopsises +synopsizing, synopsising +synthesise, synthetize +synthesised, synthetized +synthesises, synthetizes +synthesising, synthetizing +synthesization's, synthesisation's +synthesization, synthesisation +synthesizations, synthesisations +synthesizer's, synthesiser's +synthesizer, synthesiser +synthesizers, synthesisers +synthetization, synthetisation +synthetizer's, synthetiser's +synthetizer, synthetiser +synthetizers, synthetisers +syntonization's, syntonisation's +syntonization, syntonisation +syntonize, syntonise +syntonized, syntonised +syntonizes, syntonises +syntonizing, syntonising +syphilization's, syphilisation's +syphilization, syphilisation +syphilizations, syphilisations +syphilize, syphilise +syphilized, syphilised +syphilizing, syphilising +Syrianize's, Syrianise's +Syrianize, Syrianise +Syrianizes, Syrianises +syringocele, syringocoele +syrup's, sirup's +syrup, sirup +syrups, sirups +systematization's, systematisation's +systematization, systematisation +systematizations, systematisations +systematize, systematise +systematized, systematised +systematizer's, systematiser's +systematizer, systematiser +systematizers, systematisers +systematizes, systematises +systematizing, systematising +systemizable's, systemisable's +systemizable, systemisable +systemizabler, systemisabler +systemizables, systemisables +systemizablest, systemisablest +systemization's, systemisation's +systemization, systemisation +systemizations, systemisations +systemize, systemise +systemized, systemised +systemizer's, systemiser's +systemizer, systemiser +systemizers, systemisers +systemizes, systemises +systemizing, systemising +taboo's, tabu's +taboo, tabu +tabooed, tabued +tabooing, tabuing +taboos, tabus +tabored, taboured +taborer's, tabourer's +taborer, tabourer +taborers, tabourers +taboret's, tabouret's +taboret, tabouret +taborets, tabourets +taborin, tabourin +taborine, tabourine +taboring, tabouring +taborins, tabourins +tabularization's, tabularisation's +tabularization, tabularisation +tabularizations, tabularisations +tabularize, tabularise +tabularized, tabularised +tabularizes, tabularises +tabularizing, tabularising +tabule, tabulae +tachypnea, tachypnoea +tachypneas, tachypnoeas +tachypneic, tachypnoeic +taffetized, taffetised +tailorization's, tailorisation's +tailorization, tailorisation +tailorizations, tailorisations +tailorize, tailorise +tailorizes, tailorises +Talmudization's, Talmudisation's +Talmudization, Talmudisation +Talmudizations, Talmudisations +Talmudize's, Talmudise's +Talmudize, Talmudise +Talmudizes, Talmudises +tamable, tameable +tambura's, tamboura's +tambura, tamboura +tamburas, tambouras +Tammanyize's, Tammanyise's +Tammanyize, Tammanyise +Tammanyizes, Tammanyises +tanalized, tanalised +tandemize, tandemise +tandemizes, tandemises +tantalization's, tantalisation's +tantalization, tantalisation +tantalizations, tantalisations +tantalize, tantalise +tantalized, tantalised +tantalizer's, tantaliser's +tantalizer, tantaliser +tantalizers, tantalisers +tantalizes, tantalises +tantalizing, tantalising +tantalizinglier, tantalisinglier +tantalizinglies, tantalisinglies +tantalizingliest, tantalisingliest +tantalizingly, tantalisingly +tantalizingness, tantalisingness +tantalizingnesses, tantalisingnesses +tantalizings, tantalisings +tariffize, tariffise +tariffizes, tariffises +tartarization's, tartarisation's +tartarization, tartarisation +tartarizations, tartarisations +tartarize, tartarise +tartarized, tartarised +tartarizes, tartarises +tartarizing, tartarising +tasseled, tasselled +tasseling, tasselling +tassels, tassells +tautologize, tautologise +tautologized, tautologised +tautologizes, tautologises +tautologizing, tautologising +tavernize, tavernise +tavernizes, tavernises +taxidermize, taxidermise +taxidermized, taxidermised +taxidermizes, taxidermises +taxidermizing, taxidermising +Taylorize's, Taylorise's +Taylorize, Taylorise +Taylorizes, Taylorises +te, tae +teaseler's, teaseller's +teaseler, teaseller +teaselers, teasellers +Tebilize's, Tebilise's +Tebilize, Tebilise +Tebilized's, Tebilised's +Tebilized, Tebilised +Tebilizes, Tebilises +Tebilizing's, Tebilising's +Tebilizing, Tebilising +technicalization, technicalisation +technicalize, technicalise +technicalizes, technicalises +technicize, technicise +technicized, technicised +technicizes, technicises +technicizing, technicising +technicolor, technicolour +technicolored, technicoloured +technologize, technologise +teepee's, tipi's +teepee, tipi +teepees, tipis +teer, teaer +teers, teres +teetotaled, teetotalled +teetotaler's, teetotaller's +teetotaler, teetotaller +teetotalers, teetotallers +teetotaling, teetotalling +tegu, taegu +tele, telae +telepathize, telepathise +telepathized, telepathised +telepathizes, telepathises +telepathizing, telepathising +telesthesia's, telaesthesia's +telesthesia, telaesthesia +telesthesias, telaesthesias +telesthetic, telaesthetic +telestheticer, telaestheticer +telestheticest, telaestheticest +tellurize, tellurise +tellurized, tellurised +tellurizes, tellurises +tellurizing, tellurising +tels, taels +templize, templise +templizes, templises +temporalize, temporalise +temporalized, temporalised +temporalizes, temporalises +temporalizing, temporalising +temporization's, temporisation's +temporization, temporisation +temporizations, temporisations +temporize, temporise +temporized, temporised +temporizer's, temporiser's +temporizer, temporiser +temporizers, temporisers +temporizes, temporises +temporizing's, temporising's +temporizing, temporising +temporizinglier, temporisinglier +temporizingliest, temporisingliest +temporizingly, temporisingly +temporizings, temporisings +tempos, tempi +tenderization's, tenderisation's +tenderization, tenderisation +tenderizations, tenderisations +tenderize, tenderise +tenderized, tenderised +tenderizer's, tenderiser's +tenderizer, tenderiser +tenderizers, tenderisers +tenderizes, tenderises +tenderizing, tenderising +tendinitis's, tendonitis's +tendinitis, tendonitis +tendinitises, tendonitises +tendriled, tendrilled +tenementization's, tenementisation's +tenementization, tenementisation +tenementizations, tenementisations +tenementize, tenementise +tenementizes, tenementises +tenia's, taenia's +tenia, taenia +teniacidal, taeniacidal +teniacide's, taeniacide's +teniacide, taeniacide +teniacides, taeniacides +teniae, taeniae +teniafuge's, taeniafuge's +teniafuge, taeniafuge +teniafuges, taeniafuges +tenias, taenias +teniases, taeniases +teniasis's, taeniasis's +teniasis, taeniasis +tenioid, taenioid +tenthmeter, tenthmetre +terf, tref +terma, trema +termatic, trematic +terminalization's, terminalisation's +terminalization, terminalisation +terminalizations, terminalisations +terminalized's, terminalised's +terminalized, terminalised +terminalizeds, terminaliseds +ternize, ternise +ternizes, ternises +terre, terrae +terrestrialize, terrestrialise +terrestrializes, terrestrialises +territorialization's, territorialisation's +territorialization, territorialisation +territorializations, territorialisations +territorialize, territorialise +territorialized, territorialised +territorializes, territorialises +territorializing, territorialising +terrorization's, terrorisation's +terrorization, terrorisation +terrorizations, terrorisations +terrorize, terrorise +terrorized, terrorised +terrorizer's, terroriser's +terrorizer, terroriser +terrorizers, terrorisers +terrorizes, terrorises +terrorizing, terrorising +terts, trets +tes, taes +teste, testae +testimonialization's, testimonialisation's +testimonialization, testimonialisation +testimonializations, testimonialisations +testimonialize, testimonialise +testimonialized, testimonialised +testimonializer, testimonialiser +testimonializers, testimonialisers +testimonializes, testimonialises +testimonializing, testimonialising +tetanization's, tetanisation's +tetanization, tetanisation +tetanizations, tetanisations +tetanize, tetanise +tetanized, tetanised +tetanizes, tetanises +tetanizing, tetanising +tetrachlorethylene, tetrachloroethylene +tetrachlorethylenes, tetrachloroethylenes +Teutonization's, Teutonisation's +Teutonization, Teutonisation +Teutonize, Teutonise +teutonize, teutonise +Teutonized, Teutonised +Teutonizes, Teutonises +Teutonizing, Teutonising +texturize, texturise +texturized, texturised +texturizes, texturises +texturizing, texturising +thalamocele, thalamocoele +thalassemia, thalassaemia +thalassemias, thalassaemias +thalassemic, thalassaemic +theater's, theatre's +theater, theatre +theatergoer's, theatregoer's +theatergoer, theatregoer +theatergoers, theatregoers +theatergoing's, theatregoing's +theatergoing, theatregoing +theatergoings, theatregoings +theaterless, theatreless +theaterlesses, theatrelesses +theaterlike's, theatrelike's +theaterlike, theatrelike +theaterlikes, theatrelikes +theaters, theatres +theatricalization's, theatricalisation's +theatricalization, theatricalisation +theatricalizations, theatricalisations +theatricalize, theatricalise +theatricalized, theatricalised +theatricalizes, theatricalises +theatricalizing, theatricalising +theatricize, theatricise +theatricized, theatricised +theatricizes, theatricises +theatricizing, theatricising +theologization's, theologisation's +theologization, theologisation +theologizations, theologisations +theologize, theologise +theologized, theologised +theologizer's, theologiser's +theologizer, theologiser +theologizers, theologisers +theologizes, theologises +theologizing, theologising +Theone's, Theonoe's +Theone, Theonoe +theorization's, theorisation's +theorization, theorisation +theorizations, theorisations +theorize, theorise +theorized, theorised +theorizer's, theoriser's +theorizer, theoriser +theorizers, theorisers +theorizes, theorises +theorizing, theorising +theosophize, theosophise +theosophized, theosophised +theosophizes, theosophises +theosophizing, theosophising +therap, threap +thereness, threeness +therenesses, threenesses +thermalization, thermalisation +thermalizations, thermalisations +thermalize, thermalise +thermalized, thermalised +thermalizes, thermalises +thermalizing, thermalising +therme, thermae +thermesthesia's, thermaesthesia's +thermesthesia, thermaesthesia +thermoanesthesia's, thermoanaesthesia's +thermoanesthesia, thermoanaesthesia +thermoanesthesias, thermoanaesthesias +thermometerize, thermometerise +thermometerizes, thermometerises +thermopolymerization's, thermopolymerisation's +thermopolymerization, thermopolymerisation +thermopolymerizations, thermopolymerisations +thermosiphon's, thermosyphon's +thermosiphon, thermosyphon +thermosiphons, thermosyphons +thesmothete, thesmothetae +thiamine's, thiamin's +thiamine, thiamin +thiamines, thiamins +thralldom's, thraldom's +thralldom, thraldom +thralldoms, thraldoms +thronize, thronise +thronizes, thronises +through, thru +thruway's, throughway's +thruway, throughway +thruways, throughways +thymectomize, thymectomise +thyroidectomized, thyroidectomised +thyroidization's, thyroidisation's +thyroidization, thyroidisation +thyroidizations, thyroidisations +tidbit's, titbit's +tidbit, titbit +tidbits, titbits +Tillford's, Tillfourd's +Tillford, Tillfourd +Timonize's, Timonise's +Timonize, Timonise +Timonized's, Timonised's +Timonized, Timonised +Timonizes, Timonises +Timonizing's, Timonising's +Timonizing, Timonising +Timor's, Timour's +Timor, Timour +tinseled, tinselled +tinselier, tinsellier +tinseliest, tinselliest +tinseling, tinselling +tiro's, tyreo's +tiro, tyreo +tiros, tyreos +titer's, titre's +titer, titre +titers, titres +titivate, tittivate +titivated, tittivated +titivates, tittivates +titivating, tittivating +titivation's, tittivation's +titivation, tittivation +titivations, tittivations +tittuped, tittupped +tittuping, tittupping +tittupy, tittuppy +toffee's, toffy's +toffee, toffy +toffees, toffies +togged, toged +togging, toging +tonicize, tonicise +tonicizes, tonicises +topesthesia, topaesthesia +topi, topi +toret, touret +tormentor's, tormenter's +tormentor, tormenter +tormentors, tormenters +torporize, torporise +torporizes, torporises +Toryize's, Toryise's +Toryize, Toryise +Toryizes, Toryises +totaled, totalled +totaler's, totaller's +totaler, totaller +totalers, totallers +totaling, totalling +totalitarianize, totalitarianise +totalization's, totalisation's +totalization, totalisation +totalizations, totalisations +totalizator's, totalisator's +totalizator, totalisator +totalizators, totalisators +totalize, totalise +totalized, totalised +totalizer's, totaliser's +totalizer, totaliser +totalizers, totalisers +totalizes, totalises +totalizing, totalising +totemization's, totemisation's +totemization, totemisation +totemizations, totemisations +tourize, tourise +tourizes, tourises +toweled, towelled +toweling's, towelling's +toweling, towelling +towelings, towellings +toxanemia, toxanaemia +toxemia's, toxaemia's +toxemia, toxaemia +toxemias, toxaemias +toxemic, toxaemic +toxicemia, toxicaemia +toxicohemia, toxicohaemia +toxihemia, toxihaemia +toxinemia, toxinaemia +trabeate, trabeatae +trabecule, trabeculae +tractorization's, tractorisation's +tractorization, tractorisation +tractorizations, tractorisations +tractorize, tractorise +tractorizes, tractorises +traditionalize, traditionalise +traditionalized, traditionalised +traditionalizes, traditionalises +traditionize, traditionise +traditionizes, traditionises +tragicize, tragicise +tragicizes, tragicises +tragicolored, tragicoloured +traitorize, traitorise +traitorizes, traitorises +trammeled, trammelled +trammeler's, trammeller's +trammeler, trammeller +trammelers, trammellers +trammeling, trammelling +tranquilities, tranquillities +tranquility's, tranquillity's +tranquility, tranquillity +tranquilization's, tranquilisation's +tranquilization, tranquilisation +tranquilizations, tranquilisations +tranquilizingly, tranquilisingly +tranquillization's, tranquillisation's +tranquillization, tranquillisation +tranquillizations, tranquillisations +tranquillize, tranquillise +tranquillized, tranquillised +tranquillizer's, tranquilliser's +tranquillizer, tranquilliser +tranquillizers, tranquillisers +tranquillizes, tranquillises +tranquillizing, tranquillising +tranquillizingly, tranquillisingly +transcendentalization's, transcendentalisation's +transcendentalization, transcendentalisation +transcendentalize, transcendentalise +transcendentalized, transcendentalised +transcendentalizes, transcendentalises +transcendentalizing, transcendentalising +transcolor, transcolour +transcoloration's, transcolouration's +transcoloration, transcolouration +transcolorations, transcolourations +transcolorrer, transcolourer +transcolorrest, transcolourest +transgender, transgendered +transistorization's, transistorisation's +transistorization, transistorisation +transistorizations, transistorisations +transistorize, transistorise +transistorized, transistorised +transistorizes, transistorises +transistorizing, transistorising +transparentize, transparentise +transparentizes, transparentises +traumatization's, traumatisation's +traumatization, traumatisation +traumatizations, traumatisations +traumatize, traumatise +traumatized, traumatised +traumatizes, traumatises +traumatizing, traumatising +traveled, travelled +traveler's, traveller's +traveler, traveller +travelers, travellers +traveling's, travelling's +traveling, travelling +travelings, travellings +travelogue's, travelog's +travelogue, travelog +travelogues, travelogs +trialed, trialled +trialing, trialling +trialization, trialisation +triangularization, triangularisation +triangularizations, triangularisations +triangularize, triangularise +triangularized, triangularised +triangularizes, triangularises +triangularizing, triangularising +trichinization's, trichinisation's +trichinization, trichinisation +trichinizations, trichinisations +trichinize, trichinise +trichinized, trichinised +trichinizes, trichinises +trichinizing, trichinising +trichlorethylene, trichloroethylene +trichlorethylenes, trichloroethylenes +trichotomize, trichotomise +trichotomized, trichotomised +trichotomizes, trichotomises +trichotomizing, trichotomising +tricolor's, tricolour's +tricolor, tricolour +tricolored, tricoloured +tricolors, tricolours +triecious, trioecious +trieciously, trioeciously +triene, triaene +trifluoride, trifluouride +trillionize, trillionise +trillionizes, trillionises +trimerization's, trimerisation's +trimerization, trimerisation +trimerizations, trimerisations +tripylean, tripylaean +trivialization's, trivialisation's +trivialization, trivialisation +trivializations, trivialisations +trivialize, trivialise +trivialized, trivialised +trivializes, trivialises +trivializing, trivialising +trolley's, trolly's +trolley, trolly +trolleyed, trollied +trolleying, trollying +trolleys, trollies +tropeolin's, tropaeolin's +tropeolin, tropaeolin +tropicalization's, tropicalisation's +tropicalization, tropicalisation +tropicalizations, tropicalisations +tropicalize, tropicalise +tropicalized, tropicalised +tropicalizes, tropicalises +tropicalizing, tropicalising +troweled, trowelled +troweler's, troweller's +troweler, troweller +trowelers, trowellers +troweling, trowelling +Trubenize's, Trubenise's +Trubenize, Trubenise +Trubenized's, Trubenised's +Trubenized, Trubenised +Trubenizes, Trubenises +Trubenizing's, Trubenising's +Trubenizing, Trubenising +trypsinize's, trypsinise's +trypsinize, trypsinise +trypsinizes, trypsinises +tsarinas, tzarinas +tsarism, tzarism +tsarisms, tzarisms +tsoris, tsouris +tubercularization's, tubercularisation's +tubercularization, tubercularisation +tubercularize, tubercularise +tubercularized, tubercularised +tubercularizing, tubercularising +tuberculinization's, tuberculinisation's +tuberculinization, tuberculinisation +tuberculinizations, tuberculinisations +tuberculinize, tuberculinise +tuberculinized, tuberculinised +tuberculinizes, tuberculinises +tuberculinizing, tuberculinising +tuberculization, tuberculisation +tuberculizations, tuberculisations +tuberculize, tuberculise +tuberculized, tuberculised +tuberculizes, tuberculises +tuberculizing, tuberculising +tuberization's, tuberisation's +tuberization, tuberisation +tuberizations, tuberisations +tuberize, tuberise +tuberizes, tuberises +tubulization's, tubulisation's +tubulization, tubulisation +tubulizations, tubulisations +tularemia, tularaemia +tularemias, tularaemias +tularemic, tularaemic +tumbrel's, tumbril's +tumbrel, tumbril +tumbrels, tumbrils +tumor's, tumour's +tumor, tumour +tumored, tumoured +tumors, tumours +tunneled, tunnelled +tunneler's, tunneller's +tunneler, tunneller +tunnelers, tunnellers +tunneling, tunnelling +tunnelings, tunnellings +turdine, turdinae +Turkicize's, Turkicise's +Turkicize, Turkicise +Turkicized's, Turkicised's +Turkicized, Turkicised +Turkicizes, Turkicises +Turkicizing's, Turkicising's +Turkicizing, Turkicising +Turkize's, Turkise's +Turkize, Turkise +Turkizes, Turkises +Tuscanize's, Tuscanise's +Tuscanize, Tuscanise +Tuscanizes, Tuscanises +tutele, tutelae +tutorization's, tutorisation's +tutorization, tutorisation +tutorizations, tutorisations +tutorize, tutorise +tutorized, tutorised +tutorizes, tutorises +tutorizing, tutorising +twier, twire +twiers, twires +tyke's, tike's +tyke, tike +tykes, tikes +Tylerize's, Tylerise's +Tylerize, Tylerise +Tylerizes, Tylerises +typhemia, typhaemia +typhemia, typhoemia +typhlenteritis, typhloenteritis +typhoemia, typhoaemia +tyrannize, tyrannise +tyrannized, tyrannised +tyrannizer's, tyranniser's +tyrannizer, tyranniser +tyrannizers, tyrannisers +tyrannizes, tyrannises +tyrannizing's, tyrannising's +tyrannizing, tyrannising +tyrannizinglier, tyrannisinglier +tyrannizingliest, tyrannisingliest +tyrannizingly, tyrannisingly +tyrannizings, tyrannisings +tzar's, tsar's +tzar, tsar +tzardom's, tsardom's +tzardom, tsardom +tzardoms, tsardoms +tzarina's, tsarina's +tzarina, tsarina +tzarism's, tsarism's +tzarist, tsarist +tzars, tsars +ukulele's, ukelele's +ukulele, ukelele +ukuleles, ukeleles +ultracentralizer's, ultracentraliser's +ultracentralizer, ultracentraliser +ultracentralizers, ultracentralisers +ultrahonorable's, ultrahonourable's +ultrahonorable, ultrahonourable +ultrahonorables, ultrahonourables +ultraspecialization's, ultraspecialisation's +ultraspecialization, ultraspecialisation +ultraspecializations, ultraspecialisations +ultrastandardization's, ultrastandardisation's +ultrastandardization, ultrastandardisation +ultrastandardizations, ultrastandardisations +unacclimatized, unacclimatised +unagonize, unagonise +unalcoholized's, unalcoholised's +unalcoholized, unalcoholised +unalcoholizedder, unalcoholisedder +unalcoholizeddest, unalcoholiseddest +unalcoholizeds, unalcoholiseds +unalphabetized, unalphabetised +unamortization's, unamortisation's +unamortization, unamortisation +unamortizations, unamortisations +unamortized, unamortised +unanalyzable, unanalysable +unanalyzed, unanalysed +unanatomizable, unanatomisable +unanatomized, unanatomised +unanemic, unanaemic +unanimalized's, unanimalised's +unanimalized, unanimalised +unanimalizeds, unanimaliseds +unantagonizable's, unantagonisable's +unantagonizable, unantagonisable +unantagonizabler, unantagonisabler +unantagonizables, unantagonisables +unantagonizablest, unantagonisablest +unantagonized, unantagonised +unantagonizedder, unantagonisedder +unantagonizeddest, unantagoniseddest +unantagonizing, unantagonising +unantagonizinger, unantagonisinger +unantagonizingest, unantagonisingest +unapologizing's, unapologising's +unapologizing, unapologising +unapostatized's, unapostatised's +unapostatized, unapostatised +unapostatizeds, unapostatiseds +unappetizing, unappetising +unappetizinger, unappetisinger +unappetizingest, unappetisingest +unappetizinglier, unappetisinglier +unappetizingliest, unappetisingliest +unappetizingly, unappetisingly +unapprized, unapprised +unarbored, unarboured +unarmored, unarmoured +unarmoredder, unarmouredder +unarmoreddest, unarmoureddest +unauthorize, unauthorise +unauthorized, unauthorised +unauthorizedder, unauthorisedder +unauthorizeddest, unauthoriseddest +unauthorizedly, unauthorisedly +unauthorizedness, unauthorisedness +unauthorizes, unauthorises +unbaptize, unbaptise +unbaptized, unbaptised +unbaptizes, unbaptises +unbaptizing, unbaptising +unbarbarize, unbarbarise +unbarbarized, unbarbarised +unbarbarizing, unbarbarising +unbarricaded, unbarricadoed +unbastardized, unbastardised +unbastardizedder, unbastardisedder +unbastardizeddest, unbastardiseddest +unbeknownst, unbeknown +unbrutalize, unbrutalise +unbrutalized, unbrutalised +unbrutalizes, unbrutalises +unbrutalizing, unbrutalising +unbrutize, unbrutise +unbrutized, unbrutised +unbrutizes, unbrutises +unbrutizing, unbrutising +uncanceled, uncancelled +uncanceledder, uncancelledder +uncanceleddest, uncancelleddest +uncandor, uncandour +uncanonization's, uncanonisation's +uncanonization, uncanonisation +uncanonize, uncanonise +uncanonized, uncanonised +uncanonizes, uncanonises +uncanonizing, uncanonising +uncantonized's, uncantonised's +uncantonized, uncantonised +uncantonizeds, uncantoniseds +uncapitalized, uncapitalised +uncapitalizedder, uncapitalisedder +uncapitalizeddest, uncapitaliseddest +uncaramelized, uncaramelised +uncatechized's, uncatechised's +uncatechized, uncatechised +uncatechizedness, uncatechisedness +uncatechizeds, uncatechiseds +uncategorized, uncategorised +uncategorizedder, uncategorisedder +uncategorizeddest, uncategoriseddest +uncatholicize, uncatholicise +uncatholicized, uncatholicised +uncatholicizes, uncatholicises +uncatholicizing, uncatholicising +uncauterized's, uncauterised's +uncauterized, uncauterised +uncauterizeds, uncauteriseds +uncelestialized's, uncelestialised's +uncelestialized, uncelestialised +uncelestializeds, uncelestialiseds +uncenter, uncentre +uncentralized, uncentralised +uncharacterized, uncharacterised +uncharacterizedder, uncharacterisedder +uncharacterizeddest, uncharacteriseddest +unchastizable, unchastisable +unchastized, unchastised +unchloridized's, unchloridised's +unchloridized, unchloridised +unchloridizeds, unchloridiseds +unchristianize, unchristianise +unchristianized, unchristianised +unchristianizes, unchristianises +unchristianizing, unchristianising +uncircularized's, uncircularised's +uncircularized, uncircularised +uncircularizedder, uncircularisedder +uncircularizeddest, uncirculariseddest +uncircularizeds, uncirculariseds +uncivilizable's, uncivilisable's +uncivilizable, uncivilisable +uncivilizabler, uncivilisabler +uncivilizables, uncivilisables +uncivilizablest, uncivilisablest +uncivilize, uncivilise +uncivilized, uncivilised +uncivilizedly, uncivilisedly +uncivilizedness, uncivilisedness +uncivilizes, uncivilises +unclericalize, unclericalise +unclericalizes, unclericalises +uncognizable, uncognisable +uncolonize, uncolonise +uncolonized, uncolonised +uncolonizes, uncolonises +uncolonizing, uncolonising +uncolorable's, uncolourable's +uncolorable, uncolourable +uncolorabler, uncolourabler +uncolorables, uncolourables +uncolorablest, uncolourablest +uncolorablier, uncolourablier +uncolorablies, uncolourablies +uncolorabliest, uncolourabliest +uncolorably, uncolourably +uncolored, uncoloured +uncoloredder, uncolouredder +uncoloreddest, uncoloureddest +uncoloredlier, uncolouredlier +uncoloredliest, uncolouredliest +uncoloredly, uncolouredly +uncoloredness's, uncolouredness's +uncoloredness, uncolouredness +uncolorednesses, uncolourednesses +uncoloreds, uncoloureds +unconcerted, unconcreted +unconventionalize, unconventionalise +unconventionalizes, unconventionalises +uncriticizable's, uncriticisable's +uncriticizable, uncriticisable +uncriticizabler, uncriticisabler +uncriticizables, uncriticisables +uncriticizablest, uncriticisablest +uncriticizably, uncriticisably +uncriticized, uncriticised +uncriticizing, uncriticising +uncriticizingly, uncriticisingly +uncrystallizabilities, uncrystallisabilities +uncrystallizability's, uncrystallisability's +uncrystallizability, uncrystallisability +uncrystallizable's, uncrystallisable's +uncrystallizable, uncrystallisable +uncrystallizabler, uncrystallisabler +uncrystallizables, uncrystallisables +uncrystallizablest, uncrystallisablest +uncrystallized, uncrystallised +uncurricularized's, uncurricularised's +uncurricularized, uncurricularised +uncurricularizeds, uncurriculariseds +undefense's, undefence's +undefense, undefence +undefenses, undefences +undemagnetizable's, undemagnetisable's +undemagnetizable, undemagnetisable +undemagnetizables, undemagnetisables +undemocratization's, undemocratisation's +undemocratization, undemocratisation +undemocratize, undemocratise +undemocratized, undemocratised +undemocratizes, undemocratises +undemocratizing, undemocratising +undenominationalize, undenominationalise +undenominationalizes, undenominationalises +undercapitalization's, undercapitalisation's +undercapitalization, undercapitalisation +undercapitalizations, undercapitalisations +undercapitalize, undercapitalise +undercapitalized, undercapitalised +undercapitalizes, undercapitalises +undercapitalizing, undercapitalising +undercolor's, undercolour's +undercolor, undercolour +undercolored, undercoloured +undercoloring, undercolouring +undercolorings, undercolourings +undercolors, undercolours +underemphasize, underemphasise +underemphasized, underemphasised +underemphasizes, underemphasises +underemphasizing, underemphasising +undergoer, undergore +underlaborer's, underlabourer's +underlaborer, underlabourer +underlaborers, underlabourers +underorganization's, underorganisation's +underorganization, underorganisation +underorganizations, underorganisations +underoxidize, underoxidise +underoxidized, underoxidised +underoxidizes, underoxidises +underoxidizing, underoxidising +underprize, underprise +underprized, underprised +underprizes, underprises +underprizing, underprising +underrealize, underrealise +underrealized, underrealised +underrealizes, underrealises +underrealizing, underrealising +undersavior's, undersaviour's +undersavior, undersaviour +undersaviors, undersaviours +undersized, undersize +underutilization's, underutilisation's +underutilization, underutilisation +underutilizations, underutilisations +underutilize, underutilise +underutilized, underutilised +underutilizes, underutilises +underutilizing, underutilising +undervitalized's, undervitalised's +undervitalized, undervitalised +undervitalizeds, undervitaliseds +undialyzed's, undialysed's +undialyzed, undialysed +undialyzeds, undialyseds +undiphthongize, undiphthongise +undiphthongizes, undiphthongises +undiscolored's, undiscoloured's +undiscolored, undiscoloured +undiscoloredder, undiscolouredder +undiscoloreddest, undiscoloureddest +undiscoloreds, undiscoloureds +undishonored, undishonoured +undisorganized, undisorganised +undramatizable's, undramatisable's +undramatizable, undramatisable +undramatizabler, undramatisabler +undramatizables, undramatisables +undramatizablest, undramatisablest +undramatized's, undramatised's +undramatized, undramatised +undramatizeds, undramatiseds +undreamed, undreamt +undualize, undualise +undualizes, undualises +uneconomizing, uneconomising +unenamored's, unenamoured's +unenamored, unenamoured +unenamoredder, unenamouredder +unenamoreddest, unenamoureddest +unenamoreds, unenamoureds +unendeavored, unendeavoured +unenergized's, unenergised's +unenergized, unenergised +unenergizeds, unenergiseds +unepitomized, unepitomised +unepitomizedder, unepitomisedder +unepitomizeddest, unepitomiseddest +unequaled, unequalled +unequaledder, unequalledder +unequaleddest, unequalleddest +unequalize, unequalise +unequalized, unequalised +unequalizes, unequalises +unequalizing, unequalising +uneulogized's, uneulogised's +uneulogized, uneulogised +uneulogizedder, uneulogisedder +uneulogizeddest, uneulogiseddest +uneulogizeds, uneulogiseds +unevangelized's, unevangelised's +unevangelized, unevangelised +unevangelizedder, unevangelisedder +unevangelizeddest, unevangeliseddest +unevangelizeds, unevangeliseds +unfamiliarized, unfamiliarised +unfamiliarizedder, unfamiliarisedder +unfamiliarizeddest, unfamiliariseddest +unfavorable's, unfavourable's +unfavorable, unfavourable +unfavorableness's, unfavourableness's +unfavorableness, unfavourableness +unfavorablenesses, unfavourablenesses +unfavorabler, unfavourabler +unfavorables, unfavourables +unfavorablest, unfavourablest +unfavorablier, unfavourablier +unfavorabliest, unfavourabliest +unfavorably, unfavourably +unfavored's, unfavoured's +unfavored, unfavoured +unfavoredder, unfavouredder +unfavoreddest, unfavoureddest +unfavoring's, unfavouring's +unfavoring, unfavouring +unfavoringer, unfavouringer +unfavoringest, unfavouringest +unfavorings, unfavourings +unfavorite's, unfavourite's +unfavorite, unfavourite +unfavoriter, unfavouriter +unfavorites, unfavourites +unfavoritest, unfavouritest +unfeminize, unfeminise +unfeminized, unfeminised +unfeminizing, unfeminising +unfertilizable's, unfertilisable's +unfertilizable, unfertilisable +unfertilizabler, unfertilisabler +unfertilizables, unfertilisables +unfertilizablest, unfertilisablest +unfertilized, unfertilised +unfertilizedder, unfertilisedder +unfertilizeddest, unfertiliseddest +unfertilizing, unfertilising +unfeudalize, unfeudalise +unfeudalized, unfeudalised +unfeudalizes, unfeudalises +unfeudalizing, unfeudalising +unflavored, unflavoured +unflavoredder, unflavouredder +unflavoreddest, unflavoureddest +unflavorous, unflavourous +unfocused, unfocussed +unformalized, unformalised +unformalizedder, unformalisedder +unformalizeddest, unformaliseddest +unfossilized's, unfossilised's +unfossilized, unfossilised +unfossilizedder, unfossilisedder +unfossilizeddest, unfossiliseddest +unfossilizeds, unfossiliseds +unfraternized, unfraternised +unfraternizing's, unfraternising's +unfraternizing, unfraternising +unfraternizings, unfraternisings +ungalvanized's, ungalvanised's +ungalvanized, ungalvanised +ungalvanizeds, ungalvaniseds +ungelatinizable's, ungelatinisable's +ungelatinizable, ungelatinisable +ungelatinizables, ungelatinisables +ungelatinized's, ungelatinised's +ungelatinized, ungelatinised +ungelatinizeds, ungelatiniseds +ungeneralized, ungeneralised +ungeneralizedder, ungeneralisedder +ungeneralizeddest, ungeneraliseddest +ungeneralizing, ungeneralising +ungentilize, ungentilise +ungentilizes, ungentilises +ungentlemanize, ungentlemanise +ungentlemanizes, ungentlemanises +unglamorous, unglamourous +unglamorously, unglamourously +ungospelized's, ungospelised's +ungospelized, ungospelised +ungospelizeds, ungospeliseds +ungraphitized's, ungraphitised's +ungraphitized, ungraphitised +ungraphitizeds, ungraphitiseds +unharbor's, unharbour's +unharbor, unharbour +unharbored, unharboured +unharmonize, unharmonise +unharmonized, unharmonised +unharmonizes, unharmonises +unharmonizing, unharmonising +unheroize, unheroise +unheroizes, unheroises +unhonorable's, unhonourable's +unhonorable, unhonourable +unhonorables, unhonourables +unhonorablies, unhonourablies +unhonorably, unhonourably +unhonored, unhonoured +unhonoredder, unhonouredder +unhonoreddest, unhonoureddest +unhouseled, unhouselled +unhumanize, unhumanise +unhumanized, unhumanised +unhumanizes, unhumanises +unhumanizing, unhumanising +unhumored, unhumoured +unhumoredder, unhumouredder +unhumoreddest, unhumoureddest +unhumorous, unhumourous +unhumorously, unhumourously +unhydrolyzed's, unhydrolysed's +unhydrolyzed, unhydrolysed +unhydrolyzeds, unhydrolyseds +unhypnotizable's, unhypnotisable's +unhypnotizable, unhypnotisable +unhypnotizabler, unhypnotisabler +unhypnotizables, unhypnotisables +unhypnotizablest, unhypnotisablest +unhypnotize, unhypnotise +unhypnotized, unhypnotised +unhypnotizes, unhypnotises +unhypnotizing, unhypnotising +unicolor, unicolour +unicolorate, unicolourate +unicolored, unicoloured +unicolorous, unicolourous +unidealized, unidealised +unidealizedder, unidealisedder +unidealizeddest, unidealiseddest +unidolized's, unidolised's +unidolized, unidolised +unidolizedder, unidolisedder +unidolizeddest, unidoliseddest +unidolizeds, unidoliseds +uniformization's, uniformisation's +uniformization, uniformisation +uniformizations, uniformisations +uniformize, uniformise +uniformized, uniformised +uniformizes, uniformises +uniformizing, uniformising +unilateralization's, unilateralisation's +unilateralization, unilateralisation +unilateralizations, unilateralisations +unilateralize, unilateralise +unilateralizes, unilateralises +unimmortalize, unimmortalise +unimmortalized, unimmortalised +unimmortalizes, unimmortalises +unimmunized, unimmunised +unindividualize, unindividualise +unindividualized, unindividualised +unindividualizes, unindividualises +unindustrialized's, unindustrialised's +unindustrialized, unindustrialised +unindustrializeds, unindustrialiseds +uninitializable, uninitialisable +uninitialized, uninitialised +unionization's, unionisation's +unionization, unionisation +unionizations, unionisations +unionize, unionise +unionized, unionised +unionizer, unioniser +unionizers, unionisers +unionizes, unionises +unionizing, unionising +unitalicized, unitalicised +Unitarianize's, Unitarianise's +Unitarianize, Unitarianise +Unitarianizes, Unitarianises +unitemized, unitemised +unitization's, unitisation's +unitization, unitisation +unitizations, unitisations +unitize, unitise +unitized, unitised +unitizes, unitises +unitizing, unitising +universalization's, universalisation's +universalization, universalisation +universalizations, universalisations +universalize, universalise +universalized, universalised +universalizer's, universaliser's +universalizer, universaliser +universalizers, universalisers +universalizes, universalises +universalizing, universalising +unjeopardized, unjeopardised +unjournalized, unjournalised +unkenneled, unkennelled +unkenneling, unkennelling +unlabeled, unlabelled +unlabeledder, unlabelledder +unlabeleddest, unlabelleddest +unlabialize, unlabialise +unlabialized, unlabialised +unlabializes, unlabialises +unlabializing, unlabialising +unlaborable's, unlabourable's +unlaborable, unlabourable +unlaborables, unlabourables +unlabored's, unlaboured's +unlabored, unlaboured +unlaboredder, unlabouredder +unlaboreddest, unlaboureddest +unlaboring's, unlabouring's +unlaboring, unlabouring +unlaboringer, unlabouringer +unlaboringest, unlabouringest +unlaborings, unlabourings +unlegalized, unlegalised +unlegalizedder, unlegalisedder +unlegalizeddest, unlegaliseddest +unleveled, unlevelled +unleveling, unlevelling +unliberalized, unliberalised +unliberalizedder, unliberalisedder +unliberalizeddest, unliberaliseddest +unlionized, unlionised +unliteralized, unliteralised +unlocalizable's, unlocalisable's +unlocalizable, unlocalisable +unlocalizabler, unlocalisabler +unlocalizables, unlocalisables +unlocalizablest, unlocalisablest +unlocalize, unlocalise +unlocalized, unlocalised +unlocalizes, unlocalises +unlocalizing, unlocalising +unmacadamized, unmacadamised +unmagnetized's, unmagnetised's +unmagnetized, unmagnetised +unmagnetizedder, unmagnetisedder +unmagnetizeddest, unmagnetiseddest +unmagnetizeds, unmagnetiseds +unmaterialized, unmaterialised +unmechanize, unmechanise +unmechanized, unmechanised +unmechanizes, unmechanises +unmechanizing, unmechanising +unmediatized's, unmediatised's +unmediatized, unmediatised +unmediatizeds, unmediatiseds +unmedieval, unmediaeval +unmelodized, unmelodised +unmemorialized's, unmemorialised's +unmemorialized, unmemorialised +unmemorializedder, unmemorialisedder +unmemorializeddest, unmemorialiseddest +unmemorializeds, unmemorialiseds +unmemorized, unmemorised +unmercerized's, unmercerised's +unmercerized, unmercerised +unmercerizeds, unmerceriseds +unmesmerize, unmesmerise +unmesmerized, unmesmerised +unmesmerizedder, unmesmerisedder +unmesmerizeddest, unmesmeriseddest +unmesmerizes, unmesmerises +unmetallised's, unmetallized's +unmetallised, unmetallized +unmetalliseds, unmetallizeds +unmethodized's, unmethodised's +unmethodized, unmethodised +unmethodizedder, unmethodisedder +unmethodizeddest, unmethodiseddest +unmethodizeds, unmethodiseds +unmethodizing's, unmethodising's +unmethodizing, unmethodising +unmethodizinger, unmethodisinger +unmethodizingest, unmethodisingest +unmethodizings, unmethodisings +unmilitarized, unmilitarised +unmineralized's, unmineralised's +unmineralized, unmineralised +unmineralizedder, unmineralisedder +unmineralizeddest, unmineraliseddest +unmineralizeds, unmineraliseds +unminimized, unminimised +unminimizedder, unminimisedder +unminimizeddest, unminimiseddest +unminimizing, unminimising +unmissionized's, unmissionised's +unmissionized, unmissionised +unmissionizeds, unmissioniseds +unmiter, unmitre +unmiters, unmitres +unmobilized's, unmobilised's +unmobilized, unmobilised +unmobilizedder, unmobilisedder +unmobilizeddest, unmobiliseddest +unmobilizeds, unmobiliseds +unmodernize, unmodernise +unmodernized, unmodernised +unmodernizedder, unmodernisedder +unmodernizeddest, unmoderniseddest +unmodernizes, unmodernises +unmonopolize, unmonopolise +unmonopolized, unmonopolised +unmonopolizedder, unmonopolisedder +unmonopolizeddest, unmonopoliseddest +unmonopolizes, unmonopolises +unmonopolizing, unmonopolising +unmonopolizinger, unmonopolisinger +unmonopolizingest, unmonopolisingest +unmonopolizings, unmonopolisings +unmoralize, unmoralise +unmoralized, unmoralised +unmoralizes, unmoralises +unmoralizing, unmoralising +unmoralizinger, unmoralisinger +unmoralizingest, unmoralisingest +unmoralizings, unmoralisings +unmotorized, unmotorised +unmotorizedder, unmotorisedder +unmotorizeddest, unmotoriseddest +unmunicipalized's, unmunicipalised's +unmunicipalized, unmunicipalised +unmunicipalizedder, unmunicipalisedder +unmunicipalizeddest, unmunicipaliseddest +unmunicipalizeds, unmunicipaliseds +unmutualized's, unmutualised's +unmutualized, unmutualised +unmutualizedder, unmutualisedder +unmutualizeddest, unmutualiseddest +unmutualizeds, unmutualiseds +unmysticize, unmysticise +unmysticized, unmysticised +unmysticizes, unmysticises +unmysticizing, unmysticising +unnationalized, unnationalised +unnationalizedder, unnationalisedder +unnationalizeddest, unnationaliseddest +unnaturalizable's, unnaturalisable's +unnaturalizable, unnaturalisable +unnaturalizables, unnaturalisables +unnaturalize, unnaturalise +unnaturalized, unnaturalised +unnaturalizes, unnaturalises +unnaturalizing, unnaturalising +unneighbored, unneighboured +unneighborlier, unneighbourlier +unneighborliest, unneighbourliest +unneighborlike's, unneighbourlike's +unneighborlike, unneighbourlike +unneighborlikes, unneighbourlikes +unneighborliness's, unneighbourliness's +unneighborliness, unneighbourliness +unneighborlinesses, unneighbourlinesses +unneighborly, unneighbourly +unneutralize, unneutralise +unneutralized, unneutralised +unneutralizing, unneutralising +unnitrogenized's, unnitrogenised's +unnitrogenized, unnitrogenised +unnitrogenizedder, unnitrogenisedder +unnitrogenizeddest, unnitrogeniseddest +unnitrogenizeds, unnitrogeniseds +unnoncolorables, unnoncolourables +unnoncolorablies, unnoncolourablies +unnoncolorably, unnoncolourably +unnormalize, unnormalise +unnormalized, unnormalised +unnormalizedder, unnormalisedder +unnormalizeddest, unnormaliseddest +unnormalizes, unnormalises +unnormalizing, unnormalising +unnormalizinger, unnormalisinger +unnormalizingest, unnormalisingest +unoptimize, unoptimise +unoptimized, unoptimised +unoptimizes, unoptimises +unoptimizing, unoptimising +unorganizable's, unorganisable's +unorganizable, unorganisable +unorganizabler, unorganisabler +unorganizables, unorganisables +unorganizablest, unorganisablest +unorganize, unorganise +unorganized, unorganised +unorganizedly, unorganisedly +unorganizedness, unorganisedness +unoxidizable's, unoxidisable's +unoxidizable, unoxidisable +unoxidizabler, unoxidisabler +unoxidizables, unoxidisables +unoxidizablest, unoxidisablest +unoxidized, unoxidised +unoxidizedder, unoxidisedder +unoxidizeddest, unoxidiseddest +unoxygenized's, unoxygenised's +unoxygenized, unoxygenised +unoxygenizeds, unoxygeniseds +unpaganize, unpaganise +unpaganizes, unpaganises +unpalisaded, unpalisadoed +unpanegyrized, unpanegyrised +unparagonized's, unparagonised's +unparagonized, unparagonised +unparagonizeds, unparagoniseds +unparalleled, unparallelled +unparalyzed's, unparalysed's +unparalyzed, unparalysed +unparalyzedder, unparalysedder +unparalyzeddest, unparalyseddest +unparalyzeds, unparalyseds +unparameterized, unparameterised +unparametrized, unparametrised +unparceled, unparcelled +unparceledder, unparcelledder +unparceleddest, unparcelleddest +unparenthesized, unparenthesised +unparticularized's, unparticularised's +unparticularized, unparticularised +unparticularizedder, unparticularisedder +unparticularizeddest, unparticulariseddest +unparticularizeds, unparticulariseds +unparticularizing's, unparticularising's +unparticularizing, unparticularising +unparticularizinger, unparticularisinger +unparticularizingest, unparticularisingest +unparticularizings, unparticularisings +unpartizan, unpartisan +unpasteurized, unpasteurised +unpatronizable's, unpatronisable's +unpatronizable, unpatronisable +unpatronizabler, unpatronisabler +unpatronizables, unpatronisables +unpatronizablest, unpatronisablest +unpatronized, unpatronised +unpatronizing's, unpatronising's +unpatronizing, unpatronising +unpauperized's, unpauperised's +unpauperized, unpauperised +unpauperizeds, unpauperiseds +unpenalized, unpenalised +unpenalizedder, unpenalisedder +unpenalizeddest, unpenaliseddest +unperceptively, unpreceptively +unpersonalized, unpersonalised +unpersonalizing, unpersonalising +unphilosophize, unphilosophise +unphilosophized, unphilosophised +unphilosophizes, unphilosophises +unphosphatized's, unphosphatised's +unphosphatized, unphosphatised +unphosphatizedder, unphosphatisedder +unphosphatizeddest, unphosphatiseddest +unphosphatizeds, unphosphatiseds +unpictorialize, unpictorialise +unpictorialized, unpictorialised +unpictorializing, unpictorialising +unplagiarized's, unplagiarised's +unplagiarized, unplagiarised +unplagiarizedder, unplagiarisedder +unplagiarizeddest, unplagiariseddest +unplagiarizeds, unplagiariseds +unpluralized, unpluralised +unpoeticized's, unpoeticised's +unpoeticized, unpoeticised +unpoeticizedder, unpoeticisedder +unpoeticizeddest, unpoeticiseddest +unpoeticizeds, unpoeticiseds +unpoetize, unpoetise +unpoetized, unpoetised +unpoetizes, unpoetises +unpolarizable's, unpolarisable's +unpolarizable, unpolarisable +unpolarizables, unpolarisables +unpolarized's, unpolarised's +unpolarized, unpolarised +unpolarizedder, unpolarisedder +unpolarizeddest, unpolariseddest +unpolarizeds, unpolariseds +unpolymerized's, unpolymerised's +unpolymerized, unpolymerised +unpolymerizedder, unpolymerisedder +unpolymerizeddest, unpolymeriseddest +unpolymerizeds, unpolymeriseds +unpopularize, unpopularise +unpopularized, unpopularised +unpopularizes, unpopularises +unpracticed, unpractised +unpracticedder, unpractisedder +unpracticeddest, unpractiseddest +unpressurized, unpressurised +unprotestantize, unprotestantise +unprotestantized, unprotestantised +unprotestantizes, unprotestantises +unprotestantizing, unprotestantising +unpublicized, unpublicised +unpulverize, unpulverise +unpulverized, unpulverised +unpulverizedder, unpulverisedder +unpulverizeddest, unpulveriseddest +unpulverizes, unpulverises +unquantized, unquantised +unradicalize, unradicalise +unradicalizes, unradicalises +unrancored's, unrancoured's +unrancored, unrancoured +unrancoredder, unrancouredder +unrancoreddest, unrancoureddest +unrancoreds, unrancoureds +unrancorous, unrancourous +unrationalized, unrationalised +unrationalizing, unrationalising +unraveled, unravelled +unraveler's, unraveller's +unraveler, unraveller +unravelers, unravellers +unraveling, unravelling +unrealizable's, unrealisable's +unrealizable, unrealisable +unrealizables, unrealisables +unrealize, unrealise +unrealized, unrealised +unrealizes, unrealises +unrealizing, unrealising +unrealizings, unrealisings +unrecognizable, unrecognisable +unrecognizabler, unrecognisabler +unrecognizablest, unrecognisablest +unrecognizably, unrecognisably +unrecognized, unrecognised +unrecognizing, unrecognising +unrecognizingly, unrecognisingly +unreconnoitered's, unreconnoitred's +unreconnoitered, unreconnoitred +unreconnoiteredder, unreconnoitredder +unreconnoitereddest, unreconnoitreddest +unreconnoitereds, unreconnoitreds +unregularized, unregularised +unreorganized, unreorganised +unreorganizedder, unreorganisedder +unreorganizeddest, unreorganiseddest +unrevelationize, unrevelationise +unrevelationizes, unrevelationises +unrivaled, unrivalled +unrivaledder, unrivalledder +unrivaleddest, unrivalleddest +unromanized, unromanised +unromanticized's, unromanticised's +unromanticized, unromanticised +unromanticizedder, unromanticisedder +unromanticizeddest, unromanticiseddest +unromanticizeds, unromanticiseds +unroyalized's, unroyalised's +unroyalized, unroyalised +unroyalizeds, unroyaliseds +unrumored, unrumoured +unrumoredder, unrumouredder +unrumoreddest, unrumoureddest +unsabered, unsabred +unsaberedder, unsabredder +unsabereddest, unsabreddest +unsatirizable, unsatirisable +unsatirize, unsatirise +unsatirized, unsatirised +unsatirizedder, unsatirisedder +unsatirizeddest, unsatiriseddest +unsatirizes, unsatirises +unsavored, unsavoured +unsavoredder, unsavouredder +unsavoreddest, unsavoureddest +unsavoredly, unsavouredly +unsavoredness, unsavouredness +unsavorier, unsavourier +unsavories, unsavouries +unsavoriest, unsavouriest +unsavorilier, unsavourilier +unsavorilies, unsavourilies +unsavoriliest, unsavouriliest +unsavorily, unsavourily +unsavoriness's, unsavouriness's +unsavoriness, unsavouriness +unsavorinesses, unsavourinesses +unsavory's, unsavoury's +unsavory, unsavoury +unscandalize, unscandalise +unscandalized, unscandalised +unscandalizedder, unscandalisedder +unscandalizeddest, unscandaliseddest +unscandalizes, unscandalises +unscepter's, unsceptre's +unscepter, unsceptre +unsceptered, unsceptred +unscepteredder, unsceptredder +unsceptereddest, unsceptreddest +unscepters, unsceptres +unschematized's, unschematised's +unschematized, unschematised +unschematizedder, unschematisedder +unschematizeddest, unschematiseddest +unschematizeds, unschematiseds +unscored, unscoured +unscoring, unscouring +unscrutinized, unscrutinised +unscrutinizedder, unscrutinisedder +unscrutinizeddest, unscrutiniseddest +unscrutinizing, unscrutinising +unscrutinizinger, unscrutinisinger +unscrutinizingest, unscrutinisingest +unscrutinizinglier, unscrutinisinglier +unscrutinizingliest, unscrutinisingliest +unscrutinizingly, unscrutinisingly +unsectarianize, unsectarianise +unsectarianizes, unsectarianises +unsectionalized, unsectionalised +unsecularize, unsecularise +unsecularized, unsecularised +unsecularizedder, unsecularisedder +unsecularizeddest, unseculariseddest +unsecularizes, unsecularises +unsensitize, unsensitise +unsensitized, unsensitised +unsensitizes, unsensitises +unsensitizing, unsensitising +unsensualize, unsensualise +unsensualized, unsensualised +unsensualizes, unsensualises +unsensualizing, unsensualising +unsentimentalize, unsentimentalise +unsentimentalized, unsentimentalised +unsentimentalizes, unsentimentalises +unsepulcher, unsepulchre +unsepulchered, unsepulchred +unsepulchers, unsepulchres +unserialized, unserialised +unshakable, unshakeable +unshed, unshoed +unsignalized's, unsignalised's +unsignalized, unsignalised +unsignalizedder, unsignalisedder +unsignalizeddest, unsignaliseddest +unsignalizeds, unsignaliseds +unsiphon's, unsyphon's +unsiphon, unsyphon +unsiphons, unsyphons +unsocialized, unsocialised +unsocializedder, unsocialisedder +unsocializeddest, unsocialiseddest +unsocializing, unsocialising +unsolemnize, unsolemnise +unsolemnized, unsolemnised +unsolemnizedder, unsolemnisedder +unsolemnizeddest, unsolemniseddest +unsolemnizes, unsolemnises +unsomber, unsombre +unsomberly, unsombrely +unsomberness's, unsombreness's +unsomberness, unsombreness +unspecialized, unspecialised +unspecializedder, unspecialisedder +unspecializeddest, unspecialiseddest +unspecializing, unspecialising +unspecializinger, unspecialisinger +unspecializingest, unspecialisingest +unspecterlike's, unspectrelike's +unspecterlike, unspectrelike +unspecterlikes, unspectrelikes +unspiritualize, unspiritualise +unspiritualized, unspiritualised +unspiritualizes, unspiritualises +unspiritualizing, unspiritualising +unsplendorous, unsplendourous +unsplendorously, unsplendourously +unspoiled, unspoilt +unstabilized, unstabilised +unstabilizing, unstabilising +unstandardizable, unstandardisable +unstandardized, unstandardised +unstandardizedder, unstandardisedder +unstandardizeddest, unstandardiseddest +unsterilized, unsterilised +unstigmatized's, unstigmatised's +unstigmatized, unstigmatised +unstigmatizedder, unstigmatisedder +unstigmatizeddest, unstigmatiseddest +unstigmatizeds, unstigmatiseds +unstoicize, unstoicise +unstoicizes, unstoicises +unsubsidized, unsubsidised +unsubstantialize, unsubstantialise +unsubstantialized, unsubstantialised +unsubstantializes, unsubstantialises +unsubstantializing, unsubstantialising +unsuccorable's, unsuccourable's +unsuccorable, unsuccourable +unsuccorables, unsuccourables +unsuccored, unsuccoured +unsulphurized's, unsulphurised's +unsulphurized, unsulphurised +unsulphurizeds, unsulphuriseds +unsummarizable, unsummarisable +unsummarized, unsummarised +unsummarizedder, unsummarisedder +unsummarizeddest, unsummariseddest +unsupernaturalize, unsupernaturalise +unsupernaturalized, unsupernaturalised +unsupernaturalizes, unsupernaturalises +unsymbolized, unsymbolised +unsymbolizedder, unsymbolisedder +unsymbolizeddest, unsymboliseddest +unsymmetrized's, unsymmetrised's +unsymmetrized, unsymmetrised +unsymmetrizeds, unsymmetriseds +unsympathizabilities, unsympathisabilities +unsympathizability's, unsympathisability's +unsympathizability, unsympathisability +unsympathizable's, unsympathisable's +unsympathizable, unsympathisable +unsympathizables, unsympathisables +unsympathized, unsympathised +unsympathizedder, unsympathisedder +unsympathizeddest, unsympathiseddest +unsympathizing's, unsympathising's +unsympathizing, unsympathising +unsympathizinger, unsympathisinger +unsympathizingest, unsympathisingest +unsympathizinglier, unsympathisinglier +unsympathizingliest, unsympathisingliest +unsympathizingly, unsympathisingly +unsympathizings, unsympathisings +unsynchronized, unsynchronised +unsynchronizedder, unsynchronisedder +unsynchronizeddest, unsynchroniseddest +unsynthesized, unsynthesised +unsynthesizedder, unsynthesisedder +unsynthesizeddest, unsynthesiseddest +unsystematized, unsystematised +unsystematizedder, unsystematisedder +unsystematizeddest, unsystematiseddest +unsystematizedly, unsystematisedly +unsystematizing, unsystematising +unsystematizinger, unsystematisinger +unsystematizingest, unsystematisingest +unsystemizable's, unsystemisable's +unsystemizable, unsystemisable +unsystemizables, unsystemisables +untantalized, untantalised +untantalizedder, untantalisedder +untantalizeddest, untantaliseddest +untantalizing's, untantalising's +untantalizing, untantalising +untantalizinger, untantalisinger +untantalizingest, untantalisingest +untantalizings, untantalisings +untartarized's, untartarised's +untartarized, untartarised +untartarizeds, untartariseds +untechnicalize, untechnicalise +untechnicalizes, untechnicalises +untemporizing's, untemporising's +untemporizing, untemporising +untemporizings, untemporisings +unterrorized, unterrorised +untheorizable's, untheorisable's +untheorizable, untheorisable +untheorizables, untheorisables +untrammeled, untrammelled +untrammeledder, untrammelledder +untrammeleddest, untrammelleddest +untranquilized, untranquilised +untranquillize, untranquillise +untranquillized, untranquillised +untyrannized, untyrannised +unutilizable's, unutilisable's +unutilizable, unutilisable +unutilizables, unutilisables +unutilized, unutilised +unvaporized's, unvaporised's +unvaporized, unvaporised +unvaporizeds, unvaporiseds +unvectorizable, unvectorisable +unverbalized, unverbalised +unvictimized, unvictimised +unvisualized, unvisualised +unvisualizedder, unvisualisedder +unvisualizeddest, unvisualiseddest +unvitalized's, unvitalised's +unvitalized, unvitalised +unvitalizeds, unvitaliseds +unvitriolized's, unvitriolised's +unvitriolized, unvitriolised +unvitriolizeds, unvitrioliseds +unvocalized's, unvocalised's +unvocalized, unvocalised +unvocalizedder, unvocalisedder +unvocalizeddest, unvocaliseddest +unvocalizeds, unvocaliseds +unvolatilize, unvolatilise +unvolatilized, unvolatilised +unvolatilizedder, unvolatilisedder +unvolatilizeddest, unvolatiliseddest +unvolatilizes, unvolatilises +unvulcanized's, unvulcanised's +unvulcanized, unvulcanised +unvulcanizedder, unvulcanisedder +unvulcanizeddest, unvulcaniseddest +unvulcanizeds, unvulcaniseds +unvulgarize, unvulgarise +unvulgarized, unvulgarised +unvulgarizes, unvulgarises +unvulgarizing, unvulgarising +unwesternized's, unwesternised's +unwesternized, unwesternised +unwesternizeds, unwesterniseds +unwomanize, unwomanise +unwomanized, unwomanised +unwomanizes, unwomanises +updraft's, updraught's +updraft, updraught +updrafts, updraughts +uralitization, uralitisation +uralitizations, uralitisations +uralitize, uralitise +uralitized, uralitised +uralitizes, uralitises +uralitizing, uralitising +uratemia, urataemia +urbanization's, urbanisation's +urbanization, urbanisation +urbanizations, urbanisations +urbanize, urbanise +urbanized, urbanised +urbanizes, urbanises +urbanizing, urbanising +uredema, uroedema +uremia's, uraemia's +uremia, uraemia +uremias, uraemias +uremic, uraemic +urethrorrhea, urethrorrhoea +uricemia, uricaemia +uricemic, uricaemic +urinemia, urinaemia +urinemic, urinaemic +urohematin, urohaematin +urophein, urophaein +usability's, useability's +usability, useability +usable, useable +utilitarianize, utilitarianise +utilitarianized, utilitarianised +utilitarianizes, utilitarianises +utilitarianizing, utilitarianising +utilizabilities, utilisabilities +utilizability, utilisability +utilizable's, utilisable's +utilizable, utilisable +utilizables, utilisables +utilization's, utilisation's +utilization, utilisation +utilizations, utilisations +utilize, utilise +utilized, utilised +utilizer's, utiliser's +utilizer, utiliser +utilizers, utilisers +utilizes, utilises +utilizing, utilising +Utopianize's, Utopianise's +Utopianize, Utopianise +utopianize, utopianise +utopianized, utopianised +utopianizer's, utopianiser's +utopianizer, utopianiser +utopianizers, utopianisers +Utopianizes, Utopianises +utopianizes, utopianises +utopianizing, utopianising +vaagmer, vaagmaer +vaccinization's, vaccinisation's +vaccinization, vaccinisation +vaccinizations, vaccinisations +vacuolization's, vacuolisation's +vacuolization, vacuolisation +vacuolizations, vacuolisations +vacuumize, vacuumise +vacuumized, vacuumised +vacuumizes, vacuumises +vacuumizing, vacuumising +vagabondize, vagabondise +vagabondized, vagabondised +vagabondizer, vagabondiser +vagabondizers, vagabondisers +vagabondizes, vagabondises +vagabondizing, vagabondising +vaginule, vaginulae +vagrantize, vagrantise +vagrantizes, vagrantises +valor's, valour's +valor, valour +valorization's, valorisation's +valorization, valorisation +valorizations, valorisations +valorize, valorise +valorized, valorised +valorizes, valorises +valorizing, valorising +valorousness, valourousness +valors, valours +valvule, valvulae +vampirize, vampirise +vampirized, vampirised +vampirizes, vampirises +vampirizing, vampirising +vandalization's, vandalisation's +vandalization, vandalisation +vandalizations, vandalisations +vandalize, vandalise +vandalized, vandalised +vandalizes, vandalises +vandalizing, vandalising +vapor's, vapour's +vapor, vapour +vaporabilities, vapourabilities +vaporability's, vapourability's +vaporability, vapourability +vaporable's, vapourable's +vaporable, vapourable +vaporables, vapourables +vapored, vapoured +vaporer's, vapourer's +vaporer, vapourer +vaporers, vapourers +vaporescent, vapourescent +vaporier, vapourier +vaporiest, vapouriest +vaporific, vapourific +vaporimeter's, vapourimeter's +vaporimeter, vapourimeter +vaporing's, vapouring's +vaporing, vapouring +vaporingly, vapouringly +vaporings, vapourings +vaporish, vapourish +vaporisher, vapourisher +vaporishest, vapourishest +vaporishness's, vapourishness's +vaporishness, vapourishness +vaporishnesses, vapourishnesses +vaporizable's, vaporisable's +vaporizable, vaporisable +vaporizabler, vaporisabler +vaporizables, vaporisables +vaporizablest, vaporisablest +vaporization's, vaporisation's +vaporization, vaporisation +vaporizations, vaporisations +vaporize, vaporise +vaporized, vaporised +vaporizer's, vaporiser's +vaporizer, vaporiser +vaporizers, vaporisers +vaporizes, vaporises +vaporizing, vaporising +vaporless, vapourless +vaporlesses, vapourlesses +vaporlike's, vapourlike's +vaporlike, vapourlike +vaporlikes, vapourlikes +vaporose, vapourose +vaporously, vapourously +vapors, vapours +vaporware, vapourware +vapory, vapoury +varicolored's, varicoloured's +varicolored, varicoloured +varicoloredder, varicolouredder +varicoloreddest, varicoloureddest +varicoloreds, varicoloureds +varicolorous, varicolourous +vascularization's, vascularisation's +vascularization, vascularisation +vascularizations, vascularisations +vascularize, vascularise +vascularized, vascularised +vascularizes, vascularises +vascularizing, vascularising +vasectomize, vasectomise +vasectomized, vasectomised +vasectomizing, vasectomising +vassalization, vassalisation +vassalize, vassalise +vassalized, vassalised +vassalizes, vassalises +vassalizing, vassalising +Vaticanization's, Vaticanisation's +Vaticanization, Vaticanisation +Vaticanizations, Vaticanisations +Vaticanize's, Vaticanise's +Vaticanize, Vaticanise +Vaticanizes, Vaticanises +vavasor, vavasour +vavasors, vavasours +Ve's, Voe's +Ve, Voe +vectorizable, vectorisable +vectorization's, vectorisation's +vectorization, vectorisation +vectorizations, vectorisations +vectorize, vectorise +vectorized, vectorised +vectorizer, vectoriser +vectorizered, vectorisered +vectorizering, vectorisering +vectorizers, vectorisers +vectorizes, vectorises +vectorizing, vectorising +veery, verey +vegetablize, vegetablise +vegetablizes, vegetablises +velarization's, velarisation's +velarization, velarisation +velarizations, velarisations +velarize, velarise +velarized, velarised +velarizes, velarises +velarizing, velarising +veld's, veldt's +veld, veldt +velds, veldts +venalization's, venalisation's +venalization, venalisation +venalizations, venalisations +venalize, venalise +venalizes, venalises +vendor's, vender's +vendor, vender +vendors, venders +venomization's, venomisation's +venomization, venomisation +venomizations, venomisations +venomize, venomise +venomizes, venomises +venter, ventre +venters, ventres +ventriloquize, ventriloquise +ventriloquized, ventriloquised +ventriloquizes, ventriloquises +ventriloquizing, ventriloquising +venule, venulae +veranda's, verandah's +veranda, verandah +verandas, verandahs +verbalization's, verbalisation's +verbalization, verbalisation +verbalizations, verbalisations +verbalize, verbalise +verbalized, verbalised +verbalizer's, verbaliser's +verbalizer, verbaliser +verbalizers, verbalisers +verbalizes, verbalises +verbalizing, verbalising +vermeiled, vermeilled +vermeiles, vermeilles +vermeiling, vermeilling +vermilion's, vermillion's +vermilion, vermillion +vermilionize, vermilionise +vermilionizes, vermilionises +vernacularization's, vernacularisation's +vernacularization, vernacularisation +vernacularizations, vernacularisations +vernacularize, vernacularise +vernacularized, vernacularised +vernacularizes, vernacularises +vernacularizing, vernacularising +vernalization's, vernalisation's +vernalization, vernalisation +vernalizations, vernalisations +vernalize, vernalise +vernalized, vernalised +vernalizes, vernalises +vernalizing, vernalising +versicolor, versicolour +versicolorate, versicolourate +versicolored, versicoloured +versicolorous, versicolourous +versionize, versionise +versionizes, versionises +vesicule, vesiculae +vestryize, vestryise +vestryizes, vestryises +veter's, vetoer's +veter, vetoer +veteranize, veteranise +veteranizes, veteranises +vialed, vialled +vialing, vialling +victimizable's, victimisable's +victimizable, victimisable +victimizables, victimisables +victimization's, victimisation's +victimization, victimisation +victimizations, victimisations +victimize, victimise +victimized, victimised +victimizer's, victimiser's +victimizer, victimiser +victimizers, victimisers +victimizes, victimises +victimizing, victimising +Victorianize's, Victorianise's +Victorianize, Victorianise +Victorianizes, Victorianises +victualage's, victuallage's +victualage, victuallage +victualages, victuallages +victualed, victualled +victualer's, victualler's +victualer, victualler +victualers, victuallers +victualess, victualless +victualing, victualling +videodisc's, videodisk's +videodisc, videodisk +videodiscs, videodisks +vier, vire +viers, vires +Vietnamization's, Vietnamisation's +Vietnamization, Vietnamisation +Vietnamize, Vietnamise +Vietnamized, Vietnamised +Vietnamizes, Vietnamises +Vietnamizing, Vietnamising +vigor's, vigour's +vigor, vigour +vigorless, vigourless +vigors, vigours +villagization, villagisation +villagizations, villagisations +viremia, viraemia +viremias, viraemias +viremic, viraemic +virilization, virilisation +virilizations, virilisations +virilized, virilised +virilizing, virilising +virtualization, virtualisation +virtualize, virtualise +virtualizes, virtualises +virtuosos, virtuosoes +visionize, visionise +visionizes, visionises +visor's, vizor's +visor, vizor +visors, vizors +visualizable, visualisable +visualization's, visualisation's +visualization, visualisation +visualizations, visualisations +visualize, visualise +visualized, visualised +visualizer's, visualiser's +visualizer, visualiser +visualizers, visualisers +visualizes, visualises +visualizing, visualising +vitalization's, vitalisation's +vitalization, vitalisation +vitalizations, vitalisations +vitalize, vitalise +vitalized, vitalised +vitalizer's, vitaliser's +vitalizer, vitaliser +vitalizers, vitalisers +vitalizes, vitalises +vitalizing's, vitalising's +vitalizing, vitalising +vitalizingly, vitalisingly +vitalizings, vitalisings +vitaminization, vitaminisation +vitaminize, vitaminise +vitaminized, vitaminised +vitaminizes, vitaminises +vitaminizing, vitaminising +vitriolizable's, vitriolisable's +vitriolizable, vitriolisable +vitriolizables, vitriolisables +vitriolization's, vitriolisation's +vitriolization, vitriolisation +vitriolizations, vitriolisations +vitriolize, vitriolise +vitriolized, vitriolised +vitriolizer, vitrioliser +vitriolizers, vitriolisers +vitriolizes, vitriolises +vitriolizing, vitriolising +vivandier, vivandire +viver, vivre +viverrine, viverrinae +vivers, vivres +vizard, visard +vizards, visards +vizied, visied +vizies, visies +vocalization's, vocalisation's +vocalization, vocalisation +vocalizations, vocalisations +vocalize, vocalise +vocalized, vocalised +vocalizer's, vocaliser's +vocalizer, vocaliser +vocalizers, vocalisers +vocalizes, vocalises +vocalizing, vocalising +vocationalization's, vocationalisation's +vocationalization, vocationalisation +vocationalizations, vocationalisations +vocationalize, vocationalise +vocationalizes, vocationalises +volatilizable's, volatilisable's +volatilizable, volatilisable +volatilizabler, volatilisabler +volatilizables, volatilisables +volatilizablest, volatilisablest +volatilization's, volatilisation's +volatilization, volatilisation +volatilizations, volatilisations +volatilize, volatilise +volatilized, volatilised +volatilizer's, volatiliser's +volatilizer, volatiliser +volatilizers, volatilisers +volatilizes, volatilises +volatilizing, volatilising +volcanism's, vulcanism's +volcanism, vulcanism +volcanisms, vulcanisms +volcanization, volcanisation +volcanizations, volcanisations +volcanize, volcanise +volcanized, volcanised +volcanizes, volcanises +volcanizing, volcanising +voltize, voltise +voltizes, voltises +vowelization's, vowelisation's +vowelization, vowelisation +vowelizations, vowelisations +vowelize, vowelise +vowelized, vowelised +vowelizes, vowelises +vowelizing, vowelising +vulcanizable's, vulcanisable's +vulcanizable, vulcanisable +vulcanizabler, vulcanisabler +vulcanizables, vulcanisables +vulcanizablest, vulcanisablest +vulcanizate's, vulcanisate's +vulcanizate, vulcanisate +vulcanizates, vulcanisates +vulcanization's, vulcanisation's +vulcanization, vulcanisation +vulcanizations, vulcanisations +vulcanize, vulcanise +vulcanized, vulcanised +vulcanizer's, vulcaniser's +vulcanizer, vulcaniser +vulcanizers, vulcanisers +vulcanizes, vulcanises +vulcanizing, vulcanising +vulgarization's, vulgarisation's +vulgarization, vulgarisation +vulgarizations, vulgarisations +vulgarize, vulgarise +vulgarized, vulgarised +vulgarizer's, vulgariser's +vulgarizer, vulgariser +vulgarizers, vulgarisers +vulgarizes, vulgarises +vulgarizing, vulgarising +wackes, wackoes +wackier, whackier +wackiest, whackiest +wacky, whacky +Wagnerize's, Wagnerise's +Wagnerize, Wagnerise +Wagnerizes, Wagnerises +wagon's, waggon's +wagon, waggon +wagoned, waggoned +wagoneer, waggoneer +wagoner's, waggoner's +wagoner, waggoner +wagoners, waggoners +wagonette's, waggonette's +wagonette, waggonette +wagonettes, waggonettes +wagoning, waggoning +wagons, waggons +wainscoted, wainscotted +wainscoting's, wainscotting's +wainscoting, wainscotting +wainscotings, wainscottings +wallah, walla +wallahs, wallas +wantonize, wantonise +wantonized, wantonised +wantonizes, wantonises +wantonizing, wantonising +warer, warre +Warford's, Warfourd's +Warford, Warfourd +warrantize, warrantise +waterbed's, water_bed's +waterbed, water_bed +waterbeds, water_beds +watercolor's, watercolour's +watercolor, watercolour +watercolored, watercoloured +watercoloring, watercolouring +watercolorist's, watercolourist's +watercolorist, watercolourist +watercolorists, watercolourists +watercolors, watercolours +weaseled, weaselled +weaseling, weaselling +weatherize, weatherise +weatherized, weatherised +weatherizes, weatherises +weatherizing, weatherising +weeviled, weevilled +weftwize, weftwise +weize, weise +weized, weised +weizes, weises +weizing, weising +welsh, welch +welshed, welched +welshes, welches +welshing, welching +wer, waer +werewolf's, werwolf's +werewolf, werwolf +werewolves, werwolves +westernization's, westernisation's +westernization, westernisation +westernizations, westernisations +westernize, westernise +westernized, westernised +westernizes, westernises +westernizing, westernising +whimsies, whimseys +whimsy's, whimsey's +whimsy, whimsey +whir's, whirr's +whir, whirr +whirs, whirrs +Whitmanize's, Whitmanise's +Whitmanize, Whitmanise +Whitmanizes, Whitmanises +whiz's, whizz's +whiz, whizz +whizz's, wiz's +whizz, wiz +whizzes, wizzes +whodunit's, whodunnit's +whodunit, whodunnit +whodunits, whodunnits +wigeon's, widgeon's +wigeon, widgeon +willful, wilful +willfuler, wilfuler +willfulest, wilfulest +willfullier, wilfullier +willfulliest, wilfulliest +willfully, wilfully +willfulness's, wilfulness's +willfulness, wilfulness +willy, willie +winterization's, winterisation's +winterization, winterisation +winterizations, winterisations +winterize, winterise +winterized, winterised +winterizes, winterises +winterizing, winterising +wintrier, winterier +wintriest, winteriest +wintry, wintery +wisteria's, wistaria's +wisteria, wistaria +wisterias, wistarias +wizen, wisen +womanization's, womanisation's +womanization, womanisation +womanizations, womanisations +womanize, womanise +womanized, womanised +womanizer's, womaniser's +womanizer, womaniser +womanizers, womanisers +womanizes, womanises +womanizing, womanising +woodcockize, woodcockise +woodcockizes, woodcockises +woolen's, woollen's +woolen, woollen +woolenner, woollenner +woolennest, woollennest +woolens, woollens +woollenisation's, woollenization's +woollenisation, woollenization +woollenisations, woollenizations +woollenise, woollenize +woollenises, woollenizes +wornil, wournil +worshiped, worshipped +worshiper's, worshipper's +worshiper, worshipper +worshipers, worshippers +worshiping, worshipping +yak's, yack's +yak, yack +yak, yack +yak, yock +yakked, yacked +yakking, yacking +yaks, yacks +yaks, yacks +yeshiva's, yeshivah's +yeshiva, yeshivah +yeshivot, yeshivahs +yock's, yak's +yocks, yaks +yodeled, yodelled +yodeler's, yodeller's +yodeler, yodeller +yodelers, yodellers +yodeling, yodelling +yoghourt's, yogourt's +yoghourt, yogourt +yoghourts, yogourts +yogi's, yogin's +yogi, yogin +yogis, yogins +yuck, yuk +yuk, yuck +yukked, yucked +yukking, yucking +yuks, yucks +zaffer, zaffre +zaffers, zaffres +zea, zoea +zeas, zoeas +zeroize, zeroise +zeroized, zeroised +zeroizes, zeroises +zeroizing, zeroising +zipper's, Zipper's +zipper, Zipper +zippers, Zippers +zoea's, zoaea's +zoea, zoaea +zoea, zooea +zoeae, zooeae +zoeal, zooeal +zoeas, zooeas +zoecia, zooecia +zoecium, zooecium +zombie's, zombi's +zombie, zombi +zombies, zombis +zonesthesia, zonaesthesia +zonule, zonulae +zooglea, zoogloea +zoogleae, zoogloeae +zoogleal, zoogloeal +zoogleas, zoogloeas +zygenid, zygaenid diff --git a/test/rootfs/opt/solr/server/solr/default/conf/synonyms_und.txt b/test/rootfs/opt/solr/server/solr/default/conf/synonyms_und.txt new file mode 100644 index 00000000..91689ff9 --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/conf/synonyms_und.txt @@ -0,0 +1 @@ +drupal, durpal diff --git a/test/rootfs/opt/solr/server/solr/default/core.properties b/test/rootfs/opt/solr/server/solr/default/core.properties new file mode 100644 index 00000000..8c68b5bf --- /dev/null +++ b/test/rootfs/opt/solr/server/solr/default/core.properties @@ -0,0 +1,3 @@ +name=default +config=solrconfig.xml +dataDir=data diff --git a/test/rootfs/var/www/drupal/assets/patches/default_settings.txt b/test/rootfs/var/www/drupal/assets/patches/default_settings.txt new file mode 100644 index 00000000..ac78c264 --- /dev/null +++ b/test/rootfs/var/www/drupal/assets/patches/default_settings.txt @@ -0,0 +1,84 @@ +/** + * Section appended onto drupal/core default.settings.php via "drupal-scaffold" in composer.json. + */ + +// Let Drush use all the memory available. +if (PHP_SAPI === 'cli') { + ini_set('memory_limit', '-1'); +} + +// Required when running Drupal behind a reverse proxy. +$settings['reverse_proxy'] = TRUE; +$settings['reverse_proxy_addresses'] = array($_SERVER['REMOTE_ADDR']); +$settings['reverse_proxy_trusted_headers'] = \Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL; + +/** + * Private file path: + * + * A local file system path where private files will be stored. This directory + * must be absolute, outside of the Drupal installation directory and not + * accessible over the web. + * + * Note: Caches need to be cleared when this value is changed to make the + * private:// stream wrapper available to the system. + * + * See https://www.drupal.org/documentation/modules/file for more information + * about securing private files. + */ +$settings['file_private_path'] = '/var/www/drupal/private/'; + +// Shared configuration, config_split is used for any site specific differences. +$settings['config_sync_directory'] = '/var/www/drupal/config/sync'; + +// Content sync module. +global $content_directories; +$content_directories['sync'] = '/var/www/drupal/content/sync'; + +// Container environment variable path. +$path = "/var/run/s6/container_environment/"; + +// Some configurations are derived from environment variables. +$config['islandora.settings']['broker_url'] = file_get_contents($path . 'DRUPAL_DEFAULT_BROKER_URL'); +$config['islandora.settings']['broker_user'] = file_exists($path . 'DRUPAL_DEFAULT_BROKER_USER') ? file_get_contents($path . 'DRUPAL_DEFAULT_BROKER_USER') : NULL; +$config['islandora.settings']['broker_password'] = file_exists($path . 'DRUPAL_DEFAULT_BROKER_PASSWORD') ? file_get_contents($path . 'DRUPAL_DEFAULT_BROKER_PASSWORD') : NULL; +$config['islandora_iiif.settings']['iiif_server'] = file_get_contents($path . 'DRUPAL_DEFAULT_CANTALOUPE_URL'); +$config['matomo.settings']['url_http'] = file_get_contents($path . 'DRUPAL_DEFAULT_MATOMO_URL_HTTP'); +$config['matomo.settings']['url_https'] = file_get_contents($path . 'DRUPAL_DEFAULT_MATOMO_URL_HTTPS'); +$config['openseadragon.settings']['iiif_server'] = file_get_contents($path . 'DRUPAL_DEFAULT_CANTALOUPE_URL'); +$config['search_api.server.default_solr_server']['backend_config']['connector_config']['host'] = file_get_contents($path . 'DRUPAL_DEFAULT_SOLR_HOST'); +$config['search_api.server.default_solr_server']['backend_config']['connector_config']['port'] = file_get_contents($path . 'DRUPAL_DEFAULT_SOLR_PORT'); +$config['search_api.server.default_solr_server']['backend_config']['connector_config']['core'] = file_get_contents($path . 'DRUPAL_DEFAULT_SOLR_CORE'); + +// Others are hardcoded. +$config['key.key.islandora_rsa_key']['key_provider_settings']['file_location'] = '/opt/keys/jwt/private.key'; + +// Some settings are derived from environment variables. +$settings['hash_salt'] = file_get_contents($path . 'DRUPAL_DEFAULT_SALT'); +$settings['trusted_host_patterns'] = [ + 0 => file_get_contents($path . 'DRUPAL_DEFAULT_SITE_URL'), +]; + +// Database settings are also derived from environment variables. +$databases['default']['default'] = [ + 'database' => file_get_contents($path . 'DRUPAL_DEFAULT_DB_NAME'), + 'username' => file_get_contents($path . 'DRUPAL_DEFAULT_DB_USER'), + 'password' => file_get_contents($path . 'DRUPAL_DEFAULT_DB_PASSWORD'), + 'host' => file_get_contents($path . 'DB_MYSQL_HOST'), + 'port' => file_get_contents($path . 'DB_MYSQL_PORT'), + 'prefix' => '', + 'driver' => 'mysql', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', +]; + +// Flysystem +$settings['flysystem']['fedora']['driver'] = 'fedora'; +$settings['flysystem']['fedora']['config']['root'] = file_get_contents($path . 'DRUPAL_DEFAULT_FCREPO_URL'); + +// Change the php_storage settings in your setting.php. It is recommend that +// this directory be outside out of the docroot. +$settings['php_storage']['twig']['directory'] = $settings['file_private_path'] . '/php'; +$settings['php_storage']['twig']['secret'] = $settings['hash_salt']; + +/** + * End Section. + */ diff --git a/base/rootfs/etc/cont-finish.d/.gitignore b/test/rootfs/var/www/drupal/web/files/private/.gitignore similarity index 100% rename from base/rootfs/etc/cont-finish.d/.gitignore rename to test/rootfs/var/www/drupal/web/files/private/.gitignore diff --git a/base/rootfs/etc/fix-attrs.d/.gitignore b/test/rootfs/var/www/drupal/web/files/public/.gitignore similarity index 100% rename from base/rootfs/etc/fix-attrs.d/.gitignore rename to test/rootfs/var/www/drupal/web/files/public/.gitignore diff --git a/test/rootfs/var/www/drupal/web/modules/custom/README.md b/test/rootfs/var/www/drupal/web/modules/custom/README.md new file mode 100644 index 00000000..8b2e440d --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/README.md @@ -0,0 +1,11 @@ +# Custom Modules + +We need two separate modules as islandora requires all the taxonomy terms to be +present to function correctly, having just the direct dependencies is not +enough. + +`sample_core` is installed first, followed by `sample_content`. + +We include the `taxonomy_terms` that are normally ingested via the `migrate-api` +using this module as we need a consistent `uuid` for each to properly link the +default content to them as `id` changes on every re-install. diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.jpg b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.jpg new file mode 100644 index 00000000..1d0253b6 Binary files /dev/null and b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.jpg differ diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.mp3 b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.mp3 new file mode 100644 index 00000000..0379b4d7 Binary files /dev/null and b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.mp3 differ diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.mp4 b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.mp4 new file mode 100644 index 00000000..860d01bd Binary files /dev/null and b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.mp4 differ diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.pdf b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.pdf new file mode 100644 index 00000000..c0e31a07 Binary files /dev/null and b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample.pdf differ diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_audio.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_audio.yml new file mode 100644 index 00000000..87320a38 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_audio.yml @@ -0,0 +1,30 @@ +_meta: + version: '1.0' + entity_type: file + uuid: 71aef23b-86cc-4826-9ea4-becaf4a0c6d6 + default_langcode: en +default: + uid: + - + target_id: 1 + filename: + - + value: sample.mp3 + uri: + - + value: 'fedora://2022-11/sample.mp3' + filemime: + - + value: audio/mpeg + filesize: + - + value: 764176 + status: + - + value: true + created: + - + value: 1668787348 + sha1: + - + value: dae94d2ae419b398c977f27f4190680715ae10c3 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_document.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_document.yml new file mode 100644 index 00000000..3ab4c5a9 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_document.yml @@ -0,0 +1,30 @@ +_meta: + version: '1.0' + entity_type: file + uuid: cb22c7d7-0d0b-45a9-b716-71c499bc3fd5 + default_langcode: en +default: + uid: + - + target_id: 1 + filename: + - + value: sample.pdf + uri: + - + value: 'fedora://2022-11/sample.pdf' + filemime: + - + value: application/pdf + filesize: + - + value: 3028 + status: + - + value: true + created: + - + value: 1668785846 + sha1: + - + value: bfd009f500c057195ffde66fae64f92fa5f59b72 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_image.yml new file mode 100644 index 00000000..83dc96f4 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_image.yml @@ -0,0 +1,30 @@ +_meta: + version: '1.0' + entity_type: file + uuid: 8acb9ed6-5430-40a8-8110-075da7f405b2 + default_langcode: en +default: + uid: + - + target_id: 1 + filename: + - + value: sample.jpg + uri: + - + value: 'fedora://2022-11/sample.jpg' + filemime: + - + value: image/jpeg + filesize: + - + value: 358020 + status: + - + value: true + created: + - + value: 1668006708 + sha1: + - + value: c234bb8e6526adf16352365bc05520a1d2763a69 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_video.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_video.yml new file mode 100644 index 00000000..15bf785b --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/file/sample_video.yml @@ -0,0 +1,30 @@ +_meta: + version: '1.0' + entity_type: file + uuid: b77150f6-950c-4be3-b7e6-f501335a60de + default_langcode: en +default: + uid: + - + target_id: 1 + filename: + - + value: sample.mp4 + uri: + - + value: 'fedora://2022-11/sample.mp4' + filemime: + - + value: video/mp4 + filesize: + - + value: 273100 + status: + - + value: true + created: + - + value: 1668002700 + sha1: + - + value: 55508bc98a00f615dbe9bd4c84a253ba4238b021 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_audio.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_audio.yml new file mode 100644 index 00000000..63f102e9 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_audio.yml @@ -0,0 +1,52 @@ +_meta: + version: '1.0' + entity_type: media + uuid: d63d1e91-29c0-4af7-93e5-05d65614655b + bundle: audio + default_langcode: en + depends: + 71aef23b-86cc-4826-9ea4-becaf4a0c6d6: file + c18ab21b-2713-4120-9de4-9fd0d8ec1b0b: node + 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0: taxonomy_term +default: + revision_user: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + name: + - + value: 'Sample Audio' + created: + - + value: 1668787341 + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_file_size: + - + value: 764176 + field_media_audio_file: + - + entity: 71aef23b-86cc-4826-9ea4-becaf4a0c6d6 + display: true + description: '' + field_media_of: + - + entity: c18ab21b-2713-4120-9de4-9fd0d8ec1b0b + field_media_use: + - + entity: 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0 + field_mime_type: + - + value: audio/mpeg diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_document.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_document.yml new file mode 100644 index 00000000..09ab880c --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_document.yml @@ -0,0 +1,56 @@ +_meta: + version: '1.0' + entity_type: media + uuid: fa518f3c-4f31-4ca3-94af-31648d68bc37 + bundle: document + default_langcode: en + depends: + cb22c7d7-0d0b-45a9-b716-71c499bc3fd5: file + 955c361d-1f45-48f9-812d-fe699a6de60f: node + 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0: taxonomy_term +default: + revision_user: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + name: + - + value: 'Sample Document' + created: + - + value: 1668785814 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_file_size: + - + value: 3028 + field_media_document: + - + entity: cb22c7d7-0d0b-45a9-b716-71c499bc3fd5 + display: true + description: '' + field_media_of: + - + entity: 955c361d-1f45-48f9-812d-fe699a6de60f + field_media_use: + - + entity: 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0 + field_mime_type: + - + value: application/pdf diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_image.yml new file mode 100644 index 00000000..9a4eeb74 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_image.yml @@ -0,0 +1,61 @@ +_meta: + version: '1.0' + entity_type: media + uuid: 047959ca-2ff2-4664-91bb-6541cae44f31 + bundle: image + default_langcode: en + depends: + 8acb9ed6-5430-40a8-8110-075da7f405b2: file + 34fafe07-661c-44c7-8c34-27179a23d759: node + 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0: taxonomy_term + c6a604f2-f612-463d-b82e-35b032f87728: taxonomy_term +default: + revision_user: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + name: + - + value: 'Sample Image' + created: + - + value: 1668006692 + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_file_size: + - + value: 358020 + field_height: + - + value: 1374 + field_media_image: + - + entity: 8acb9ed6-5430-40a8-8110-075da7f405b2 + alt: 'Sample Image' + title: '' + width: 1483 + height: 1374 + field_media_of: + - + entity: 34fafe07-661c-44c7-8c34-27179a23d759 + field_media_use: + - + entity: 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0 + field_mime_type: + - + value: image/jpeg + field_width: + - + value: 1483 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_video.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_video.yml new file mode 100644 index 00000000..c6c2dc07 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/media/sample_video.yml @@ -0,0 +1,54 @@ +_meta: + version: '1.0' + entity_type: media + uuid: c6c791fd-9771-4071-aa35-c70aada1811f + bundle: video + default_langcode: en + depends: + 4c1d613d-36b9-40a6-99a2-488ad9330c2a: node + 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0: taxonomy_term + c6a604f2-f612-463d-b82e-35b032f87728: taxonomy_term + afc418da-8303-45bb-8639-0a9fc158c324: taxonomy_term + b77150f6-950c-4be3-b7e6-f501335a60de: file +default: + revision_user: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + name: + - + value: 'Sample Video' + created: + - + value: 1668002691 + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_file_size: + - + value: 236780 + field_media_of: + - + entity: 4c1d613d-36b9-40a6-99a2-488ad9330c2a + field_media_use: + - + entity: 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0 + field_media_video_file: + - + entity: b77150f6-950c-4be3-b7e6-f501335a60de + display: true + description: '' + field_mime_type: + - + value: video/mp4 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_audio.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_audio.yml new file mode 100644 index 00000000..10f4cc98 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_audio.yml @@ -0,0 +1,53 @@ +_meta: + version: '1.0' + entity_type: node + uuid: c18ab21b-2713-4120-9de4-9fd0d8ec1b0b + bundle: islandora_object + default_langcode: en + depends: + 0c7da6e9-7295-46eb-afd0-16cf94462dce: node + 60c1d566-4693-412e-b184-9a208459f1d9: taxonomy_term + bd9d194c-2de7-43de-8f5e-df50d8ed2a99: taxonomy_term +default: + revision_uid: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + title: + - + value: 'Sample Audio' + created: + - + value: 1668787139 + promote: + - + value: true + sticky: + - + value: false + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_extent: + - + value: '1 item' + field_member_of: + - + entity: 0c7da6e9-7295-46eb-afd0-16cf94462dce + field_model: + - + entity: 60c1d566-4693-412e-b184-9a208459f1d9 + field_resource_type: + - + entity: bd9d194c-2de7-43de-8f5e-df50d8ed2a99 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_collection.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_collection.yml new file mode 100644 index 00000000..14a5d189 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_collection.yml @@ -0,0 +1,42 @@ +_meta: + version: '1.0' + entity_type: node + uuid: 0c7da6e9-7295-46eb-afd0-16cf94462dce + bundle: islandora_object + default_langcode: en + depends: + 4adbf9a6-08e6-4911-bd36-9cd0ab8e3b59: taxonomy_term +default: + revision_uid: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + title: + - + value: 'Sample Collection' + created: + - + value: 1682105372 + promote: + - + value: true + sticky: + - + value: false + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_model: + - + entity: 4adbf9a6-08e6-4911-bd36-9cd0ab8e3b59 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_document.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_document.yml new file mode 100644 index 00000000..58dda5a9 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_document.yml @@ -0,0 +1,57 @@ +_meta: + version: '1.0' + entity_type: node + uuid: 955c361d-1f45-48f9-812d-fe699a6de60f + bundle: islandora_object + default_langcode: en + depends: + 0c7da6e9-7295-46eb-afd0-16cf94462dce: node + a66edb41-4736-4bc8-8da3-9f801ef0ab0f: taxonomy_term + 23038c93-e6e1-41f8-b1de-663bd529f6bd: taxonomy_term + 6a6061d1-58ab-4a7f-9968-9836d48d72f8: taxonomy_term +default: + revision_uid: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + title: + - + value: 'Sample Document' + created: + - + value: 1668785776 + promote: + - + value: true + sticky: + - + value: false + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_extent: + - + value: '1 item' + field_member_of: + - + entity: 0c7da6e9-7295-46eb-afd0-16cf94462dce + field_model: + - + entity: a66edb41-4736-4bc8-8da3-9f801ef0ab0f + field_resource_type: + - + entity: 23038c93-e6e1-41f8-b1de-663bd529f6bd + field_viewer_override: + - + entity: 6a6061d1-58ab-4a7f-9968-9836d48d72f8 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_image.yml new file mode 100644 index 00000000..69c9f5fc --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_image.yml @@ -0,0 +1,53 @@ +_meta: + version: '1.0' + entity_type: node + uuid: 34fafe07-661c-44c7-8c34-27179a23d759 + bundle: islandora_object + default_langcode: en + depends: + 0c7da6e9-7295-46eb-afd0-16cf94462dce: node + ec911234-5830-41ea-b73d-307b370a5f2a: taxonomy_term + dd1732a5-d66d-498f-8860-bbc6fd63b195: taxonomy_term +default: + revision_uid: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + title: + - + value: 'Sample Image' + created: + - + value: 1668006672 + promote: + - + value: true + sticky: + - + value: false + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_extent: + - + value: '1 item' + field_member_of: + - + entity: 0c7da6e9-7295-46eb-afd0-16cf94462dce + field_model: + - + entity: ec911234-5830-41ea-b73d-307b370a5f2a + field_resource_type: + - + entity: dd1732a5-d66d-498f-8860-bbc6fd63b195 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_video.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_video.yml new file mode 100644 index 00000000..e1bebccd --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/content/node/sample_video.yml @@ -0,0 +1,53 @@ +_meta: + version: '1.0' + entity_type: node + uuid: 4c1d613d-36b9-40a6-99a2-488ad9330c2a + bundle: islandora_object + default_langcode: en + depends: + 0c7da6e9-7295-46eb-afd0-16cf94462dce: node + 25d9e1ec-0034-4adf-9a47-d93b36f9d63e: taxonomy_term + 06f1735c-b84e-4ffa-bef6-da06e0ccecb1: taxonomy_term +default: + revision_uid: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + title: + - + value: 'Sample Video' + created: + - + value: 1668001671 + promote: + - + value: true + sticky: + - + value: false + revision_translation_affected: + - + value: true + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + field_extent: + - + value: '1 item' + field_member_of: + - + entity: 0c7da6e9-7295-46eb-afd0-16cf94462dce + field_model: + - + entity: 25d9e1ec-0034-4adf-9a47-d93b36f9d63e + field_resource_type: + - + entity: 06f1735c-b84e-4ffa-bef6-da06e0ccecb1 diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_content/sample_content.info.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/sample_content.info.yml new file mode 100644 index 00000000..1334c3df --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_content/sample_content.info.yml @@ -0,0 +1,10 @@ +# This .info.yml files provides the basic information about our module to Drupal +# More: https://www.drupal.org/node/2000204 +name: Sample Content +description: "Sample content for testing" +type: module +package: Custom +version: 1.0 +core_version_requirement: ^8 || ^9 +dependencies: + - drupal:sample_core diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/composer.json b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/composer.json new file mode 100644 index 00000000..dc79bc5e --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/composer.json @@ -0,0 +1,27 @@ +{ + "name": "islandora/sample_core", + "description": "Required sample content for testing", + "type": "drupal-custom-module", + "keywords": ["Drupal", "Islandora"], + "homepage": "https://github.com/Islandora-Devops/isle-buildkit", + "support": { + "issues": "https://github.com/Islandora/documentation/issues" + }, + "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + } + ], + "require": { + "drupal/default_content": "^2.0@alpha" + }, + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Islandora Foundation", + "email": "community@islandora.ca", + "role": "Owner" + } + ] +} diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_display.openseadragon.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_display.openseadragon.yml new file mode 100644 index 00000000..a4c1e0de --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_display.openseadragon.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 16e30a08-9867-4894-8e5a-867c07d69409 + bundle: islandora_display + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Open Seadragon' + description: + - + value: 'Display using the Open Seadragon viewer' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://openseadragon.github.io' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_display.pdfjs.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_display.pdfjs.yml new file mode 100644 index 00000000..91f52ff2 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_display.pdfjs.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 6a6061d1-58ab-4a7f-9968-9836d48d72f8 + bundle: islandora_display + default_langcode: en +default: + status: + - + value: true + name: + - + value: PDFjs + description: + - + value: 'Display using the PDF.js viewer' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://mozilla.github.io/pdf.js' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.fits_file.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.fits_file.yml new file mode 100644 index 00000000..42ebd53f --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.fits_file.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 4238f4fd-0127-4027-b52b-990dab8eaad1 + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'FITS File' + description: + - + value: 'Technical Metadata associated with an original media file' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'https://projects.iq.harvard.edu/fits' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.intermediate_file.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.intermediate_file.yml new file mode 100644 index 00000000..c8c15c4e --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.intermediate_file.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: e3581d39-d3ea-4dd2-967f-c1140f486c19 + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Intermediate File' + description: + - + value: 'High quality representation of the Object, appropriate for generating derivatives or other additional processing' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#IntermediateFile' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.original_file.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.original_file.yml new file mode 100644 index 00000000..ae59345e --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.original_file.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 3397d872-5a18-4e04-bf0a-f1e5ba69f6d0 + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Original File' + description: + - + value: 'The original creation format of a file' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#OriginalFile' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.preservation_master_file.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.preservation_master_file.yml new file mode 100644 index 00000000..460ee835 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.preservation_master_file.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: c6a604f2-f612-463d-b82e-35b032f87728 + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Preservation Master File' + description: + - + value: 'Best quality representation of the Object appropriate for long-term preservation' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#PreservationMasterFile' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.service_file.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.service_file.yml new file mode 100644 index 00000000..217a3d7a --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.service_file.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: afc418da-8303-45bb-8639-0a9fc158c324 + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Service File' + description: + - + value: 'A medium quality representation of the Object appropriate for serving to users' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#ServiceFile' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.thumbnail_image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.thumbnail_image.yml new file mode 100644 index 00000000..ed9837d4 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.thumbnail_image.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 87352faf-272b-49f3-a5f5-241c8c9d89dc + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Thumbnail Image' + description: + - + value: 'A low resolution image representation of the Object appropriate for using as an icon' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#ThumbnailImage' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.transcript.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.transcript.yml new file mode 100644 index 00000000..ace34f6d --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_media_use.transcript.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 6ae2b742-32bc-4312-8554-0beb9e41590e + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: Transcript + description: + - + value: 'A textual representation of the Object appropriate for presenting to users, such as subtitles or transcript of a video. Can be used as a substitute or complement to other files for accessibility purposes' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#Transcript' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.audio.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.audio.yml new file mode 100644 index 00000000..7272ea59 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.audio.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 60c1d566-4693-412e-b184-9a208459f1d9 + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Audio + description: + - + value: 'A resource primarily intended to be heard. Examples include a music playback file format, an audio compact disc, and recorded speech or sounds' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://purl.org/coar/resource_type/c_18cc' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.binary.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.binary.yml new file mode 100644 index 00000000..a6134d33 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.binary.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 4e7608cd-1d66-489f-b362-92f202ff82aa + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Binary + description: + - + value: 'A generic binary file for repository items that don''t fall into any other category or cannot be shown in a browser' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://purl.org/coar/resource_type/c_1843' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.collection.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.collection.yml new file mode 100644 index 00000000..4c454f32 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.collection.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 4adbf9a6-08e6-4911-bd36-9cd0ab8e3b59 + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Collection + description: + - + value: 'A collection is an aggregation of items' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://purl.org/dc/dcmitype/Collection' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.compound_object.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.compound_object.yml new file mode 100644 index 00000000..6202940a --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.compound_object.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 67e21de9-6f01-4649-b98c-13f01499ff5e + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Compound Object' + description: + - + value: 'A special type of collection where the parent item may also have complex metadata' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://vocab.getty.edu/aat/300242735' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.digital_document.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.digital_document.yml new file mode 100644 index 00000000..a0964811 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.digital_document.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: a66edb41-4736-4bc8-8da3-9f801ef0ab0f + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Digital Document' + description: + - + value: 'An electronic file or document.' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'https://schema.org/DigitalDocument' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.image.yml new file mode 100644 index 00000000..9699bc70 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.image.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: ec911234-5830-41ea-b73d-307b370a5f2a + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Image + description: + - + value: 'A visual representation other than text, including all types of moving image and still image' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://purl.org/coar/resource_type/c_c513' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.newspaper.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.newspaper.yml new file mode 100644 index 00000000..96b978df --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.newspaper.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 4d551de2-b6d1-46d2-bcd0-ea263d065571 + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Newspaper + description: + - + value: 'A special type of collection which only has Newspaper Issues for children.' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'https://schema.org/Newspaper' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.page.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.page.yml new file mode 100644 index 00000000..ff25fe05 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.page.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: e64dbae9-4ee5-4dad-aaa5-e4a434787d7a + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Page + description: + - + value: 'A page in an Electronic Paged Content Object' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://id.loc.gov/ontologies/bibframe/part' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.paged_content.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.paged_content.yml new file mode 100644 index 00000000..ad28c28e --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.paged_content.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: e510cc34-5294-48e1-a81b-e89e79feb060 + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Paged Content' + description: + - + value: 'An Electronic Book, object with pages' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'https://schema.org/Book' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.publication_issue.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.publication_issue.yml new file mode 100644 index 00000000..4988331e --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.publication_issue.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 888ef0d7-e787-47fb-b236-ce94209feeeb + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Publication Issue' + description: + - + value: 'A part of a successively published publication such as a periodical or publication volume, often numbered, usually containing a grouping of works such as articles.' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'https://schema.org/PublicationIssue' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.video.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.video.yml new file mode 100644 index 00000000..39b77273 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/islandora_models.video.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 25d9e1ec-0034-4adf-9a47-d93b36f9d63e + bundle: islandora_models + default_langcode: en +default: + status: + - + value: true + name: + - + value: Video + description: + - + value: 'A recording of visual images, usually in motion and with sound accompaniment' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://purl.org/coar/resource_type/c_12ce' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.collection.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.collection.yml new file mode 100644 index 00000000..17aa16a5 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.collection.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: aecf7357-df20-4ce9-a1fa-5ae509995159 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Collection + description: + - + value: 'An aggregation of resources' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/ontology/bibo/Collection' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.dataset.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.dataset.yml new file mode 100644 index 00000000..2c80073e --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.dataset.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 23b05143-0e63-4f35-b98d-50b1b742a633 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Dataset + description: + - + value: 'Data encoded in a defined structure' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/Dataset' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.extracted_text.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.extracted_text.yml new file mode 100644 index 00000000..1370f765 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.extracted_text.yml @@ -0,0 +1,47 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: eb1c24fc-a405-4cd5-acfa-9d361a450c21 + bundle: islandora_media_use + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Extracted Text' + description: + - + value: 'A textual representation of the Object appropriate for fulltext indexing, such as a plaintext version of a document, or OCR text' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_external_uri: + - + uri: 'http://pcdm.org/use#ExtractedText' + title: '' + options: { } diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.image.yml new file mode 100644 index 00000000..a1693671 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.image.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: dd1732a5-d66d-498f-8860-bbc6fd63b195 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Image + description: + - + value: 'A visual representation other than text' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/Image' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.interactive_resource.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.interactive_resource.yml new file mode 100644 index 00000000..feb885e0 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.interactive_resource.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: a5d6a09b-fe24-497b-8159-aeafcce30529 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Interactive Resource' + description: + - + value: 'A resource requiring interaction from the user to be understood, executed, or experienced' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/InteractiveResource' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.moving_image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.moving_image.yml new file mode 100644 index 00000000..97350121 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.moving_image.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 06f1735c-b84e-4ffa-bef6-da06e0ccecb1 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Moving Image' + description: + - + value: 'A series of visual representations imparting an impression of motion when shown in succession' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/MovingImage' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.physical_object.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.physical_object.yml new file mode 100644 index 00000000..bd63fde2 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.physical_object.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 7337f3ea-69b6-4308-a444-7c0fb7e7f822 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Physical Object' + description: + - + value: 'An inanimate, three-dimensional object or substance' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/PhysicalObject' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.service.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.service.yml new file mode 100644 index 00000000..b77e9d03 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.service.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: bbbe265d-5069-438e-b5ec-ea48ad8940b7 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Service + description: + - + value: 'A system that provides one or more functions' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/Service' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.software.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.software.yml new file mode 100644 index 00000000..db46b7b2 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.software.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: f775b786-54f1-4a59-ac6f-bb4f9d98b96b + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Software + description: + - + value: 'A computer program in source or compiled form' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/Software' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.sound.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.sound.yml new file mode 100644 index 00000000..53c05ad3 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.sound.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: bd9d194c-2de7-43de-8f5e-df50d8ed2a99 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Sound + description: + - + value: 'A resource primarily intended to be heard' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/Sound' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.still_image.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.still_image.yml new file mode 100644 index 00000000..a9838d03 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.still_image.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 1b9a9398-7742-4815-a1eb-5126f3b28dd4 + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: 'Still Image' + description: + - + value: 'A static visual representation' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/StillImage' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.text.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.text.yml new file mode 100644 index 00000000..dca20421 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/content/taxonomy_term/resource_types.text.yml @@ -0,0 +1,48 @@ +_meta: + version: '1.0' + entity_type: taxonomy_term + uuid: 23038c93-e6e1-41f8-b1de-663bd529f6bd + bundle: resource_types + default_langcode: en +default: + status: + - + value: true + name: + - + value: Text + description: + - + value: 'A resource consisting primarily of words for reading' + format: '' + weight: + - + value: 0 + parent: + - + target_id: 0 + revision_translation_affected: + - + value: true + path: + - + alias: '' + langcode: en + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + content_translation_uid: + - + target_id: 1 + content_translation_created: + - + value: 1667998710 + field_authority_link: + - + uri: 'http://purl.org/dc/dcmitype/Text' + title: '' + options: { } + source: '' diff --git a/test/rootfs/var/www/drupal/web/modules/custom/sample_core/sample_core.info.yml b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/sample_core.info.yml new file mode 100644 index 00000000..19436524 --- /dev/null +++ b/test/rootfs/var/www/drupal/web/modules/custom/sample_core/sample_core.info.yml @@ -0,0 +1,10 @@ +# This .info.yml files provides the basic information about our module to Drupal +# More: https://www.drupal.org/node/2000204 +name: Sample Core +description: "Required sample content for testing" +type: module +package: Custom +version: 1.0 +core_version_requirement: ^8 || ^9 +dependencies: + - drupal:default_content diff --git a/test/tests/IntegrationTests/.env b/test/tests/IntegrationTests/.env new file mode 100644 index 00000000..a3f0e57b --- /dev/null +++ b/test/tests/IntegrationTests/.env @@ -0,0 +1,3 @@ +# Required for traefik on OSX (inconsistent behavior). +DOCKER_CLIENT_TIMEOUT=120 +COMPOSE_HTTP_TIMEOUT=120 diff --git a/test/tests/IntegrationTests/build.gradle.kts b/test/tests/IntegrationTests/build.gradle.kts new file mode 100644 index 00000000..f14f3046 --- /dev/null +++ b/test/tests/IntegrationTests/build.gradle.kts @@ -0,0 +1,7 @@ +import java.time.Duration.ofMinutes +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // This test requires more time that normal. + timeout.convention(ofMinutes(10)) +} diff --git a/test/tests/IntegrationTests/docker-compose.yml b/test/tests/IntegrationTests/docker-compose.yml new file mode 100644 index 00000000..caf62c94 --- /dev/null +++ b/test/tests/IntegrationTests/docker-compose.yml @@ -0,0 +1,96 @@ +# file: docker-compose.yml +# +# Tests the following: +# - Site starts. +# - Derivatives get created. +# - Content is index in Solr. +# - Content is index in Fedora. +# - Matomo is installed? +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +volumes: + drupal-solr-config: {} + +name: test-integrationtests +services: + alpaca: + <<: *common + image: ${ALPACA:-islandora/alpaca:local} + depends_on: + - activemq + - crayfits + - homarus + - houdini + - hypercube + crayfits: + <<: *common + image: ${CRAYFITS:-islandora/crayfits:local} + fits: + <<: *common + image: ${FITS:-islandora/fits:local} + homarus: + <<: *common + image: ${HOMARUS:-islandora/homarus:local} + houdini: + <<: *common + image: ${HOUDINI:-islandora/houdini:local} + hypercube: + <<: *common + image: ${HYPERCUBE:-islandora/hypercube:local} + mariadb: + <<: *common + image: ${MARIADB:-islandora/mariadb:local} + milliner: + <<: *common + image: ${MILLINER:-islandora/milliner:local} + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} + blazegraph: + <<: *common + image: ${BLAZEGRAPH:-islandora/blazegraph:local} + test: + <<: *common + image: ${TEST:-islandora/test:local} + environment: + # Keep this in sync with "islandora.drupal.properties" in the helm chart. + DRUPAL_DEFAULT_CANTALOUPE_URL: "http://test/cantaloupe/iiif/2" + DRUPAL_DEFAULT_CONFIGDIR: "/var/www/drupal/config/sync" + DRUPAL_DEFAULT_FCREPO_HOST: "fcrepo" + DRUPAL_DEFAULT_FCREPO_PORT: 8080 + DRUPAL_DEFAULT_FCREPO_URL: "http://fcrepo:8080/fcrepo/rest/" + DRUPAL_DEFAULT_INSTALL_EXISTING_CONFIG: "true" + DRUPAL_DEFAULT_MATOMO_URL_HTTP: "http://test/matomo/" + DRUPAL_DEFAULT_MATOMO_URL_HTTPS: "https://test/matomo/" + DRUPAL_DEFAULT_NAME: "Islandora Digital Collections" + DRUPAL_DEFAULT_PROFILE: "minimal" + DRUPAL_DEFAULT_SITE_URL: "test" + DRUPAL_DEFAULT_SOLR_CORE: "default" + DRUPAL_DRUSH_URI: "http://test" # Used by docker/drupal/rootfs/usr/local/share/custom/install.sh + DRUPAL_ENABLE_HTTPS: false + volumes: + - drupal-solr-config:/opt/solr/server/solr/default:ro + - ./test.sh:/test.sh # Test to run. + command: /test.sh # Run test and exit. + fcrepo: + <<: *common + image: ${FCREPO6:-islandora/fcrepo6:local} + environment: + FCREPO_ALLOW_EXTERNAL_DEFAULT: "http://default/" + FCREPO_ALLOW_EXTERNAL_DRUPAL: "http://test/" + depends_on: + - activemq + solr: + <<: *common + image: ${SOLR:-islandora/solr:local} + volumes: + - type: volume + source: drupal-solr-config + target: /opt/solr/server/solr/default + volume: + nocopy: true diff --git a/test/tests/IntegrationTests/test.sh b/test/tests/IntegrationTests/test.sh new file mode 100755 index 00000000..74e1d577 --- /dev/null +++ b/test/tests/IntegrationTests/test.sh @@ -0,0 +1,57 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +set -xeuo pipefail + +function node_count() { + local count="${1}" + test "$(drush sql-query 'select count(*) from node;')" -eq "${count}" +} + +function media_use_count() { + local name="${1}" + local count="${2}" + TID=$(drush sql-query "select tid from taxonomy_term_field_data where name = '${name}';") + test "$(drush sql-query "select count(*) from media__field_media_use where field_media_use_target_id = $TID;")" -eq "${count}" +} + +function solr_document_count() { + local count="${1}" + test "$(curl -sL 'solr:8983/solr/default/select?q=*:*&rows=0' | jq '.response.numFound')" -eq "${count}" +} + +function main() { + # Tests + echo "Perform Tests" + + sleep 30 + + echo "Confirm default Nodes were created." + node_count 5 + + echo "Confirm default Media was created." + media_use_count "Original File" 4 + + # Note: + # Test fails relatively often due to https://www.drupal.org/project/drupal/issues/2833539 + # occurring when Alpaca tries to write a derivative to Drupal + # Route that is the culprit: + # https://github.com/Islandora/islandora/blob/2923a1a8b9303569fdea4bdbf580c1f56e3ed033/islandora.routing.yml#L81-L89 + # Until this is resolved we can't really uncomment the checks below. + + #echo "Confirm FITS exists for each media item" + #media_use_count "FITS File" 4 + + #echo "Confirm Thumbnails were created." + #media_use_count "Thumbnail Image" 3 # Audio does not produce a thumbnail. + + #echo "Confirm Service Files were created." + #media_use_count "Service File" 3 # One for Image, Audio and Video. + + #echo "Confirm Extract Text was created." + #media_use_count "Extracted Text" 1 + + echo "Confirm Solr documents were created." + solr_document_count 5 +} +main diff --git a/tls.yml b/tls.yml new file mode 100644 index 00000000..54084e6f --- /dev/null +++ b/tls.yml @@ -0,0 +1,6 @@ +tls: + stores: + default: + defaultCertificate: + certFile: /etc/ssl/traefik/cert.pem + keyFile: /etc/ssl/traefik/privkey.pem diff --git a/tomcat/.dockerignore b/tomcat/.dockerignore index b43bf86b..1b2f9f5c 100644 --- a/tomcat/.dockerignore +++ b/tomcat/.dockerignore @@ -1 +1,4 @@ +build.gradle.kts README.md +tests +tests/**/* diff --git a/tomcat/Dockerfile b/tomcat/Dockerfile index 4bb0ba2d..5fe9ffea 100644 --- a/tomcat/Dockerfile +++ b/tomcat/Dockerfile @@ -1,29 +1,42 @@ -# syntax=docker/dockerfile:experimental -FROM local/java:latest +# syntax=docker/dockerfile:1.5.1 +FROM java -RUN --mount=id=downloads,type=cache,target=/opt/downloads \ - DOWNLOAD_CACHE_DIRECTORY="/opt/downloads" && \ - TOMCAT_VERSION="9.0.34" && \ +ARG TARGETARCH +ARG TOMCAT_VERSION="9.0.71" +ARG TOMCAT_FILE_SHA256="d78a3a09a67695d4f391d2e40713eeeb437bb201ad4571d200f9d23cc7868a78" + +EXPOSE 8080 + +WORKDIR /opt/tomcat + +RUN --mount=type=cache,id=tomcat-downloads-${TARGETARCH},sharing=locked,target=/opt/downloads \ TOMCAT_FILE="apache-tomcat-${TOMCAT_VERSION}.tar.gz" && \ TOMCAT_URL="https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin/${TOMCAT_FILE}" && \ - TOMCAT_FILE_SHA256="321de5b18a48ec09d2963d9faba4bfeafc7dd2203d80a2ef7e7a20b159e2120a" && \ - TOMCAT_SIG_SHA256="40cdb1433a3e080b26a9e791409fb3840364150b2f4594e19b3f7d0c97f7c736" && \ download.sh --url "${TOMCAT_URL}" --sha256 "${TOMCAT_FILE_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - download.sh --url "${TOMCAT_URL}.asc" --sha256 "${TOMCAT_SIG_SHA256}" "${DOWNLOAD_CACHE_DIRECTORY}" && \ - install-apache-service.sh \ - --name tomcat \ - --key "A9C5DF4D22E99998D9875A5110C01C5A2F6059E7" \ - --file "${DOWNLOAD_CACHE_DIRECTORY}/${TOMCAT_FILE}" \ - webapps/docs webapps/examples - -# Install reverse proxy to redirect from 80 to 8080. -RUN --mount=type=cache,target=/var/cache/apk \ - --mount=type=cache,target=/etc/cache/apk \ - apk-install.sh nginx && \ + download.sh \ + --url "${TOMCAT_URL}" \ + --sha256 "${TOMCAT_FILE_SHA256}" \ + --dest "/opt/tomcat" \ + --strip \ + webapps/docs webapps/examples \ + && \ cleanup.sh -WORKDIR /opt/tomcat +RUN create-service-user.sh \ + --name tomcat \ + --group jwt \ + /data \ + && \ + cleanup.sh -EXPOSE 8080 +ENV \ + TOMCAT_ADMIN_NAME=admin \ + TOMCAT_ADMIN_PASSWORD=password \ + TOMCAT_ADMIN_ROLES=manager-gui \ + TOMCAT_CONNECTION_TIMEOUT=20000 \ + TOMCAT_CATALINA_OPTS= \ + TOMCAT_JAVA_OPTS= \ + TOMCAT_LOG_LEVEL=INFO \ + TOMCAT_MANAGER_REMOTE_ADDRESS_VALVE=^.*$ -COPY rootfs / +COPY --link rootfs / diff --git a/tomcat/README.md b/tomcat/README.md index 9ff91e3a..6c3161ca 100644 --- a/tomcat/README.md +++ b/tomcat/README.md @@ -1,6 +1,6 @@ # Tomcat -Docker image for [Tomcat] version 9.0.34. +Docker image for [Tomcat] version 9.0.71. Please refer to the [Tomcat Documentation] for more in-depth information. @@ -9,7 +9,7 @@ to view the manager webapp on . ```bash docker run --rm -ti \ - -p 80:80 \ + -p 8080:8080 \ islandora/tomcat ``` @@ -30,39 +30,39 @@ additional settings, volumes, ports, etc. ## Settings -> N.B. For all of the settings below images that descend from -> ``islandora/tomcat`` will apply prefix to every setting. So for example -> `CATALINA_OPTS` would become `FCREPO_CATALINA_OPTS` this is to allow for -> different settings on a per-service basis. - -| Environment Variable | Etcd Key | Default | Description | -| :---------------------------------- | :----------------------------------- | :---------- | :------------------------------------------------------------------------------------ | -| CATALINA_OPTS | /catalina/opts | | | -| JAVA_OPTS | /java/opts | | | -| TOMCAT_ADMIN_NAME | /tomcat/admin/name | admin | The user name of the manager webapp admin user | -| TOMCAT_ADMIN_PASSWORD | /tomcat/admin/password | password | The password for the manager webapp admin user | -| TOMCAT_ADMIN_ROLES | /tomcat/admin/roles | manager-gui | Comma separated list of roles the user has | -| TOMCAT_LOG_LEVEL | /tomcat/log/level | ALL | Log level. Possible Values: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST or ALL | -| TOMCAT_MANAGER_REMOTE_ADDRESS_VALVE | /tomcat/manager/remote/address/valve | ^.*$ | Allows / blocks access to manager app to addresses which match this regex | +| Environment Variable | Default | Description | +| :---------------------------------- | :---------- | :------------------------------------------------------------------------------------ | +| TOMCAT_ADMIN_NAME | admin | The user name of the manager webapp admin user | +| TOMCAT_ADMIN_PASSWORD | password | The password for the manager webapp admin user | +| TOMCAT_ADMIN_ROLES | manager-gui | Comma separated list of roles the user has | +| TOMCAT_CATALINA_OPTS | | | +| TOMCAT_JAVA_OPTS | | | +| TOMCAT_LOG_LEVEL | INFO | Log level. Possible Values: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST or ALL | +| TOMCAT_MANAGER_REMOTE_ADDRESS_VALVE | ^.*$ | Allows / blocks access to manager app to addresses which match this regex | Additional users/groups/etc can be defined by adding more environment variables, following the above conventions: -| Environment Variable | Etcd Key | Description | -| :-------------------------- | :--------------------------- | :----------------------------------------- | -| TOMCAT_USER_{USER}_NAME | /tomcat/user/{USER}/name | The user name | -| TOMCAT_USER_{USER}_PASSWORD | /tomcat/user/{USER}/password | The password for the user | -| TOMCAT_USER_{USER}_ROLES | /tomcat/user/{USER}/roles | Comma separated list of roles the user has | +| Environment Variable | Description | +| :-------------------------- | :----------------------------------------- | +| TOMCAT_USER_{USER}_NAME | The user name | +| TOMCAT_USER_{USER}_PASSWORD | The password for the user | +| TOMCAT_USER_{USER}_ROLES | Comma separated list of roles the user has | > N.B. These do not have defaults. For example to add a new user `someone` you would need to define the following: -| Environment Variable | Etcd Key | Value | -| :--------------------------- | :---------------------------- | :------- | -| TOMCAT_USER_SOMEONE_NAME | /tomcat/user/someone/name | someone | -| TOMCAT_USER_SOMEONE_PASSWORD | /tomcat/user/someone/password | password | -| TOMCAT_USER_SOMEONE_ROLES | /tomcat/user/someone/roles | admin | +| Environment Variable | Value | +| :--------------------------- | :------- | +| TOMCAT_USER_SOMEONE_NAME | someone | +| TOMCAT_USER_SOMEONE_PASSWORD | password | +| TOMCAT_USER_SOMEONE_ROLES | admin | + +> N.B. For all of the settings above, images that descend from this image can +> apply a prefix to every setting. So for example `TOMCAT_CATALINA_OPTS` would +> become `FCREPO_TOMCAT_CATALINA_OPTS`. This is to allow for different settings +> on a per-service basis when sharing the same confd backend. [AJP]: https://tomcat.apache.org/tomcat-9.0-doc/config/ajp.html [Tomcat Documentation]: https://tomcat.apache.org/tomcat-9.0-doc/ diff --git a/tomcat/rootfs/etc/confd/conf.d/default.conf.toml b/tomcat/rootfs/etc/confd/conf.d/default.conf.toml deleted file mode 100644 index d984fe73..00000000 --- a/tomcat/rootfs/etc/confd/conf.d/default.conf.toml +++ /dev/null @@ -1,7 +0,0 @@ -[template] -src = "default.conf.tmpl" -dest = "/etc/nginx/conf.d/default.conf" -uid = 100 -gid = 101 -mode = "0644" -keys = [ "/nginx" ] diff --git a/tomcat/rootfs/etc/confd/conf.d/logging.properties.toml b/tomcat/rootfs/etc/confd/conf.d/logging.properties.toml index 40ccc567..ed6ea3d9 100644 --- a/tomcat/rootfs/etc/confd/conf.d/logging.properties.toml +++ b/tomcat/rootfs/etc/confd/conf.d/logging.properties.toml @@ -3,4 +3,4 @@ src = "logging.properties.tmpl" dest = "/opt/tomcat/conf/logging.properties" uid = 100 gid = 1000 -keys = ["/tomcat/admin/user", "/tomcat/admin/password"] +keys = [ "/" ] diff --git a/tomcat/rootfs/etc/confd/conf.d/manager.context.toml b/tomcat/rootfs/etc/confd/conf.d/manager.context.toml index 0480ca66..70a36faa 100644 --- a/tomcat/rootfs/etc/confd/conf.d/manager.context.toml +++ b/tomcat/rootfs/etc/confd/conf.d/manager.context.toml @@ -3,4 +3,4 @@ src = "manager.context.xml.tmpl" dest = "/opt/tomcat/webapps/manager/META-INF/context.xml" uid = 100 gid = 1000 -keys = ["/tomcat/manager/remote/address/valve"] +keys = [ "/" ] diff --git a/tomcat/rootfs/etc/confd/conf.d/server.xml.toml b/tomcat/rootfs/etc/confd/conf.d/server.xml.toml new file mode 100644 index 00000000..ef088afe --- /dev/null +++ b/tomcat/rootfs/etc/confd/conf.d/server.xml.toml @@ -0,0 +1,7 @@ +[template] +src = "server.xml.tmpl" +dest = "/opt/tomcat/conf/server.xml" +uid = 100 +gid = 1000 +mode = "0640" +keys = [ "/" ] diff --git a/tomcat/rootfs/etc/confd/conf.d/setenv.sh.toml b/tomcat/rootfs/etc/confd/conf.d/setenv.sh.toml deleted file mode 100644 index 7f0fbd2f..00000000 --- a/tomcat/rootfs/etc/confd/conf.d/setenv.sh.toml +++ /dev/null @@ -1,6 +0,0 @@ -[template] -src = "setenv.sh.tmpl" -dest = "/opt/tomcat/bin/setenv.sh" -uid = 100 -gid = 1000 -keys = ["/java/opts", "/catalina/opts"] diff --git a/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml b/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml index 196ecdde..f5ebde25 100644 --- a/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml +++ b/tomcat/rootfs/etc/confd/conf.d/tomcat-users.toml @@ -3,4 +3,4 @@ src = "tomcat-users.xml.tmpl" dest = "/opt/tomcat/conf/tomcat-users.xml" uid = 100 gid = 1000 -keys = ["/tomcat/admin/user", "/tomcat/admin/password"] +keys = [ "/" ] diff --git a/tomcat/rootfs/etc/confd/templates/default.conf.tmpl b/tomcat/rootfs/etc/confd/templates/default.conf.tmpl deleted file mode 100644 index a73eb265..00000000 --- a/tomcat/rootfs/etc/confd/templates/default.conf.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -server { - listen 80; - client_max_body_size {{ getv "/nginx/client/max/body/size" "0" }}; - location / { - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header Host $http_host; - proxy_pass "http://127.0.0.1:8080"; - } -} diff --git a/tomcat/rootfs/etc/confd/templates/logging.properties.tmpl b/tomcat/rootfs/etc/confd/templates/logging.properties.tmpl index cc824d9b..b3ef0457 100644 --- a/tomcat/rootfs/etc/confd/templates/logging.properties.tmpl +++ b/tomcat/rootfs/etc/confd/templates/logging.properties.tmpl @@ -22,7 +22,7 @@ handlers = java.util.logging.ConsoleHandler # Describes specific configuration info for Handlers. ############################################################ -java.util.logging.ConsoleHandler.level = {{ getv "/tomcat/log/level" "ALL" }} +java.util.logging.ConsoleHandler.level = {{ getenv "TOMCAT_LOG_LEVEL" }} java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter java.util.logging.ConsoleHandler.encoding = UTF-8 @@ -37,4 +37,4 @@ java.util.logging.ConsoleHandler.encoding = UTF-8 #org.apache.coyote.http2.level = FINE # To see debug messages for WebSocket handling, uncomment the following line: -#org.apache.tomcat.websocket.level = FINE \ No newline at end of file +#org.apache.tomcat.websocket.level = FINE diff --git a/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl b/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl index ab46261c..5efd41dc 100644 --- a/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl +++ b/tomcat/rootfs/etc/confd/templates/manager.context.xml.tmpl @@ -18,6 +18,6 @@ + allow="{{ getenv "TOMCAT_MANAGER_REMOTE_ADDRESS_VALVE" }}" /> diff --git a/tomcat/rootfs/etc/confd/templates/server.xml.tmpl b/tomcat/rootfs/etc/confd/templates/server.xml.tmpl new file mode 100644 index 00000000..2f67e566 --- /dev/null +++ b/tomcat/rootfs/etc/confd/templates/server.xml.tmpl @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tomcat/rootfs/etc/confd/templates/setenv.sh.tmpl b/tomcat/rootfs/etc/confd/templates/setenv.sh.tmpl deleted file mode 100755 index 789681e5..00000000 --- a/tomcat/rootfs/etc/confd/templates/setenv.sh.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -export JAVA_OPTS="{{ getv "/java/opts" "" }}" -export CATALINA_OPTS="{{ getv "/catalina/opts" "" }}" diff --git a/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl b/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl index 7e1c42cc..b137d2cf 100644 --- a/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl +++ b/tomcat/rootfs/etc/confd/templates/tomcat-users.xml.tmpl @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> - - {{ range $dir := lsdir "/user" }} + + {{ range $dir := lsdir "/tomcat/user" }} {{ end }} diff --git a/tomcat/rootfs/etc/cont-init.d/02-ngnix-install.sh b/tomcat/rootfs/etc/cont-init.d/02-ngnix-install.sh deleted file mode 100755 index b952b50f..00000000 --- a/tomcat/rootfs/etc/cont-init.d/02-ngnix-install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -e - -mkdir /run/nginx &> /dev/null || true - -# Change log files to redirect to stdout/stderr -ln -sf /dev/stdout /var/log/nginx/access.log -chown nginx:nginx /var/log/nginx/access.log - -ln -sf /dev/stderr /var/log/nginx/error.log -chown nginx:nginx /var/log/nginx/error.log diff --git a/tomcat/rootfs/etc/nginx/modules/daemon.conf b/tomcat/rootfs/etc/nginx/modules/daemon.conf deleted file mode 100644 index ef1f9c1c..00000000 --- a/tomcat/rootfs/etc/nginx/modules/daemon.conf +++ /dev/null @@ -1 +0,0 @@ -daemon off; diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/environment-override-tomcat b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/environment-override-tomcat new file mode 100644 index 00000000..e69de29b diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/dependencies.d/container-environment b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/type b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/type @@ -0,0 +1 @@ +oneshot diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/up b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/up new file mode 100755 index 00000000..451b375c --- /dev/null +++ b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/environment-override-tomcat/up @@ -0,0 +1,2 @@ +# Allow TOMCAT_LOG_LEVEL to be overridden by FEDORA_TOMCAT_LOG_LEVEL, etc. +/usr/local/bin/confd-override-environment.sh --prefix TOMCAT diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/dependencies.d/ready b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/dependencies.d/ready new file mode 100644 index 00000000..e69de29b diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/finish b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/finish new file mode 100755 index 00000000..4096c5e8 --- /dev/null +++ b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/finish @@ -0,0 +1,2 @@ +#!/command/execlineb -S2 +/usr/local/share/s6/finish ${1} ${2} diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/run b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/run new file mode 100755 index 00000000..1ef17ba7 --- /dev/null +++ b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/run @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -e + +# Many services deployed into tomcat need somewhere to write data, by convention +# we make this /data. +# +# When bind mounting we need to ensure that we +# actually can write to the folder. +chown tomcat:tomcat /data + +exec with-contenv s6-setuidgid tomcat /opt/tomcat/bin/catalina.sh run diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/type b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/tomcat/type @@ -0,0 +1 @@ +longrun diff --git a/tomcat/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/tomcat b/tomcat/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/tomcat new file mode 100644 index 00000000..e69de29b diff --git a/tomcat/rootfs/etc/services.d/nginx/finish b/tomcat/rootfs/etc/services.d/nginx/finish deleted file mode 100644 index 9030da41..00000000 --- a/tomcat/rootfs/etc/services.d/nginx/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh: -s6-svscanctl -t /var/run/s6/services diff --git a/tomcat/rootfs/etc/services.d/nginx/run b/tomcat/rootfs/etc/services.d/nginx/run deleted file mode 100644 index 7503678e..00000000 --- a/tomcat/rootfs/etc/services.d/nginx/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh: -/usr/sbin/nginx diff --git a/tomcat/rootfs/etc/services.d/tomcat/finish b/tomcat/rootfs/etc/services.d/tomcat/finish deleted file mode 100644 index f8984dd3..00000000 --- a/tomcat/rootfs/etc/services.d/tomcat/finish +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/execlineb -S1 -# -*- mode: sh -*- -# vi: set ft=sh : -s6-svscanctl -t /var/run/s6/services diff --git a/tomcat/rootfs/etc/services.d/tomcat/run b/tomcat/rootfs/etc/services.d/tomcat/run deleted file mode 100644 index b66a361b..00000000 --- a/tomcat/rootfs/etc/services.d/tomcat/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/execlineb -P -# -*- mode: sh -*- -# vi: set ft=sh : -with-contenv -s6-setuidgid tomcat -/opt/tomcat/bin/catalina.sh run diff --git a/tomcat/rootfs/opt/tomcat/bin/setenv.sh b/tomcat/rootfs/opt/tomcat/bin/setenv.sh new file mode 100755 index 00000000..c69a73c5 --- /dev/null +++ b/tomcat/rootfs/opt/tomcat/bin/setenv.sh @@ -0,0 +1,4 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +export JAVA_OPTS="${TOMCAT_JAVA_OPTS}" +export CATALINA_OPTS="${TOMCAT_CATALINA_OPTS}" diff --git a/tomcat/rootfs/usr/local/bin/install-war-into-tomcat.sh b/tomcat/rootfs/usr/local/bin/install-war-into-tomcat.sh deleted file mode 100755 index bf73eff2..00000000 --- a/tomcat/rootfs/usr/local/bin/install-war-into-tomcat.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash -set -e - -readonly PROGNAME=$(basename $0) -readonly ARGS="$@" - -function usage { - cat <<- EOF - usage: $PROGNAME options [FILE]... - - Installs the given war into tomcat. - - OPTIONS: - -n --name The name to use for the unpacked war. - -f --file The location to copy the war from. - -h --help Show this help. - -x --debug Debug this script. - - The options --file and --url are mutually exclusive. - - Examples: - Install Blazegraph as bigdata: - $PROGNAME --name "bigdata" --file /opt/downloads/blazegraph.war" -EOF -} - -function cmdline { - local arg= - for arg - do - local delim="" - case "$arg" in - # Translate --gnu-long-options to -g (short options) - --name) args="${args}-n ";; - --file) args="${args}-f ";; - --help) args="${args}-h ";; - --debug) args="${args}-x ";; - # Pass through anything else - *) [[ "${arg:0:1}" == "-" ]] || delim="\"" - args="${args}${delim}${arg}${delim} ";; - esac - done - - # Reset the positional parameters to the short options - eval set -- $args - - while getopts "n:f:hx" OPTION - do - case $OPTION in - n) - readonly NAME=${OPTARG} - readonly DEPLOY_DIRECTORY="/opt/tomcat/webapps/${NAME}" - ;; - f) - readonly FILE=${OPTARG} - ;; - h) - usage - exit 0 - ;; - x) - readonly DEBUG='-x' - set -x - ;; - esac - done - - if [[ -z $NAME || -z $FILE ]]; then - echo "Missing one of required options: --name --file" - exit 1 - fi - - return 0 -} - -function main { - cmdline ${ARGS} - s6-setuidgid tomcat mkdir "${DEPLOY_DIRECTORY}" - s6-setuidgid tomcat unzip "${FILE}" -d "${DEPLOY_DIRECTORY}" -} -main diff --git a/tomcat/tests/ServiceStartsWithDefaults/build.gradle.kts b/tomcat/tests/ServiceStartsWithDefaults/build.gradle.kts new file mode 100644 index 00000000..daaa68db --- /dev/null +++ b/tomcat/tests/ServiceStartsWithDefaults/build.gradle.kts @@ -0,0 +1,6 @@ +import plugins.TestsPlugin.DockerComposeUp + +tasks.named("test") { + // Remove 143 when https://github.com/Islandora-Devops/isle-buildkit/issues/269 is resolved. + expectExitCodes("tomcat", 0, 143) +} diff --git a/tomcat/tests/ServiceStartsWithDefaults/docker-compose.yml b/tomcat/tests/ServiceStartsWithDefaults/docker-compose.yml new file mode 100644 index 00000000..295bb52f --- /dev/null +++ b/tomcat/tests/ServiceStartsWithDefaults/docker-compose.yml @@ -0,0 +1,16 @@ +--- +version: "3.8" + +# Common to all services +x-common: &common + restart: "no" + +name: tomcat-servicestartswithdefaults +services: + tomcat: + <<: *common + image: ${TOMCAT:-islandora/tomcat:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/tomcat/tests/ServiceStartsWithDefaults/test.sh b/tomcat/tests/ServiceStartsWithDefaults/test.sh new file mode 100755 index 00000000..cfb0e778 --- /dev/null +++ b/tomcat/tests/ServiceStartsWithDefaults/test.sh @@ -0,0 +1,11 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source /usr/local/share/isle/utilities.sh + +# Wait for service to start. +wait_20x http://localhost:8080/ + +# Service must start for us to get to this point. +exit 0