diff --git a/.github/workflows/http-tests.yml b/.github/workflows/http-tests.yml index 7d886a3d10..40f1716612 100644 --- a/.github/workflows/http-tests.yml +++ b/.github/workflows/http-tests.yml @@ -33,6 +33,14 @@ jobs: - name: Add bin/ and its subdirectories to PATH run: | find "$GITHUB_WORKSPACE/bin" -type d >> "$GITHUB_PATH" + # cli/ resolves linkeddatahub-rdf by ${project.version}, and the library lives in this same + # checkout - so it is built here rather than fetched. Resolving a sibling through a remote + # repository would make every version bump wait on a publish: the post-release develop asks + # for a SNAPSHOT nothing has deployed yet, and the release tag asks for a version Central has + # not seen. `make cli` does the same thing locally. + - name: Build the linkeddatahub-rdf library + run: mvn -B install + working-directory: rdf - name: Build the ldh CLI run: mvn -B package # the CLI unit tests run here; the suite drives ldh for its fixtures working-directory: cli diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3768a94e6f..385670d70d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,9 +5,26 @@ on: tags: - '*' +env: + PLATFORM_IMAGE: atomgraph/linkeddatahub + SEF_COMPILER_IMAGE: atomgraph/linkeddatahub-sef-compiler + jobs: + # one job per architecture, each on a runner of that architecture. A single multi-platform build + # runs the arm64 leg through QEMU, which puts javac, the Saxon SEF compile and npm at a fraction + # of native speed and serializes it behind the amd64 one. These push untagged manifests by + # digest; the manifest job below assembles them into the tagged manifest lists docker: - runs-on: ubuntu-latest + strategy: + matrix: + include: + - platform: linux/amd64 + arch: amd64 + runner: ubuntu-latest + - platform: linux/arm64 + arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} steps: - name: Login to Docker Hub uses: docker/login-action@v4 @@ -15,14 +32,83 @@ jobs: username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 + # no checkout step: with no context input the action builds from the Git context, so buildx + # clones the tag itself + + - name: Build and push the platform image + id: platform + uses: docker/build-push-action@v6 + with: + platforms: ${{ matrix.platform }} + tags: ${{ env.PLATFORM_IMAGE }} # the repository alone: these manifests are pushed untagged, by digest + outputs: type=image,push-by-digest=true,name-canonical=true,push=true + cache-from: type=gha,scope=platform-${{ matrix.arch }} + cache-to: type=gha,mode=max,scope=platform-${{ matrix.arch }} + + # the sef-compiler service composes each dataspace's client stylesheet with its package + # stylesheets, so a deployment that consumes images rather than building them needs it + # published under the same version as the platform it compiles for. Same Dockerfile, same + # tag, one stage earlier - the two images are only ever released together. + # + # It reads the platform scope too, which is where the maven stage the two share was exported. + # Separate scopes rather than one: each build exports only the stages it reaches, and a shared + # scope would have them overwrite each other's export on every run + - name: Build and push the SEF compiler image + id: sef-compiler + uses: docker/build-push-action@v6 + with: + platforms: ${{ matrix.platform }} + target: sef-compiler + tags: ${{ env.SEF_COMPILER_IMAGE }} # the repository alone: these manifests are pushed untagged, by digest + outputs: type=image,push-by-digest=true,name-canonical=true,push=true + cache-from: | + type=gha,scope=sef-compiler-${{ matrix.arch }} + type=gha,scope=platform-${{ matrix.arch }} + cache-to: type=gha,mode=max,scope=sef-compiler-${{ matrix.arch }} + + # one empty file per digest, named after it: the manifest job addresses the images it assembles + # by digest and needs nothing else from this one + - name: Export the digests + env: + PLATFORM_DIGEST: ${{ steps.platform.outputs.digest }} + SEF_COMPILER_DIGEST: ${{ steps.sef-compiler.outputs.digest }} + run: | + mkdir -p /tmp/digests/platform /tmp/digests/sef-compiler + touch "/tmp/digests/platform/${PLATFORM_DIGEST#sha256:}" + touch "/tmp/digests/sef-compiler/${SEF_COMPILER_DIGEST#sha256:}" + + - name: Upload the digests + uses: actions/upload-artifact@v4 + with: + name: digests-${{ matrix.arch }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + # assemble one tagged manifest list per image from the per-architecture manifests pushed above + manifest: + name: Assemble the multi-architecture manifests + needs: docker + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # the digest file names are unique per architecture, so the artifacts merge into one tree + - name: Download the digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + - name: Extract version parts - id: version run: | RAW_REF="${{ github.ref_name }}" # strip the literal prefix @@ -34,32 +120,24 @@ jobs: echo "MINOR=$MAJOR.$MINOR" >> $GITHUB_ENV echo "FULL_VERSION=$VERSION" >> $GITHUB_ENV - - name: Build and push the platform image - uses: docker/build-push-action@v6 - with: - platforms: linux/amd64,linux/arm64 - push: true - tags: | - atomgraph/linkeddatahub:latest - atomgraph/linkeddatahub:${{ env.FULL_VERSION }} - atomgraph/linkeddatahub:${{ env.MINOR }} - atomgraph/linkeddatahub:${{ env.MAJOR }} + - name: Create the manifest lists + run: | + create_manifest() { + image="$1" + refs=() + for digest in "/tmp/digests/$2"/*; do + refs+=("$image@sha256:$(basename "$digest")") + done + docker buildx imagetools create \ + -t "$image:latest" \ + -t "$image:$FULL_VERSION" \ + -t "$image:$MINOR" \ + -t "$image:$MAJOR" \ + "${refs[@]}" + } - # the sef-compiler service composes each dataspace's client stylesheet with its package - # stylesheets, so a deployment that consumes images rather than building them needs it - # published under the same version as the platform it compiles for. Same Dockerfile, same - # tag, one stage earlier - the two images are only ever released together - - name: Build and push the SEF compiler image - uses: docker/build-push-action@v6 - with: - platforms: linux/amd64,linux/arm64 - push: true - target: sef-compiler - tags: | - atomgraph/linkeddatahub-sef-compiler:latest - atomgraph/linkeddatahub-sef-compiler:${{ env.FULL_VERSION }} - atomgraph/linkeddatahub-sef-compiler:${{ env.MINOR }} - atomgraph/linkeddatahub-sef-compiler:${{ env.MAJOR }} + create_manifest "$PLATFORM_IMAGE" platform + create_manifest "$SEF_COMPILER_IMAGE" sef-compiler cli: name: Attach the ldh CLI to the release diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 8ee87d65c7..4d59b17b13 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -33,6 +33,14 @@ jobs: - name: Add bin/ and its subdirectories to PATH run: | find "$GITHUB_WORKSPACE/bin" -type d >> "$GITHUB_PATH" + # cli/ resolves linkeddatahub-rdf by ${project.version}, and the library lives in this same + # checkout - so it is built here rather than fetched. Resolving a sibling through a remote + # repository would make every version bump wait on a publish: the post-release develop asks + # for a SNAPSHOT nothing has deployed yet, and the release tag asks for a version Central has + # not seen. `make cli` does the same thing locally. + - name: Build the linkeddatahub-rdf library + run: mvn -B install + working-directory: rdf - name: Build the ldh CLI run: mvn -B package # the suite builds its fixtures with ldh, the way tests/http does working-directory: cli diff --git a/CHANGELOG.md b/CHANGELOG.md index f55545e80e..3439ae449f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,29 @@ +## [Unreleased] +### Migration +- **BREAKING**: `ldh` drops `-b`/`--base`; dataspace-level commands take the base URI as their positional, defaulting to `LDH_BASE` +- `Link` relation types are always quoted, e.g. `rel="timemap"` +- Runtime settings are kept as a change set in `settings/dataspaces.ru`; an existing `settings/dataspaces.trig` is converted once + +### Changed +- `ldh add file`, `import csv`, `import rdf` and `push` derive the upload URI from the target document +- `Link` headers are built with `jakarta.ws.rs.core.Link`, keeping empty fragments such as `ns#` +- Release images are built natively per architecture, with a layer cache +- `MAX_CONN_PER_ROUTE`, `MAX_TOTAL_CONN` and `MAX_REQUEST_RETRIES` are passed as system properties +- The browser parses and serialises SPARQL with SPARQL.js alone; `SPARQLBuilder.js` is gone + +### Fixed +- ORCID endpoints derive from `ORCID_ISSUER` (default `https://orcid.org`) instead of the hardwired sandbox +- Concurrent writes quoting the same `ETag` no longer both pass `If-Match` +- Runtime settings no longer mask later edits to `config/dataspaces.trig` and `config/system.trig` +- Restoring a version from a historical view no longer fails `412` +- An unwritten versioned document has an empty TimeMap instead of `404` +- The History dialog names every author, not only the signed-in agent +- The request access dialog names the signed-in agent instead of showing their WebID +- A malformed `Accept-Language` is ignored instead of causing a `500` +- Views support an aliased first variable, and say when it binds no resources +- The file drop overlay clears when a drag leaves the window early +- CI builds `linkeddatahub-rdf` from the checkout, so version bumps no longer break the suites + ## [6.0.1] - 2026-09-30 ### Added - `linkeddatahub-rdf`, a separately published library of the vocabularies and the document shapes the HTTP API accepts, so the CLI and other clients build against one description of the request bodies diff --git a/Dockerfile b/Dockerfile index a5ad77f187..a95246e1fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,13 +11,19 @@ RUN mkdir /jena && \ tar -xzf - -C /jena # copy platform source code and POM +# +# the POM comes first and resolves the dependency tree in a layer of its own, so a source change +# does not invalidate it. go-offline does not cover every profile-bound plugin, which is why the +# install below stays online and fetches whatever is left rather than failing on it WORKDIR /usr/src/platform -COPY src /usr/src/platform/src - COPY pom.xml /usr/src/platform/pom.xml +RUN mvn -B -Pstandalone dependency:go-offline + +COPY src /usr/src/platform/src + RUN mvn -Pstandalone clean install # ============================== diff --git a/README.md b/README.md index 228587c121..c6a90abbdf 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ LinkedDataHub includes an HTTP [test suite](https://github.com/AtomGraph/LinkedD ### Browser * [Saxon-JS](https://www.saxonica.com/saxon-js/) -* [SPARQLBuilder](https://github.com/AtomGraph/sparql-builder) +* [SPARQL.js](https://github.com/RubenVerborgh/SPARQL.js) * [OpenLayers](https://openlayers.org) * [Google Charts](https://developers.google.com/chart) * [xml-c14n-sync](https://github.com/AtomGraph/xml-c14n-sync) diff --git a/cli/README.md b/cli/README.md index 08d8bfbfb9..5fa75145f8 100644 --- a/cli/README.md +++ b/cli/README.md @@ -111,9 +111,21 @@ Repeated options can be set once via environment variables: |---|---| | `LDH_CERT_FILE` | `-c`, `--cert` | | `LDH_CERT_PASSWORD` | `-p`, `--cert-password` | -| `LDH_BASE` | `-b`, `--base` | +| `LDH_BASE` | `BASE_URI`, the positional of the dataspace-addressing commands | | `LDH_PROXY` | `--proxy` | +The commands that address no document of their own take the dataspace's base URI as their positional +argument instead, where every other command puts its target: the `packages` family, +`admin clear ontology`, `admin create ontology`, `admin create group`, `admin create authorization`, +`admin import ontology` and `admin make-public`. `LDH_BASE` is its default, so with it exported the +argument is left out: + +```bash +ldh packages add --package https://packages.linkeddatahub.com/editor/taxonomy/#this https://localhost:4443/ +ldh admin clear ontology https://admin.localhost:4443/ +ldh admin create group --name Editors --member "$AGENT_URI" https://admin.localhost:4443/ +``` + ```bash export LDH_CERT_FILE=ssl/owner/keystore.p12 LDH_CERT_PASSWORD=... LDH_BASE=https://localhost:4443/ @@ -138,7 +150,7 @@ without them (the taxonomy editor package rejects a concept with no `skos:inSche - Commands that create or append to a document print its URL as the only line on stdout, so shell pipelines keep working: `item=$(ldh create item ...)`. `add file` prints the content-addressed - upload URI (`{base}uploads/{sha1}`). All diagnostics go to stderr. + upload URI (`uploads/{sha1}` under the root of the document's origin). All diagnostics go to stderr. - `push` writes many documents in one run and prints one line per written document URL or upload URI, in write order, so the listing greps and cuts like `packages list` does. Progress (`PUT <- `, `POST <- `) and `Skipping ` lines go to stderr. On the @@ -210,7 +222,7 @@ ldh packages list | grep ^available | cut -f2 The registry defaults to `https://packages.linkeddatahub.com/` and `--registry` overrides it. It is read through the application's Linked Data proxy rather than fetched directly, the same way the -application settings modal reads it, so `packages list` needs `--base` as much as the other two do. +application settings modal reads it, so `packages list` needs the application URI as much as the other two do. The commands go through `PATCH /settings`, which is the live path: the change is in effect immediately but lives in the running application's context dataset. Declaring the same @@ -235,7 +247,7 @@ With `D` the URL of the directory being walked (`TARGET_URI` for the pushed dire - Any other RDF file `name.ext` is `PUT` to `D/name/`, with its relative URIs resolved against that URL (the same `turtle --base` resolution `put` applies). - Every other file is uploaded into `D`, as `add file` would: title = file name, media type - detected, upload URI `{base}uploads/{sha1}`. + detected, upload URI `uploads/{sha1}` under the root of the document's origin. - A subdirectory `name` maps to `D/name/`: its document is the RDF file `name.ext` beside it, its files are uploaded into that document, and its subdirectories recurse. @@ -309,6 +321,10 @@ shell scripts. ### Differences from the scripts +- `-b/--base` is gone. The commands that take a document URI never needed it (the scripts required it + but never read it, resolving relative URIs against the target instead; the upload URI `add file`, + `import csv`, `import rdf` and `push` print is `uploads/{sha1}` under the root of the target's + origin), and the ones that act on the dataspace itself take its base URI as the positional argument. - `-f/--cert-pem-file` is now `-c/--cert` and takes either the PKCS12 keystore or the PEM the scripts fed `curl -E`, whichever is at hand. - `admin create group` writes the `--name` value into `foaf:name`/`dct:title` (the script wrote an diff --git a/cli/pom.xml b/cli/pom.xml index 650801be75..3151843ac2 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -4,7 +4,7 @@ com.atomgraph linkeddatahub-cli - 6.0.1 + 6.1.0-SNAPSHOT jar LinkedDataHub CLI @@ -17,28 +17,13 @@ 3.1.11 - - - - central-portal-snapshots - https://central.sonatype.com/repository/maven-snapshots/ - - false - - - true - - - - + clients; this project adds the command line over them. Built from rdf/ in this same + checkout - `make cli` and the workflows install it first - and deliberately resolvable + from nowhere else: a remote fallback would let a build quietly use an older published + snapshot instead of failing when that step is missing. --> com.atomgraph linkeddatahub-rdf ${project.version} diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddConstruct.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddConstruct.java index 38f5f7eabc..f1019482ab 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddConstruct.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddConstruct.java @@ -18,14 +18,12 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.http.LDHClient; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Queries; import com.atomgraph.linkeddatahub.rdf.vocabulary.SP; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -38,9 +36,6 @@ public class AddConstruct extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the query") private String title; @@ -62,8 +57,6 @@ public class AddConstruct extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - core(getClient(), target, uri, title, Files.readString(queryFile), service, description); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddFile.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddFile.java index a3f5df769d..221aaf2694 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddFile.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddFile.java @@ -19,7 +19,6 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.http.HttpException; import com.atomgraph.linkeddatahub.cli.http.LDHClient; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Digests; import com.atomgraph.linkeddatahub.rdf.vocabulary.NFO; import jakarta.ws.rs.client.Entity; @@ -35,7 +34,6 @@ import org.glassfish.jersey.media.multipart.FormDataMultiPart; import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -48,9 +46,6 @@ public class AddFile extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the file") private String title; @@ -69,9 +64,7 @@ public class AddFile extends BaseCommand @Override public Integer call() throws Exception { - URI base = baseMixin.require(getSpec()); - - URI fileURI = core(getClient(), base, target, file, contentType, title, description); + URI fileURI = core(getClient(), target, file, contentType, title, description); print(fileURI); return 0; @@ -83,7 +76,6 @@ public Integer call() throws Exception * its ol/ou value. * * @param client client instance - * @param base application base URI * @param target target document URI * @param file file path * @param contentType file media type (optional, auto-detected if null) @@ -92,7 +84,7 @@ public Integer call() throws Exception * @return upload URI derived from the SHA1 hash of the file content * @throws IOException file read error */ - public static URI core(LDHClient client, URI base, URI target, Path file, String contentType, String title, String description) throws IOException + public static URI core(LDHClient client, URI target, Path file, String contentType, String title, String description) throws IOException { String fileContentType = contentType != null ? contentType : detectContentType(file); @@ -101,20 +93,21 @@ public static URI core(LDHClient client, URI base, URI target, Path file, String HttpException.check(target, client.post(target, Entity.entity(multiPart, multiPart.getMediaType()), ACCEPT_TURTLE)).close(); } - return uploadURI(base, file); + return uploadURI(target, file); } /** - * Returns the content-addressed URI an upload gets, {base}uploads/{sha1}. It is - * derived from the file content alone, so it can be computed without sending the file. + * Returns the content-addressed URI an upload gets, uploads/{sha1} under the root of + * the target document's dataspace. It is derived from the file content alone, so it can be computed + * without sending the file. * - * @param base application base URI + * @param target target document URI * @param file file path * @return upload URI */ - public static URI uploadURI(URI base, Path file) + public static URI uploadURI(URI target, Path file) { - return URI.create(base.toString() + "uploads/" + Digests.sha1Hex(file)); + return target.resolve("/uploads/" + Digests.sha1Hex(file)); } /** diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddGenericService.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddGenericService.java index 7952b53070..f85e253376 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddGenericService.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddGenericService.java @@ -17,11 +17,9 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Services; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -34,9 +32,6 @@ public class AddGenericService extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the service") private String title; @@ -64,8 +59,6 @@ public class AddGenericService extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Services.service(target, uri, title, endpoint, graphStore, authUser, authPwd, description)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddResultSetChart.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddResultSetChart.java index cb3eefb0a9..744c806e33 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddResultSetChart.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddResultSetChart.java @@ -17,11 +17,9 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Views; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -34,9 +32,6 @@ public class AddResultSetChart extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the chart") private String title; @@ -64,8 +59,6 @@ public class AddResultSetChart extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Views.resultSetChart(target, uri, title, query, chartType, categoryVarName, seriesVarName, description)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddSelect.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddSelect.java index 0e3530f481..13f2cd475d 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddSelect.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddSelect.java @@ -17,14 +17,12 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Queries; import com.atomgraph.linkeddatahub.rdf.vocabulary.SP; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -37,9 +35,6 @@ public class AddSelect extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the query") private String title; @@ -61,8 +56,6 @@ public class AddSelect extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Queries.query(target, uri, SP.Select, title, Files.readString(queryFile), service, description)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddView.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddView.java index d6c313370c..aac877df4a 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddView.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/AddView.java @@ -17,11 +17,9 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Views; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -34,9 +32,6 @@ public class AddView extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--query", required = true, paramLabel = "QUERY_URI", description = "URI of the SELECT query") private URI query; @@ -58,8 +53,6 @@ public class AddView extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Views.view(target, uri, query, title, description, mode)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateContainer.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateContainer.java index b1ec21a465..ca2cea5012 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateContainer.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateContainer.java @@ -17,13 +17,11 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Documents; import com.atomgraph.linkeddatahub.rdf.Slugs; import com.atomgraph.linkeddatahub.rdf.URIs; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; /** @@ -35,9 +33,6 @@ public class CreateContainer extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the container") private String title; @@ -62,8 +57,6 @@ public class CreateContainer extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - URI doc = URIs.childURI(parent, slug != null ? slug : Slugs.defaultSlug()); put(getClient(), doc, Documents.container(doc, title, description, block, mode, primaryTopic)); print(doc); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateItem.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateItem.java index 526342dc37..ccd235fe0b 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateItem.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/CreateItem.java @@ -17,13 +17,11 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Documents; import com.atomgraph.linkeddatahub.rdf.Slugs; import com.atomgraph.linkeddatahub.rdf.URIs; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; /** @@ -35,9 +33,6 @@ public class CreateItem extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the item") private String title; @@ -56,8 +51,6 @@ public class CreateItem extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - URI doc = URIs.childURI(container, slug != null ? slug : Slugs.defaultSlug()); put(getClient(), doc, Documents.item(doc, title, description, primaryTopic)); print(doc); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/Push.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/Push.java index 0ec7073bed..72f38b9eed 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/Push.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/Push.java @@ -17,7 +17,6 @@ package com.atomgraph.linkeddatahub.cli.command; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.cli.util.PushPlan; import com.atomgraph.linkeddatahub.cli.util.PushPlan.Step; import java.io.IOException; @@ -26,7 +25,6 @@ import java.nio.file.Path; import org.apache.jena.rdf.model.Model; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.ParameterException; import picocli.CommandLine.Parameters; @@ -43,9 +41,6 @@ public class Push extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--dir", defaultValue = ".", paramLabel = "DIR", description = "Directory to push (default: current directory)") private Path dir; @@ -58,12 +53,11 @@ public class Push extends BaseCommand @Override public Integer call() throws Exception { - URI base = baseMixin.require(getSpec()); if (!target.isAbsolute() || !target.toString().endsWith("/")) throw new ParameterException(getSpec().commandLine(), "TARGET_URI must be an absolute URI ending with '/': '" + target + "'"); if (!Files.isDirectory(dir)) throw new ParameterException(getSpec().commandLine(), "Not a directory: '" + dir + "'"); for (Step step : PushPlan.plan(dir.toAbsolutePath().normalize(), target)) - execute(step, base); + execute(step); return 0; } @@ -73,10 +67,9 @@ public Integer call() throws Exception * and prints the written URI on standard output. * * @param step plan step - * @param base application base URI * @throws IOException file read error */ - protected void execute(Step step, URI base) throws IOException + protected void execute(Step step) throws IOException { switch (step.kind()) { @@ -92,7 +85,7 @@ protected void execute(Step step, URI base) throws IOException { printErr("POST " + step.target() + " <- " + step.relative()); String title = step.file().getFileName().toString(); - URI upload = dryRun ? AddFile.uploadURI(base, step.file()) : AddFile.core(getClient(), base, step.target(), step.file(), null, title, null); + URI upload = dryRun ? AddFile.uploadURI(step.target(), step.file()) : AddFile.core(getClient(), step.target(), step.file(), null, title, null); print(upload); } } diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddClass.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddClass.java index dc579add33..245b9f0d97 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddClass.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddClass.java @@ -17,13 +17,11 @@ package com.atomgraph.linkeddatahub.cli.command.admin.ontologies; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Ontologies; import java.net.URI; import java.util.ArrayList; import java.util.List; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -36,9 +34,6 @@ public class AddClass extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--label", required = true, paramLabel = "LABEL", description = "Label of the class") private String label; @@ -63,8 +58,6 @@ public class AddClass extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Ontologies.owlClass(target, uri, label, comment, constructor, constraint, superClasses)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddConstructor.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddConstructor.java index 47c63cfc6c..b3c03a8f73 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddConstructor.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddConstructor.java @@ -17,14 +17,12 @@ package com.atomgraph.linkeddatahub.cli.command.admin.ontologies; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Ontologies; import com.atomgraph.linkeddatahub.rdf.vocabulary.SP; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -37,9 +35,6 @@ public class AddConstructor extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--label", required = true, paramLabel = "LABEL", description = "Label of the query") private String label; @@ -58,8 +53,6 @@ public class AddConstructor extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Ontologies.constructor(target, uri, SP.Construct, label, Files.readString(queryFile), null, comment)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddPropertyConstraint.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddPropertyConstraint.java index f33f0608d4..6f1ae1130d 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddPropertyConstraint.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddPropertyConstraint.java @@ -17,11 +17,9 @@ package com.atomgraph.linkeddatahub.cli.command.admin.ontologies; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Ontologies; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -34,9 +32,6 @@ public class AddPropertyConstraint extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--label", required = true, paramLabel = "LABEL", description = "Label of the constraint") private String label; @@ -55,8 +50,6 @@ public class AddPropertyConstraint extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Ontologies.propertyConstraint(target, uri, label, property, comment)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddRestriction.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddRestriction.java index 10cbd2613f..1acc02680c 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddRestriction.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddRestriction.java @@ -17,12 +17,10 @@ package com.atomgraph.linkeddatahub.cli.command.admin.ontologies; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Ontologies; import java.net.URI; import org.apache.jena.vocabulary.OWL; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -35,9 +33,6 @@ public class AddRestriction extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--label", required = true, paramLabel = "LABEL", description = "Label of the restriction") private String label; @@ -62,8 +57,6 @@ public class AddRestriction extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Ontologies.restriction(target, uri, label, comment, onProperty, allValuesFrom, hasValue)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddSelect.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddSelect.java index 10467adfe9..7632d36521 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddSelect.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/admin/ontologies/AddSelect.java @@ -17,14 +17,12 @@ package com.atomgraph.linkeddatahub.cli.command.admin.ontologies; import com.atomgraph.linkeddatahub.cli.BaseCommand; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Ontologies; import com.atomgraph.linkeddatahub.rdf.vocabulary.SP; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -37,9 +35,6 @@ public class AddSelect extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--label", required = true, paramLabel = "LABEL", description = "Label of the query") private String label; @@ -61,8 +56,6 @@ public class AddSelect extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - post(getClient(), target, Ontologies.constructor(target, uri, SP.Select, label, Files.readString(queryFile), service, comment)); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddObjectBlock.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddObjectBlock.java index 71a5a1a94f..6f0fed912b 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddObjectBlock.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddObjectBlock.java @@ -18,7 +18,6 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.http.HttpException; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Blocks; import com.atomgraph.linkeddatahub.rdf.SequenceNumbers; import jakarta.ws.rs.core.Response; @@ -27,7 +26,6 @@ import org.apache.jena.rdf.model.Property; import org.apache.jena.rdf.model.ResourceFactory; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -40,9 +38,6 @@ public class AddObjectBlock extends BaseCommand { - @Mixin - private BaseMixin baseMixin; // accepted for script interface parity, unused - @Option(names = "--value", required = true, paramLabel = "RESOURCE_URI", description = "URI of the object resource") private URI value; diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddXHTMLBlock.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddXHTMLBlock.java index ebb5c595c6..5a5d844ee6 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddXHTMLBlock.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/content/AddXHTMLBlock.java @@ -18,7 +18,6 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.http.HttpException; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Blocks; import com.atomgraph.linkeddatahub.rdf.SequenceNumbers; import jakarta.ws.rs.core.Response; @@ -27,7 +26,6 @@ import org.apache.jena.rdf.model.Property; import org.apache.jena.rdf.model.ResourceFactory; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -40,9 +38,6 @@ public class AddXHTMLBlock extends BaseCommand { - @Mixin - private BaseMixin baseMixin; // accepted for script interface parity, unused - @Option(names = "--value", required = true, paramLabel = "XHTML", description = "XHTML content (must be well-formed XML)") private String value; diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddCSVImport.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddCSVImport.java index d9edc45470..ce5296ea34 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddCSVImport.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddCSVImport.java @@ -18,11 +18,9 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.http.LDHClient; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Imports; import java.net.URI; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -35,9 +33,6 @@ public class AddCSVImport extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the import") private String title; @@ -62,8 +57,6 @@ public class AddCSVImport extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - core(getClient(), target, uri, title, query, file, delimiter, description); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddRDFImport.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddRDFImport.java index c57807d6b8..c13a419dfb 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddRDFImport.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/AddRDFImport.java @@ -18,12 +18,10 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.http.LDHClient; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Imports; import java.net.URI; import org.apache.jena.vocabulary.RDF; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -36,9 +34,6 @@ public class AddRDFImport extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the import") private String title; @@ -63,8 +58,6 @@ public class AddRDFImport extends BaseCommand @Override public Integer call() throws Exception { - baseMixin.require(getSpec()); // required by the script interface - core(getClient(), target, uri, title, file, query, graph, description); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportCSV.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportCSV.java index 86372a82ad..5b29f0eadc 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportCSV.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportCSV.java @@ -19,13 +19,11 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.command.AddConstruct; import com.atomgraph.linkeddatahub.cli.command.AddFile; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Slugs; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -40,9 +38,6 @@ public class ImportCSV extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the import") private String title; @@ -64,13 +59,11 @@ public class ImportCSV extends BaseCommand @Override public Integer call() throws Exception { - URI base = baseMixin.require(getSpec()); - String queryId = Slugs.defaultSlug(); AddConstruct.core(getClient(), target, "#" + queryId, title, Files.readString(queryFile), null, null); URI query = target.resolve("#" + queryId); - URI fileURI = AddFile.core(getClient(), base, target, csvFile, "text/csv", title, null); + URI fileURI = AddFile.core(getClient(), target, csvFile, "text/csv", title, null); AddCSVImport.core(getClient(), target, null, title, query, fileURI, delimiter, description); print(target); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportRDF.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportRDF.java index c93bde7170..08a87853bb 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportRDF.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/command/imports/ImportRDF.java @@ -19,13 +19,11 @@ import com.atomgraph.linkeddatahub.cli.BaseCommand; import com.atomgraph.linkeddatahub.cli.command.AddConstruct; import com.atomgraph.linkeddatahub.cli.command.AddFile; -import com.atomgraph.linkeddatahub.cli.mixin.BaseMixin; import com.atomgraph.linkeddatahub.rdf.Slugs; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @@ -40,9 +38,6 @@ public class ImportRDF extends BaseCommand { - @Mixin - private BaseMixin baseMixin; - @Option(names = "--title", required = true, paramLabel = "TITLE", description = "Title of the import") private String title; @@ -67,8 +62,6 @@ public class ImportRDF extends BaseCommand @Override public Integer call() throws Exception { - URI base = baseMixin.require(getSpec()); - URI query = null; if (queryFile != null) { @@ -77,7 +70,7 @@ public Integer call() throws Exception query = target.resolve("#" + queryId); } - URI fileURI = AddFile.core(getClient(), base, target, rdfFile, contentType, title, null); + URI fileURI = AddFile.core(getClient(), target, rdfFile, contentType, title, null); String importId = Slugs.defaultSlug(); AddRDFImport.core(getClient(), target, "#" + importId, title, fileURI, query, query == null ? graph : null, description); diff --git a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/mixin/BaseMixin.java b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/mixin/BaseMixin.java index 5b56680cf4..5da265ec28 100644 --- a/cli/src/main/java/com/atomgraph/linkeddatahub/cli/mixin/BaseMixin.java +++ b/cli/src/main/java/com/atomgraph/linkeddatahub/cli/mixin/BaseMixin.java @@ -18,19 +18,23 @@ import java.net.URI; import picocli.CommandLine.Model.CommandSpec; -import picocli.CommandLine.Option; import picocli.CommandLine.ParameterException; +import picocli.CommandLine.Parameters; /** - * Application base URI option shared by commands whose script counterpart takes -b. + * Application base URI, the positional parameter of the commands that address no document of their + * own and so need the dataspace named: the packages family, the admin + * create, clear and import commands and make-public. + * It is the thing those commands act on, which is why it sits where every other command puts its + * target. * * @author Martynas Jusevičius {@literal } */ public class BaseMixin { - @Option(names = {"-b", "--base"}, defaultValue = "${env:LDH_BASE}", paramLabel = "BASE_URI", - description = "Base URI of the application (env: LDH_BASE)") + @Parameters(index = "0", arity = "0..1", defaultValue = "${env:LDH_BASE}", paramLabel = "BASE_URI", + description = "Base URI of the application (default: LDH_BASE)") private URI base; /** @@ -41,7 +45,7 @@ public class BaseMixin */ public URI require(CommandSpec spec) { - if (base == null) throw new ParameterException(spec.commandLine(), "Missing required option: '--base=BASE_URI' (or set LDH_BASE)"); + if (base == null) throw new ParameterException(spec.commandLine(), "Missing required parameter: 'BASE_URI' (or set LDH_BASE)"); return base; } diff --git a/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandOutputTest.java b/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandOutputTest.java index f08e73d0ec..a5db422f84 100644 --- a/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandOutputTest.java +++ b/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandOutputTest.java @@ -68,8 +68,7 @@ public void createdURLIsTheOnlyLineOnStdout() throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("create", "container", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--title", "Test", "--slug", "test", "--parent", base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--title", "Test", "--slug", "test", "--parent", base.toString()); assertEquals(0, code); assertEquals(base + "test/", out.toString().strip()); @@ -88,8 +87,7 @@ public void createdURLMatchesTheDocumentActuallyWritten() throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); commandLine(out, err).execute("create", "container", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--title", "Test", "--slug", "test", "--parent", base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--title", "Test", "--slug", "test", "--parent", base.toString()); assertEquals("PUT", server.getLastMethod()); assertEquals("/test/", server.getLastTarget()); @@ -107,8 +105,7 @@ public void slugIsPercentEncodedInBothURLAndRequest() throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("create", "container", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--title", "Ö", "--slug", "ö x", "--parent", base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--title", "Ö", "--slug", "ö x", "--parent", base.toString()); assertEquals(0, code); assertEquals(base + "%C3%B6%20x/", out.toString().strip()); @@ -233,8 +230,7 @@ public void httpErrorStatusExitsOneWithEmptyStdout() throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("create", "container", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--title", "Test", "--slug", "test", "--parent", base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--title", "Test", "--slug", "test", "--parent", base.toString()); assertEquals(CommandLine.ExitCode.SOFTWARE, code); assertEquals("", out.toString(), "a failed command must print nothing on stdout"); @@ -254,8 +250,7 @@ public void connectionFailureExitsOneWithEmptyStdout() throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("create", "container", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--title", "Test", "--slug", "test", "--parent", base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--title", "Test", "--slug", "test", "--parent", base.toString()); assertEquals(CommandLine.ExitCode.SOFTWARE, code); assertEquals("", out.toString(), "a failed command must print nothing on stdout"); @@ -387,7 +382,7 @@ public void listPackagesMarksTheImportedOnes() throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("packages", "list", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", base.toString()); assertEquals(0, code); assertEquals(List.of("installed\thttps://packages.linkeddatahub.com/editor/taxonomy/#this\tTaxonomy Editor", diff --git a/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandParsingTest.java b/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandParsingTest.java index b0f0441a1c..13d5f9babd 100644 --- a/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandParsingTest.java +++ b/cli/src/test/java/com/atomgraph/linkeddatahub/cli/CommandParsingTest.java @@ -121,8 +121,8 @@ public void unrecognizedRDFFileExtensionIsUsageError() @Test public void pushRequiresATrailingSlashOnTheTarget() { - assertEquals(CommandLine.ExitCode.USAGE, commandLine().execute("push", "-b", "https://localhost:4443/", "--dry-run", "https://localhost:4443/some")); - assertEquals(CommandLine.ExitCode.USAGE, commandLine().execute("push", "-b", "https://localhost:4443/", "--dry-run", "--dir", "/nonexistent/dir", "https://localhost:4443/some/")); + assertEquals(CommandLine.ExitCode.USAGE, commandLine().execute("push", "--dry-run", "https://localhost:4443/some")); + assertEquals(CommandLine.ExitCode.USAGE, commandLine().execute("push", "--dry-run", "--dir", "/nonexistent/dir", "https://localhost:4443/some/")); } @Test @@ -163,10 +163,11 @@ public void helpPrintsTheUsageOfTheCommandItWasAskedOn() public void repeatableOptionsAccumulate() { ParseResult parseResult = commandLine().parseArgs("admin", "create", "group", - "-c", "cert.p12", "-p", "secret", "-b", "https://admin.localhost:4443/", + "-c", "cert.p12", "-p", "secret", "--name", "Editors", "--member", "https://localhost:4443/acl/agents/a/#this", - "--member", "https://localhost:4443/acl/agents/b/#this"); + "--member", "https://localhost:4443/acl/agents/b/#this", + "https://admin.localhost:4443/"); ParseResult createGroup = parseResult.subcommand().subcommand().subcommand(); List members = createGroup.matchedOption("--member").getValue(); diff --git a/cli/src/test/java/com/atomgraph/linkeddatahub/cli/PushOutputTest.java b/cli/src/test/java/com/atomgraph/linkeddatahub/cli/PushOutputTest.java index 30ec07e410..0576cdad9c 100644 --- a/cli/src/test/java/com/atomgraph/linkeddatahub/cli/PushOutputTest.java +++ b/cli/src/test/java/com/atomgraph/linkeddatahub/cli/PushOutputTest.java @@ -72,8 +72,7 @@ public void pushWritesDocumentsThenUploadsInWalkOrder(@TempDir Path root) throws StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("push", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--dir", root.toString(), base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--dir", root.toString(), base.toString()); assertEquals(0, code, err.toString()); List requests = server.getRequests(); @@ -106,7 +105,7 @@ public void dryRunSendsNothingAndNeedsNoCertificate(@TempDir Path root) throws E StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("push", "--dry-run", - "-b", base.toString(), "--dir", root.toString(), base.toString()); + "--dir", root.toString(), base.toString()); assertEquals(0, code, err.toString()); assertTrue(server.getRequests().isEmpty(), "dry run sent " + server.getRequests()); @@ -126,8 +125,7 @@ public void pushStopsAtTheFirstHttpError(@TempDir Path root) throws Exception StringWriter out = new StringWriter(), err = new StringWriter(); int code = commandLine(out, err).execute("push", - "-c", keyStorePath().toString(), "-p", "changeit", "-b", base.toString(), - "--dir", root.toString(), base.toString()); + "-c", keyStorePath().toString(), "-p", "changeit", "--dir", root.toString(), base.toString()); assertEquals(CommandLine.ExitCode.SOFTWARE, code); // the write that failed and the conditional read before it, and nothing of the next document diff --git a/platform/context.xsl b/platform/context.xsl index e09797f61a..0bc778018d 100644 --- a/platform/context.xsl +++ b/platform/context.xsl @@ -37,9 +37,6 @@ xmlns:orcid="&orcid;" - - - @@ -52,6 +49,7 @@ xmlns:orcid="&orcid;" + @@ -127,15 +125,6 @@ xmlns:orcid="&orcid;" - - - - - - - - - @@ -172,6 +161,9 @@ xmlns:orcid="&orcid;" + + + diff --git a/platform/entrypoint.sh b/platform/entrypoint.sh index 8cdd93c3dd..30752c4f2c 100755 --- a/platform/entrypoint.sh +++ b/platform/entrypoint.sh @@ -1168,8 +1168,8 @@ SIGN_UP_CERT_VALIDITY_PARAM="--stringparam ldhc:signUpCertValidity '$SIGN_UP_CER CONTEXT_DATASET_PARAM="--stringparam ldhc:contextDataset '$webapp_context_dataset' " # the context dataset above is regenerated from the source configuration on every boot, so it is no # place for a setting changed at runtime. The overlay is: outside the deployed application, on a -# volume, applied over the dataset once it is loaded -SETTINGS_OVERLAY_PARAM="--stringparam ldhc:settingsOverlay 'file://$SETTINGS_ROOT/dataspaces.trig' " +# volume, and a SPARQL Update of what changed, applied to the dataset once it is loaded +SETTINGS_OVERLAY_PARAM="--stringparam ldhc:settingsOverlay 'file://$SETTINGS_ROOT/dataspaces.ru' " MAIL_SMTP_HOST_PARAM="--stringparam mail.smtp.host '$MAIL_SMTP_HOST' " MAIL_SMTP_PORT_PARAM="--stringparam mail.smtp.port '$MAIL_SMTP_PORT' " MAIL_USER_PARAM="--stringparam mail.user '$MAIL_USER' " @@ -1221,6 +1221,18 @@ if [ -n "$EGRESS_PROXY" ]; then export CATALINA_OPTS="$CATALINA_OPTS -Dcom.atomgraph.linkeddatahub.egressProxy=$EGRESS_PROXY" fi +if [ -n "$MAX_CONN_PER_ROUTE" ]; then + export CATALINA_OPTS="$CATALINA_OPTS -Dcom.atomgraph.linkeddatahub.maxConnPerRoute=$MAX_CONN_PER_ROUTE" +fi + +if [ -n "$MAX_TOTAL_CONN" ]; then + export CATALINA_OPTS="$CATALINA_OPTS -Dcom.atomgraph.linkeddatahub.maxTotalConn=$MAX_TOTAL_CONN" +fi + +if [ -n "$MAX_REQUEST_RETRIES" ]; then + export CATALINA_OPTS="$CATALINA_OPTS -Dcom.atomgraph.linkeddatahub.maxRequestRetries=$MAX_REQUEST_RETRIES" +fi + if [ -n "$CONNECTION_REQUEST_TIMEOUT" ]; then export CATALINA_OPTS="$CATALINA_OPTS -Dcom.atomgraph.linkeddatahub.connectionRequestTimeout=$CONNECTION_REQUEST_TIMEOUT" fi @@ -1279,18 +1291,6 @@ if [ -n "$MAX_CONTENT_LENGTH" ]; then MAX_CONTENT_LENGTH_PARAM="--stringparam ldhc:maxContentLength '$MAX_CONTENT_LENGTH' " fi -if [ -n "$MAX_CONN_PER_ROUTE" ]; then - MAX_CONN_PER_ROUTE_PARAM="--stringparam ldhc:maxConnPerRoute '$MAX_CONN_PER_ROUTE' " -fi - -if [ -n "$MAX_TOTAL_CONN" ]; then - MAX_TOTAL_CONN_PARAM="--stringparam ldhc:maxTotalConn '$MAX_TOTAL_CONN' " -fi - -if [ -n "$MAX_REQUEST_RETRIES" ]; then - MAX_REQUEST_RETRIES_PARAM="--stringparam ldhc:maxRequestRetries '$MAX_REQUEST_RETRIES' " -fi - if [ -n "$MAX_IMPORT_THREADS" ]; then MAX_IMPORT_THREADS_PARAM="--stringparam ldhc:maxImportThreads '$MAX_IMPORT_THREADS' " fi @@ -1331,6 +1331,11 @@ if [ -f "/run/secrets/orcid_client_secret" ]; then ORCID_CLIENT_SECRET_PARAM="--stringparam orcid:clientSecret '$ORCID_CLIENT_SECRET' " fi +# https://sandbox.orcid.org for a client registered on ORCID's sandbox; production orcid.org otherwise +if [ -n "$ORCID_ISSUER" ]; then + ORCID_ISSUER_PARAM="--stringparam orcid:issuer '$ORCID_ISSUER' " +fi + if [ -n "$FRONTEND_PROXY" ]; then FRONTEND_PROXY_PARAM="--stringparam 'ldhc:frontendProxy' '$FRONTEND_PROXY' " fi @@ -1365,9 +1370,6 @@ transform="xsltproc \ $OWNER_AUTH_QUERY_PARAM \ $ENABLE_LINKED_DATA_PROXY_PARAM \ $MAX_CONTENT_LENGTH_PARAM \ - $MAX_CONN_PER_ROUTE_PARAM \ - $MAX_TOTAL_CONN_PARAM \ - $MAX_REQUEST_RETRIES_PARAM \ $MAX_IMPORT_THREADS_PARAM \ $NOTIFICATION_ADDRESS_PARAM \ $ENABLE_WEBID_SIGNUP_PARAM \ @@ -1380,6 +1382,7 @@ transform="xsltproc \ $GOOGLE_CLIENT_SECRET_PARAM \ $ORCID_CLIENT_ID_PARAM \ $ORCID_CLIENT_SECRET_PARAM \ + $ORCID_ISSUER_PARAM \ $FRONTEND_PROXY_PARAM \ $BACKEND_PROXY_ADMIN_PARAM \ $BACKEND_PROXY_END_USER_PARAM \ diff --git a/pom.xml b/pom.xml index a9652f31ca..1f4e52ba8d 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.atomgraph linkeddatahub - 6.0.1 + 6.1.0-SNAPSHOT ${packaging.type} AtomGraph LinkedDataHub @@ -46,7 +46,7 @@ https://github.com/AtomGraph/LinkedDataHub scm:git:git://github.com/AtomGraph/LinkedDataHub.git scm:git:git@github.com:AtomGraph/LinkedDataHub.git - linkeddatahub-6.0.1 + linkeddatahub-5.5.4 diff --git a/rdf/pom.xml b/rdf/pom.xml index 9a4b4522f0..66978eccf5 100644 --- a/rdf/pom.xml +++ b/rdf/pom.xml @@ -4,7 +4,7 @@ com.atomgraph linkeddatahub-rdf - 6.0.1 + 6.1.0-SNAPSHOT jar LinkedDataHub RDF diff --git a/src/main/java/com/atomgraph/linkeddatahub/Application.java b/src/main/java/com/atomgraph/linkeddatahub/Application.java index d5f7f52661..222eb7a991 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/Application.java +++ b/src/main/java/com/atomgraph/linkeddatahub/Application.java @@ -20,6 +20,7 @@ import com.atomgraph.linkeddatahub.writer.impl.SameSiteSourceResolver; import com.atomgraph.linkeddatahub.server.util.ContextEndpointAccessor; import com.atomgraph.linkeddatahub.server.util.FileContextPersistence; +import com.atomgraph.linkeddatahub.server.util.GraphLocks; import com.atomgraph.linkeddatahub.server.util.OntologyRepository; import org.apache.jena.riot.RDFParser; import com.atomgraph.linkeddatahub.server.mapper.HttpHostConnectExceptionMapper; @@ -93,6 +94,7 @@ import com.atomgraph.linkeddatahub.server.factory.AgentContextFactory; import com.atomgraph.linkeddatahub.server.factory.ApplicationFactory; import com.atomgraph.linkeddatahub.server.factory.AuthorizationContextFactory; +import com.atomgraph.linkeddatahub.server.filter.request.AcceptLanguageFilter; import com.atomgraph.linkeddatahub.server.filter.request.ApplicationFilter; import com.atomgraph.linkeddatahub.server.filter.request.auth.WebIDFilter; import com.atomgraph.linkeddatahub.server.io.ValidatingModelProvider; @@ -266,6 +268,8 @@ public class Application extends ResourceConfig public static final String CLIENT_SEF_PATH = "/static/com/atomgraph/linkeddatahub/xsl/client.xsl.sef.json"; /** Milliseconds a request waits for a connection from the client pool when nothing configures it; the image sets the same through CONNECTION_REQUEST_TIMEOUT */ public static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 30000; + /** ORCID's production environment, used when no issuer is configured; a client registered on the sandbox sets https://sandbox.orcid.org */ + public static final String ORCID_ISSUER = "https://orcid.org"; /** Path of the client stylesheet source in the webapp, composed with package stylesheets per import set */ public static final String CLIENT_XSL_PATH = "/static/com/atomgraph/linkeddatahub/xsl/client.xsl"; @@ -276,6 +280,7 @@ public class Application extends ResourceConfig private final SameSiteSourceResolver resolver; private final Map endUserRepositories; private final PackageService packageService = new PackageService(this); + private final GraphLocks graphLocks = new GraphLocks(); private final MediaTypes mediaTypes; private final Client client, externalClient, externalNoCertClient, importClient, noCertClient, verifiedClient; private final Query documentTypeQuery, documentOwnerQuery, aclQuery, ownerAclQuery, webIDQuery, agentQuery, userAccountQuery, ontologyQuery; // no relative URIs @@ -369,8 +374,11 @@ public Application(@Context ServletConfig servletConfig) throws URISyntaxExcepti System.getProperty("com.atomgraph.linkeddatahub.allowInternalUrls") != null ? Boolean.parseBoolean(System.getProperty("com.atomgraph.linkeddatahub.allowInternalUrls")) : servletConfig.getServletContext().getInitParameter(LDHC.allowInternalUrls.getURI()) != null ? Boolean.parseBoolean(servletConfig.getServletContext().getInitParameter(LDHC.allowInternalUrls.getURI())) : false, servletConfig.getServletContext().getInitParameter(LDHC.maxContentLength.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxContentLength.getURI())) : null, + System.getProperty("com.atomgraph.linkeddatahub.maxConnPerRoute") != null ? Integer.valueOf(System.getProperty("com.atomgraph.linkeddatahub.maxConnPerRoute")) : servletConfig.getServletContext().getInitParameter(LDHC.maxConnPerRoute.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxConnPerRoute.getURI())) : null, + System.getProperty("com.atomgraph.linkeddatahub.maxTotalConn") != null ? Integer.valueOf(System.getProperty("com.atomgraph.linkeddatahub.maxTotalConn")) : servletConfig.getServletContext().getInitParameter(LDHC.maxTotalConn.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxTotalConn.getURI())) : null, + System.getProperty("com.atomgraph.linkeddatahub.maxRequestRetries") != null ? Integer.valueOf(System.getProperty("com.atomgraph.linkeddatahub.maxRequestRetries")) : servletConfig.getServletContext().getInitParameter(LDHC.maxRequestRetries.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.maxRequestRetries.getURI())) : null, System.getProperty("com.atomgraph.linkeddatahub.connectionRequestTimeout") != null ? Integer.valueOf(System.getProperty("com.atomgraph.linkeddatahub.connectionRequestTimeout")) : servletConfig.getServletContext().getInitParameter(LDHC.connectionRequestTimeout.getURI()) != null ? Integer.valueOf(servletConfig.getServletContext().getInitParameter(LDHC.connectionRequestTimeout.getURI())) : @@ -394,7 +402,8 @@ public Application(@Context ServletConfig servletConfig) throws URISyntaxExcepti servletConfig.getServletContext().getInitParameter(Google.clientID.getURI()) != null ? servletConfig.getServletContext().getInitParameter(Google.clientID.getURI()) : null, servletConfig.getServletContext().getInitParameter(Google.clientSecret.getURI()) != null ? servletConfig.getServletContext().getInitParameter(Google.clientSecret.getURI()) : null, servletConfig.getServletContext().getInitParameter(ORCID.clientID.getURI()) != null ? servletConfig.getServletContext().getInitParameter(ORCID.clientID.getURI()) : null, - servletConfig.getServletContext().getInitParameter(ORCID.clientSecret.getURI()) != null ? servletConfig.getServletContext().getInitParameter(ORCID.clientSecret.getURI()) : null + servletConfig.getServletContext().getInitParameter(ORCID.clientSecret.getURI()) != null ? servletConfig.getServletContext().getInitParameter(ORCID.clientSecret.getURI()) : null, + servletConfig.getServletContext().getInitParameter(ORCID.issuer.getURI()) != null ? servletConfig.getServletContext().getInitParameter(ORCID.issuer.getURI()) : ORCID_ISSUER ); } @@ -450,6 +459,7 @@ public Application(@Context ServletConfig servletConfig) throws URISyntaxExcepti * @param googleClientSecret client secret for Google's OAuth * @param orcidClientID client ID for ORCID's OAuth * @param orcidClientSecret client secret for ORCID's OAuth + * @param orcidIssuer ORCID environment the client is registered with (production or sandbox) * @param frontendProxyString frontend (Varnish) proxy URI used for cache invalidation BAN requests, or null * @param backendProxyAdminString backend proxy URI for the admin SPARQL service (endpoint URI rewriting + cache invalidation), or null * @param backendProxyEndUserString backend proxy URI for the end-user SPARQL service (endpoint URI rewriting + cache invalidation), or null @@ -472,7 +482,7 @@ public Application(final ServletConfig servletConfig, final MediaTypes mediaType final String frontendProxyString, final String backendProxyAdminString, final String backendProxyEndUserString, final String mailUser, final String mailPassword, final String smtpHost, final String smtpPort, final String googleClientID, final String googleClientSecret, - final String orcidClientID, final String orcidClientSecret) + final String orcidClientID, final String orcidClientSecret, final String orcidIssuer) { if (contextDatasetURIString == null) { @@ -614,6 +624,7 @@ public Application(final ServletConfig servletConfig, final MediaTypes mediaType if (googleClientSecret != null) this.property(Google.clientSecret.getURI(), googleClientSecret); if (orcidClientID != null) this.property(ORCID.clientID.getURI(), orcidClientID); if (orcidClientSecret != null) this.property(ORCID.clientSecret.getURI(), orcidClientSecret); + this.property(ORCID.issuer.getURI(), URI.create(orcidIssuer)); try { @@ -1211,6 +1222,7 @@ protected void registerResourceClasses() protected void registerContainerRequestFilters() { register(new HttpMethodOverrideFilter()); + register(AcceptLanguageFilter.class); register(ApplicationFilter.class); register(OntologyFilter.class); register(ProxiedWebIDFilter.class); @@ -2568,6 +2580,16 @@ public com.atomgraph.linkeddatahub.server.util.GraphVersioningService getGraphVe return graphVersioningService; } + /** + * Locks serialising the writes to a named graph, held from the read of the graph to the write back. + * + * @return graph locks + */ + public GraphLocks getGraphLocks() + { + return graphLocks; + } + /** * Returns the service that composes and compiles client stylesheets, or null if not configured. * diff --git a/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Authorize.java b/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Authorize.java index 45157cbc65..06f7fde6ed 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Authorize.java +++ b/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Authorize.java @@ -48,7 +48,7 @@ public Authorize(@Context HttpServletRequest httpServletRequest, com.atomgraph.l @Override protected URI getAuthorizeEndpoint() { - return URI.create("https://sandbox.orcid.org/oauth/authorize"); // "https://orcid.org/oauth/authorize" + return Login.getAuthorizeEndpoint(Login.getIssuer(getSystem())); } @Override diff --git a/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Login.java b/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Login.java index 4832f1cb73..c8abf3b5d7 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Login.java +++ b/src/main/java/com/atomgraph/linkeddatahub/resource/oauth2/orcid/Login.java @@ -30,6 +30,7 @@ import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.Request; import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; import jakarta.ws.rs.core.UriInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,18 +46,6 @@ public class Login extends LoginBase private static final Logger log = LoggerFactory.getLogger(Login.class); - /** OAuth token endpoint URL */ - public static final URI TOKEN_ENDPOINT = URI.create("https://sandbox.orcid.org/oauth/token"); // URI.create("https://orcid.org/oauth/token"); - - /** User info endpoint URL */ - public static final URI USER_INFO_ENDPOINT = URI.create("https://sandbox.orcid.org/oauth/userinfo"); // URI.create("https://orcid.org/oauth/userinfo"); - - /** JWKS endpoint URL for JWT signature verification */ - public static final URI JWKS_ENDPOINT = URI.create("https://sandbox.orcid.org/oauth/jwks"); // URI.create("https://orcid.org/oauth/jwks"); - - /** Valid ORCID issuers (supports both production and sandbox) */ - private static final java.util.List ISSUERS = java.util.Arrays.asList("https://orcid.org", "https://sandbox.orcid.org"); - /** * Constructs endpoint. * @@ -76,6 +65,61 @@ public Login(@Context Request request, @Context UriInfo uriInfo, @Context HttpHe (String)system.getProperty(ORCID.clientID.getURI()), (String)system.getProperty(ORCID.clientSecret.getURI())); } + /** + * Returns the configured ORCID issuer (production or sandbox), which all the endpoints are on. + * + * @param system system application + * @return issuer URI + */ + public static URI getIssuer(com.atomgraph.linkeddatahub.Application system) + { + return (URI)system.getProperty(ORCID.issuer.getURI()); + } + + /** + * Returns the authorization endpoint of an ORCID issuer. + * + * @param issuer ORCID issuer + * @return authorization endpoint URI + */ + public static URI getAuthorizeEndpoint(URI issuer) + { + return UriBuilder.fromUri(issuer).path("oauth/authorize").build(); + } + + /** + * Returns the token endpoint of an ORCID issuer. + * + * @param issuer ORCID issuer + * @return token endpoint URI + */ + public static URI getTokenEndpoint(URI issuer) + { + return UriBuilder.fromUri(issuer).path("oauth/token").build(); + } + + /** + * Returns the UserInfo endpoint of an ORCID issuer. + * + * @param issuer ORCID issuer + * @return UserInfo endpoint URI + */ + public static URI getUserInfoEndpoint(URI issuer) + { + return UriBuilder.fromUri(issuer).path("oauth/userinfo").build(); + } + + /** + * Returns the JWKS endpoint of an ORCID issuer, for fetching the public keys that sign its JWTs. + * + * @param issuer ORCID issuer + * @return JWKS endpoint URI + */ + public static URI getJWKSEndpoint(URI issuer) + { + return UriBuilder.fromUri(issuer).path("oauth/jwks").build(); + } + /** * Returns ORCID's OAuth token endpoint URL. * @@ -84,7 +128,7 @@ public Login(@Context Request request, @Context UriInfo uriInfo, @Context HttpHe @Override public URI getTokenEndpoint() { - return TOKEN_ENDPOINT; + return getTokenEndpoint(getIssuer(getSystem())); } /** @@ -95,18 +139,18 @@ public URI getTokenEndpoint() @Override protected URI getJWKSEndpoint() { - return JWKS_ENDPOINT; + return getJWKSEndpoint(getIssuer(getSystem())); } /** - * Returns the list of valid ORCID issuers. + * Returns the configured ORCID issuer, the only one whose tokens are accepted. * * @return list of valid issuer URLs */ @Override protected java.util.List getIssuers() { - return ISSUERS; + return java.util.List.of(getIssuer(getSystem()).toString()); } /** @@ -122,7 +166,7 @@ protected java.util.List getIssuers() protected Map getUserInfo(DecodedJWT jwt, String accessToken) { // ORCID requires a separate UserInfo endpoint call to get user details - try (Response userInfoResponse = getSystem().getClient().target(USER_INFO_ENDPOINT). + try (Response userInfoResponse = getSystem().getClient().target(getUserInfoEndpoint(getIssuer(getSystem()))). request(). header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken). get()) diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/AcceptLanguageFilter.java b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/AcceptLanguageFilter.java new file mode 100644 index 0000000000..884c560058 --- /dev/null +++ b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/AcceptLanguageFilter.java @@ -0,0 +1,64 @@ +/** + * Copyright 2026 Martynas Jusevičius + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.atomgraph.linkeddatahub.server.filter.request; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.container.PreMatching; +import jakarta.ws.rs.core.HttpHeaders; +import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Drops an Accept-Language header that does not parse, so the request proceeds as if the client stated + * no language preference. + * + * The header is advisory, so a malformed value is no reason to refuse the request. It is also not something a later + * stage can recover from: JAX-RS parses it lazily, on every Request.selectVariant() and + * getAcceptableLanguages() call, and every exception mapper's response is built through + * selectVariant(). A parse failure raised inside a mapper escapes it, and what the client gets is the + * container's 500 in place of the status the mapper meant to send - a 403 for an unauthorized request, say. The + * header is read from the request's live header map each time, so removing it here, before any filter that can + * throw into a mapper, is what makes every later reader see a request with no preference instead. + * + * @author Martynas Jusevičius {@literal } + */ +@PreMatching +@Priority(200) // before ApplicationFilter (700) and anything else that can fail into an exception mapper; after ContentLengthLimitFilter (100) +public class AcceptLanguageFilter implements ContainerRequestFilter +{ + + private static final Logger log = LoggerFactory.getLogger(AcceptLanguageFilter.class); + + @Override + public void filter(ContainerRequestContext crc) throws IOException + { + try + { + crc.getAcceptableLanguages(); + } + catch (ProcessingException ex) // Jersey's HeaderValueException, caught by its JAX-RS supertype so no internal class is named + { + if (log.isDebugEnabled()) log.debug("Ignoring malformed Accept-Language header value: '{}'", crc.getHeaderString(HttpHeaders.ACCEPT_LANGUAGE)); + crc.getHeaders().remove(HttpHeaders.ACCEPT_LANGUAGE); + } + } + +} diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/auth/orcid/IDTokenFilter.java b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/auth/orcid/IDTokenFilter.java index a6a1d37e97..ea366df447 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/auth/orcid/IDTokenFilter.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/auth/orcid/IDTokenFilter.java @@ -18,11 +18,9 @@ import com.atomgraph.linkeddatahub.resource.oauth2.orcid.Authorize; import com.atomgraph.linkeddatahub.resource.oauth2.orcid.Login; -import static com.atomgraph.linkeddatahub.resource.oauth2.orcid.Login.TOKEN_ENDPOINT; import com.atomgraph.linkeddatahub.server.filter.request.auth.IDTokenFilterBase; import com.atomgraph.linkeddatahub.vocabulary.ORCID; import java.net.URI; -import java.util.Arrays; import java.util.List; import jakarta.annotation.Priority; import jakarta.ws.rs.Priorities; @@ -42,9 +40,6 @@ public class IDTokenFilter extends IDTokenFilterBase { private static final Logger log = LoggerFactory.getLogger(IDTokenFilter.class); - /** White-list of OIDC issuers (supports both production and sandbox) */ - private static final List ISSUERS = Arrays.asList("https://orcid.org", "https://sandbox.orcid.org"); - @Override protected void initClientCredentials() { @@ -55,19 +50,19 @@ protected void initClientCredentials() @Override protected List getIssuers() { - return ISSUERS; + return List.of(Login.getIssuer(getSystem()).toString()); } @Override protected URI getJWKSEndpoint() { - return Login.JWKS_ENDPOINT; + return Login.getJWKSEndpoint(Login.getIssuer(getSystem())); } @Override protected URI getTokenEndpoint() { - return TOKEN_ENDPOINT; + return Login.getTokenEndpoint(Login.getIssuer(getSystem())); } @Override diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java b/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java index 6b5136c849..6e3535b9d5 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java @@ -83,7 +83,7 @@ public void filter(ContainerRequestContext request, ContainerResponseContext res if (request.getSecurityContext().getUserPrincipal() instanceof Agent) { Agent agent = ((Agent)(request.getSecurityContext().getUserPrincipal())); - response.getHeaders().add(HttpHeaders.LINK, new Link(URI.create(agent.getURI()), ACL.agent.getURI(), null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(URI.create(agent.getURI())).rel(ACL.agent.getURI()).build()); } boolean isTimeMap = request.getUriInfo().getQueryParameters().containsKey(DocumentHierarchyGraphStoreImpl.TIMEMAP_PARAM_NAME); @@ -105,23 +105,23 @@ public void filter(ContainerRequestContext request, ContainerResponseContext res if (getAuthorizationContext().isPresent()) getAuthorizationContext().get().getModeURIs().stream(). filter(mode -> !isSnapshotRequest || mode.toString().equals(ACL.Read.getURI())). - forEach(mode -> response.getHeaders().add(HttpHeaders.LINK, new Link(mode, ACL.mode.getURI(), null))); + forEach(mode -> response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(mode).rel(ACL.mode.getURI()).build())); // for proxy requests the external Link headers are forwarded by ProxyRequestFilter; suppress local-only hypermedia boolean isProxyRequest = request.getProperty(AC.uri.getURI()) != null; if (!isProxyRequest) - response.getHeaders().add(HttpHeaders.LINK, new Link(request.getUriInfo().getBaseUriBuilder().path(Dispatcher.class, "getSPARQLEndpoint").build(), SD.endpoint.getURI(), null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(request.getUriInfo().getBaseUriBuilder().path(Dispatcher.class, "getSPARQLEndpoint").build()).rel(SD.endpoint.getURI()).build()); // Only add application-specific links if application is present and this is not a proxy request if (!isProxyRequest && getDataspace().isPresent()) { Dataspace application = getDataspace().get(); // add Link rel=lds:dataspace - response.getHeaders().add(HttpHeaders.LINK, new Link(URI.create(application.getURI()), LDS.dataspace.getURI(), null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(URI.create(application.getURI())).rel(LDS.dataspace.getURI()).build()); // add Link rel=lds:ontology, if the ontology URI is specified if (application.getOntology() != null) - response.getHeaders().add(HttpHeaders.LINK, new Link(URI.create(application.getOntology().getURI()), LDS.ontology.getURI(), null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(URI.create(application.getOntology().getURI())).rel(LDS.ontology.getURI()).build()); // add Memento (RFC 7089) hypermedia, if the document is versioned if (getSystem().getGraphVersioningService().getRepository(application.getURI()).isPresent() && request.getUriInfo().getMatchedResources().stream().anyMatch(DocumentHierarchyGraphStoreImpl.class::isInstance)) @@ -132,29 +132,29 @@ public void filter(ContainerRequestContext request, ContainerResponseContext res // the TimeMap identifies itself with rel=self; everything else points at it with rel=timemap if (isTimeMap) - response.getHeaders().add(HttpHeaders.LINK, new Link(timeMapURI, "self", TimeMapWriter.APPLICATION_LINK_FORMAT)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(timeMapURI).rel("self").type(TimeMapWriter.APPLICATION_LINK_FORMAT).build()); else - response.getHeaders().add(HttpHeaders.LINK, new Link(timeMapURI, "timemap", TimeMapWriter.APPLICATION_LINK_FORMAT)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(timeMapURI).rel("timemap").type(TimeMapWriter.APPLICATION_LINK_FORMAT).build()); // the Original Resource MUST advertise a preferred TimeGate; the TimeGate does not link to itself if (!isTimeGate) - response.getHeaders().add(HttpHeaders.LINK, new Link(timeGateURI, "timegate", null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(timeGateURI).rel("timegate").build()); // a Memento and a TimeGate MUST link to the Original Resource, and a TimeMap lists it; // the Original Resource itself MUST NOT carry rel=original if (isSnapshotRequest) - response.getHeaders().add(HttpHeaders.LINK, new Link(originalURI, "original", null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(originalURI).rel("original").build()); } // add Link rel=ac:stylesheet, if the stylesheet URI is specified if (application.getStylesheet() != null) - response.getHeaders().add(HttpHeaders.LINK, new Link(URI.create(application.getStylesheet().getURI()), AC.stylesheet.getURI(), null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(URI.create(application.getStylesheet().getURI())).rel(AC.stylesheet.getURI()).build()); // the compiled client stylesheet composed with this application's packages, set by // XsltExecutableFilter only once it exists. Advertised rather than injected as a stylesheet // parameter, so the client reads it the same way it reads acl:mode and the Memento relations Object clientStylesheet = request.getProperty(LDH.clientStylesheet.getURI()); if (clientStylesheet != null) - response.getHeaders().add(HttpHeaders.LINK, new Link(application.getBaseURI().resolve(clientStylesheet.toString()), LDH.clientStylesheet.getURI(), null)); + response.getHeaders().add(HttpHeaders.LINK, Link.fromUri(application.getBaseURI().resolve(clientStylesheet.toString())).rel(LDH.clientStylesheet.getURI()).build()); } if (response.getHeaders().get(HttpHeaders.LINK) != null) diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/model/impl/DocumentHierarchyGraphStoreImpl.java b/src/main/java/com/atomgraph/linkeddatahub/server/model/impl/DocumentHierarchyGraphStoreImpl.java index b2b940233c..aa3f769b23 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/model/impl/DocumentHierarchyGraphStoreImpl.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/model/impl/DocumentHierarchyGraphStoreImpl.java @@ -33,6 +33,7 @@ import com.atomgraph.linkeddatahub.server.security.AgentContext; import com.atomgraph.linkeddatahub.server.util.PatchUpdateVisitor; import com.atomgraph.linkeddatahub.server.util.EntityTags; +import com.atomgraph.linkeddatahub.server.util.GraphLocks; import com.atomgraph.linkeddatahub.server.util.Skolemizer; import com.atomgraph.linkeddatahub.vocabulary.ACL; import com.atomgraph.linkeddatahub.vocabulary.DH; @@ -100,6 +101,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.function.Supplier; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.StringUtils; import org.apache.jena.atlas.RuntimeIOException; @@ -371,36 +374,39 @@ public Response post(Model model) if (log.isTraceEnabled()) log.trace("POST Graph Store request with RDF payload: {} payload size(): {}", model, model.size()); - final Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); + return writeLocked(() -> + { + final Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); - Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); - if (rb != null) return rb.build(); // preconditions not met + Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); + if (rb != null) return rb.build(); // preconditions not met - model.createResource(getURI().toString()). - removeAll(DCTerms.modified). - addLiteral(DCTerms.modified, ResourceFactory.createTypedLiteral(GregorianCalendar.getInstance())); + model.createResource(getURI().toString()). + removeAll(DCTerms.modified). + addLiteral(DCTerms.modified, ResourceFactory.createTypedLiteral(GregorianCalendar.getInstance())); - // container/item (graph) resource is already skolemized, skolemize the rest of the model - new Skolemizer(getURI().toString()).apply(model); + // container/item (graph) resource is already skolemized, skolemize the rest of the model + new Skolemizer(getURI().toString()).apply(model); - // is this implemented correctly? The specification is not very clear. - if (log.isDebugEnabled()) log.debug("POST Model to named graph with URI: {}", getURI()); - // First remove old dct:modified values from the triplestore, then add new data - existingModel.createResource(getURI().toString()).removeAll(DCTerms.modified); - Model updatedModel = existingModel.add(model); + // is this implemented correctly? The specification is not very clear. + if (log.isDebugEnabled()) log.debug("POST Model to named graph with URI: {}", getURI()); + // First remove old dct:modified values from the triplestore, then add new data + existingModel.createResource(getURI().toString()).removeAll(DCTerms.modified); + Model updatedModel = existingModel.add(model); - // the payload was validated on its own when it was read, where a constraint that spans the document - - // a block the payload appends to a document it does not type - had nothing to apply to; what is written - // is the whole document, so that is what is held to the constraints - validateConstraints(updatedModel); + // the payload was validated on its own when it was read, where a constraint that spans the document - + // a block the payload appends to a document it does not type - had nothing to apply to; what is written + // is the whole document, so that is what is held to the constraints + validateConstraints(updatedModel); - getSystem().getServiceContext(getService()).getGraphStoreClient().putModel(getURI().toString(), updatedModel); // replace entire graph to avoid accumulating dct:modified + getSystem().getServiceContext(getService()).getGraphStoreClient().putModel(getURI().toString(), updatedModel); // replace entire graph to avoid accumulating dct:modified - submitImports(model); + submitImports(model); - return Response.noContent(). - tag(getInternalResponse(updatedModel, null).getVariantEntityTag()). // entity tag of the updated graph - build(); + return Response.noContent(). + tag(getInternalResponse(updatedModel, null).getVariantEntityTag()). // entity tag of the updated graph + build(); + }); } /** @@ -443,84 +449,87 @@ public Response put(Model model) throw new BadRequestException("Double slashes not allowed in document URIs"); } - new Skolemizer(getURI().toString()).apply(model); - Model existingModel = null; - try + return writeLocked(() -> { - existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); + new Skolemizer(getURI().toString()).apply(model); + Model existingModel = null; + try + { + existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); - Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); - if (rb != null) return rb.build(); // preconditions not met - } - catch (NotFoundException ex) - { - //if (existingModel == null) existingModel = null; - } + Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); + if (rb != null) return rb.build(); // preconditions not met + } + catch (NotFoundException ex) + { + //if (existingModel == null) existingModel = null; + } - Resource parent = model.createResource(getURI().resolve("..").toString()); - Resource resource = model.createResource(getURI().toString()). - removeAll(SIOC.HAS_PARENT). - removeAll(SIOC.HAS_CONTAINER); + Resource parent = model.createResource(getURI().resolve("..").toString()); + Resource resource = model.createResource(getURI().toString()). + removeAll(SIOC.HAS_PARENT). + removeAll(SIOC.HAS_CONTAINER); - boolean typed = false; // whether the document's class is assigned here rather than by the payload - if (!getDataspace().getBaseURI().equals(getURI())) // don't update Root document's metadata - { - if (resource.hasProperty(RDF.type, DH.Container)) - resource.addProperty(SIOC.HAS_PARENT, parent); - else + boolean typed = false; // whether the document's class is assigned here rather than by the payload + if (!getDataspace().getBaseURI().equals(getURI())) // don't update Root document's metadata { - typed = !resource.hasProperty(RDF.type, DH.Item); - resource.addProperty(SIOC.HAS_CONTAINER, parent). - addProperty(RDF.type, DH.Item); // TO-DO: replace with foaf:Document? + if (resource.hasProperty(RDF.type, DH.Container)) + resource.addProperty(SIOC.HAS_PARENT, parent); + else + { + typed = !resource.hasProperty(RDF.type, DH.Item); + resource.addProperty(SIOC.HAS_CONTAINER, parent). + addProperty(RDF.type, DH.Item); // TO-DO: replace with foaf:Document? + } } - } - // the payload was validated when it was read, while the document was still untyped and so held to no - // class's constraints; a document typed here is held to dh:Item's now, before it is written - if (typed) validateConstraints(model); + // the payload was validated when it was read, while the document was still untyped and so held to no + // class's constraints; a document typed here is held to dh:Item's now, before it is written + if (typed) validateConstraints(model); - if (existingModel == null) // creating new graph and attaching it to the document hierarchy - { - resource.removeAll(DCTerms.created). // remove any client-supplied dct:created values - addLiteral(DCTerms.created, ResourceFactory.createTypedLiteral(GregorianCalendar.getInstance())); + if (existingModel == null) // creating new graph and attaching it to the document hierarchy + { + resource.removeAll(DCTerms.created). // remove any client-supplied dct:created values + addLiteral(DCTerms.created, ResourceFactory.createTypedLiteral(GregorianCalendar.getInstance())); - if (getAgentContext().isPresent()) resource.addProperty(DCTerms.creator, getAgentContext().get().getAgent()). - addProperty(ACL.owner, getAgentContext().get().getAgent()); + if (getAgentContext().isPresent()) resource.addProperty(DCTerms.creator, getAgentContext().get().getAgent()). + addProperty(ACL.owner, getAgentContext().get().getAgent()); - if (log.isDebugEnabled()) log.debug("PUT Model into new named graph with URI: {}", getURI()); - getSystem().getServiceContext(getService()).getGraphStoreClient().putModel(getURI().toString(), model); // TO-DO: catch exceptions + if (log.isDebugEnabled()) log.debug("PUT Model into new named graph with URI: {}", getURI()); + getSystem().getServiceContext(getService()).getGraphStoreClient().putModel(getURI().toString(), model); // TO-DO: catch exceptions - submitImports(model); + submitImports(model); - return Response.created(getURI()). - build(); - } - else // updating existing graph - { - // retain metadata from existing document resource - ExtendedIterator it = existingModel.createResource(getURI().toString()).listProperties(DCTerms.created). - andThen(existingModel.createResource(getURI().toString()).listProperties(DCTerms.creator)). - andThen(existingModel.createResource(getURI().toString()).listProperties(ACL.owner)); - try - { - it.forEach(stmt -> model.add(stmt)); - } - finally - { - it.close(); + return Response.created(getURI()). + build(); } + else // updating existing graph + { + // retain metadata from existing document resource + ExtendedIterator it = existingModel.createResource(getURI().toString()).listProperties(DCTerms.created). + andThen(existingModel.createResource(getURI().toString()).listProperties(DCTerms.creator)). + andThen(existingModel.createResource(getURI().toString()).listProperties(ACL.owner)); + try + { + it.forEach(stmt -> model.add(stmt)); + } + finally + { + it.close(); + } - resource.removeAll(DCTerms.modified). - addLiteral(DCTerms.modified, ResourceFactory.createTypedLiteral(GregorianCalendar.getInstance())); + resource.removeAll(DCTerms.modified). + addLiteral(DCTerms.modified, ResourceFactory.createTypedLiteral(GregorianCalendar.getInstance())); - if (log.isDebugEnabled()) log.debug("PUT Model into existing named graph with URI: {}", getURI()); - getSystem().getServiceContext(getService()).getGraphStoreClient().putModel(getURI().toString(), model); // TO-DO: catch exceptions + if (log.isDebugEnabled()) log.debug("PUT Model into existing named graph with URI: {}", getURI()); + getSystem().getServiceContext(getService()).getGraphStoreClient().putModel(getURI().toString(), model); // TO-DO: catch exceptions - submitImports(model); + submitImports(model); - return getInternalResponse(existingModel, null).getResponseBuilder(). - build(); - } + return getInternalResponse(existingModel, null).getResponseBuilder(). + build(); + } + }); } /** @@ -558,53 +567,56 @@ public Response patch(UpdateRequest updateRequest) } // no need to set WITH since we'll be updating model in memory before persisting it - final Dataset dataset; - final Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); - if (existingModel == null) throw new NotFoundException("Named graph with URI <" + getURI() + "> not found"); + return writeLocked(() -> + { + final Dataset dataset; + final Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); + if (existingModel == null) throw new NotFoundException("Named graph with URI <" + getURI() + "> not found"); - Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); - if (rb != null) return rb.build(); // preconditions not met + Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); + if (rb != null) return rb.build(); // preconditions not met - Model beforeUpdateModel = ModelFactory.createDefaultModel().add(existingModel); - dataset = DatasetFactory.wrap(existingModel); - UpdateAction.execute(updateRequest, dataset); // update model in memory - new Skolemizer(getURI().toString()).apply(existingModel); // skolemize blank nodes introduced by INSERT + Model beforeUpdateModel = ModelFactory.createDefaultModel().add(existingModel); + dataset = DatasetFactory.wrap(existingModel); + UpdateAction.execute(updateRequest, dataset); // update model in memory + new Skolemizer(getURI().toString()).apply(existingModel); // skolemize blank nodes introduced by INSERT - // if PATCH results in an empty graph, treat it as a DELETE request - if (existingModel.isEmpty()) return delete(); + // if PATCH results in an empty graph, treat it as a DELETE request + if (existingModel.isEmpty()) return delete(); - // SPIN constraints are class-scoped; allowing rdf:type removal would silently bypass them - for (Resource resource : getChangedResources(beforeUpdateModel, existingModel)) - { - Resource before = resource.inModel(beforeUpdateModel); - Resource after = resource.inModel(existingModel); - if (before.hasProperty(RDF.type) && !after.hasProperty(RDF.type) && after.listProperties().hasNext()) - throw new WebApplicationException("rdf:type cannot be removed from resource <" + resource + ">", UNPROCESSABLE_ENTITY.getStatusCode()); - } + // SPIN constraints are class-scoped; allowing rdf:type removal would silently bypass them + for (Resource resource : getChangedResources(beforeUpdateModel, existingModel)) + { + Resource before = resource.inModel(beforeUpdateModel); + Resource after = resource.inModel(existingModel); + if (before.hasProperty(RDF.type) && !after.hasProperty(RDF.type) && after.listProperties().hasNext()) + throw new WebApplicationException("rdf:type cannot be removed from resource <" + resource + ">", UNPROCESSABLE_ENTITY.getStatusCode()); + } - try - { - validate(dataset.getDefaultModel()); // this would normally be done transparently by the ValidatingModelProvider - } - catch (SPINConstraintViolationException ex) - { - // the whole post-PATCH graph gets validated, but the 422 body must describe only the - // violating resources - the full graph would leak every sibling resource into the - // error response - throw describeViolations(ex, dataset.getDefaultModel()); - } - catch (SHACLConstraintViolationException ex) - { - throw describeViolations(ex, dataset.getDefaultModel()); - } - put(dataset.getDefaultModel(), Boolean.FALSE, getURI()); + try + { + validate(dataset.getDefaultModel()); // this would normally be done transparently by the ValidatingModelProvider + } + catch (SPINConstraintViolationException ex) + { + // the whole post-PATCH graph gets validated, but the 422 body must describe only the + // violating resources - the full graph would leak every sibling resource into the + // error response + throw describeViolations(ex, dataset.getDefaultModel()); + } + catch (SHACLConstraintViolationException ex) + { + throw describeViolations(ex, dataset.getDefaultModel()); + } + put(dataset.getDefaultModel(), Boolean.FALSE, getURI()); - return getInternalResponse(dataset.getDefaultModel(), null).getResponseBuilder(). // entity tag of the updated graph - status(Response.Status.NO_CONTENT). - entity(null). // 'Content-Type' header has to be explicitly unset in ResponseHeadersFilter - header(HttpHeaders.CONTENT_LOCATION, getURI()). - tag(getInternalResponse(dataset.getDefaultModel(), null).getVariantEntityTag()). // TO-DO: optimize! - build(); + return getInternalResponse(dataset.getDefaultModel(), null).getResponseBuilder(). // entity tag of the updated graph + status(Response.Status.NO_CONTENT). + entity(null). // 'Content-Type' header has to be explicitly unset in ResponseHeadersFilter + header(HttpHeaders.CONTENT_LOCATION, getURI()). + tag(getInternalResponse(dataset.getDefaultModel(), null).getVariantEntityTag()). // TO-DO: optimize! + build(); + }); } /** @@ -646,20 +658,23 @@ public Response postMultipart(FormDataMultiPart multiPart) validate(model); if (log.isTraceEnabled()) log.trace("POST Graph Store request with RDF payload: {} payload size(): {}", model, model.size()); - final Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); - if (existingModel == null) throw new NotFoundException("Named graph with URI <" + getURI() + "> not found"); + return writeLocked(() -> + { + final Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); + if (existingModel == null) throw new NotFoundException("Named graph with URI <" + getURI() + "> not found"); - new Skolemizer(getURI().toString()).apply(model); // skolemize before writing files (they require absolute URIs) + new Skolemizer(getURI().toString()).apply(model); // skolemize before writing files (they require absolute URIs) - // appended to the store rather than written back whole, so no If-Match is asked of an upload; the - // document it is appended to is still held to the constraints as a whole, before a file is written - validateConstraints(ModelFactory.createDefaultModel().add(existingModel).add(model)); + // appended to the store rather than written back whole, so no If-Match is asked of an upload; the + // document it is appended to is still held to the constraints as a whole, before a file is written + validateConstraints(ModelFactory.createDefaultModel().add(existingModel).add(model)); - int fileCount = writeFiles(model, getFileNameBodyPartMap(multiPart)); - if (log.isDebugEnabled()) log.debug("# of files uploaded: {} ", fileCount); + int fileCount = writeFiles(model, getFileNameBodyPartMap(multiPart)); + if (log.isDebugEnabled()) log.debug("# of files uploaded: {} ", fileCount); - if (log.isDebugEnabled()) log.debug("POSTed Model size: {}", model.size()); - return post(model, false, getURI()); // ignore the @QueryParam("graph") value + if (log.isDebugEnabled()) log.debug("POSTed Model size: {}", model.size()); + return post(model, false, getURI()); // ignore the @QueryParam("graph") value + }); } catch (URISyntaxException ex) { @@ -731,19 +746,22 @@ public Response delete() if (!getAllowedMethods().contains(HttpMethod.DELETE)) throw new WebApplicationException("Cannot delete document", Response.status(Response.Status.METHOD_NOT_ALLOWED).allow(getAllowedMethods()).build()); - try + return writeLocked(() -> { - Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); + try + { + Model existingModel = getSystem().getServiceContext(getService()).getGraphStoreClient().getModel(getURI().toString()); - Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); - if (rb != null) return rb.build(); // preconditions not met - } - catch (NotFoundException ex) - { - //if (existingModel == null) existingModel = null; - } + Response.ResponseBuilder rb = evaluatePreconditions(existingModel, getHttpHeaders()); + if (rb != null) return rb.build(); // preconditions not met + } + catch (NotFoundException ex) + { + //if (existingModel == null) existingModel = null; + } - return super.delete(false, getURI()); + return super.delete(false, getURI()); + }); } /** @@ -1251,6 +1269,34 @@ public Response.ResponseBuilder evaluatePreconditions(Model model, HttpHeaders h return rb; } + + /** + * Runs a write to this document while holding the document's lock. + *

+ * The precondition {@link #evaluatePreconditions(Model, HttpHeaders)} checks is evaluated against a graph + * read moments earlier and written back moments later, in separate calls to the store. Two writers quoting the + * same entity tag that both read before either has written both pass it - the check alone does not close + * the lost update it is there to refuse. Holding the lock from the read to the write does: the writer behind + * reads the graph as the first one left it, and its tag no longer matches. The lock is reentrant, so a + * PATCH that empties the graph can complete as the DELETE it is. + * + * @param write the read-check-write sequence + * @return the write's response + * @see GraphLocks + */ + protected Response writeLocked(Supplier write) + { + Lock lock = getSystem().getGraphLocks().get(getURI()); + lock.lock(); + try + { + return write.get(); + } + finally + { + lock.unlock(); + } + } /** * Parses multipart RDF/POST request. diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/util/FileContextPersistence.java b/src/main/java/com/atomgraph/linkeddatahub/server/util/FileContextPersistence.java index 619829a337..1a579b0399 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/util/FileContextPersistence.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/util/FileContextPersistence.java @@ -20,12 +20,29 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; +import java.util.HashSet; +import java.util.Set; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.graph.Triple; import org.apache.jena.query.Dataset; import org.apache.jena.query.DatasetFactory; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFDataMgr; +import org.apache.jena.sparql.core.Quad; +import org.apache.jena.sparql.modify.request.QuadDataAcc; +import org.apache.jena.sparql.modify.request.UpdateDataDelete; +import org.apache.jena.sparql.modify.request.UpdateDataInsert; +import org.apache.jena.update.UpdateAction; +import org.apache.jena.update.UpdateFactory; +import org.apache.jena.update.UpdateRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,17 +53,29 @@ * deploys the platform and is regenerated from their sources on every boot - writing a runtime * change into it would be writing into something about to be overwritten, which is how an * installed package used to be lost on the next restart. The OVERLAY is written by the platform, - * lives outside the deployed application, and holds the dataspaces that have been changed since. + * lives outside the deployed application, and holds what has been changed since. * - * A dataspace the overlay carries REPLACES the configured one rather than adding to it, because a - * runtime change can remove a statement as well as add one: uninstalling a package removes an - * ldh:import, and a union would put it straight back. So once a dataspace has been changed at - * runtime its configuration file stops deciding what it says, and deleting the overlay hands that - * back. Each one says so in the log at startup. + * The overlay is a change: a SPARQL Update of DELETE DATA and INSERT DATA, the + * statements a runtime change removed from the configuration and the ones it added. Loading + * applies it to the configuration as it is now. A removal stays removed - uninstalling a package + * deletes an ldh:import, and the configuration cannot put it back - while a statement the deployer + * adds to the configuration later takes effect, even in a dataspace that has been changed at + * runtime. The overlay used to be a copy of each changed dataspace, which replaced its + * configuration wholesale: the wiring config/system.trig contributes to the same graph froze at + * the moment of the first runtime change, and graph versioning enabled afterwards never started. * - * Which dataspaces to write is worked out rather than tracked: a SPARQL update may touch any graph - * it likes, so the overlay is every dataspace whose description now differs from the configured - * one. That also keeps it small - a deployment that has changed nothing writes nothing. + * What to write is worked out rather than tracked: a SPARQL update may touch any graph it likes, + * so the overlay is the difference between the configured descriptions and the current ones. That + * also keeps it small - a deployment that has changed nothing writes nothing. + * + * Blank nodes cannot be matched across a restart - SPARQL forbids them in DELETE DATA, and a + * reload relabels them - so removing a statement that has one is not persisted. Dataspace + * descriptions do not use them. + * + * A copy-style overlay from before ({@code dataspaces.trig} beside the change file) is converted + * once: each dataspace it carries becomes the difference between it and the configuration. It + * cannot tell a statement removed at runtime from one added to the configuration after it was + * written, so the latter is carried over as removed and has to be added again. * * @author {@literal Martynas Jusevičius } */ @@ -61,9 +90,9 @@ public class FileContextPersistence implements ContextEndpointAccessor.Persisten /** * @param configured the configuration as the deployment's files describe it - * @param overlay where changes made at runtime are kept, or null for a deployment with nowhere - * to keep them - in which case they go back to the configured file, as they did - * before there was anywhere better + * @param overlay where changes made at runtime are kept, as a SPARQL Update, or null for a + * deployment with nowhere to keep them - in which case they go back to the + * configured file, as they did before there was anywhere better * @param configuredFile the file the configured dataset was read from */ public FileContextPersistence(Dataset configured, File overlay, File configuredFile) @@ -77,23 +106,43 @@ public FileContextPersistence(Dataset configured, File overlay, File configuredF /** * Returns the configuration to run on: what the deployment configured, with whatever has been - * changed since applied over it. + * changed since applied to it. * * @return the dataspace descriptions */ public Dataset load() { Dataset live = copy(configured); - if (overlay == null || !overlay.exists()) return live; + if (overlay == null) return live; - Dataset changes = RDFDataMgr.loadDataset(overlay.toURI().toString()); - changes.listModelNames().forEachRemaining(name -> + if (!overlay.exists()) { - live.removeNamedModel(name.getURI()); - live.addNamedModel(name.getURI(), changes.getNamedModel(name.getURI())); + File legacy = legacyOverlay(); + if (legacy == null || !legacy.exists()) return live; + + Dataset snapshot = RDFDataMgr.loadDataset(legacy.toURI().toString()); + Dataset converted = copy(configured); + snapshot.listModelNames().forEachRemaining(name -> + { + converted.removeNamedModel(name.getURI()); + converted.addNamedModel(name.getURI(), ModelFactory.createDefaultModel().add(snapshot.getNamedModel(name.getURI()))); + }); + + try + { + persist(converted); + if (log.isInfoEnabled()) log.info("Converted the dataspace copies in {} to the changes in {}", legacy, overlay); + } + catch (IOException ex) + { + if (log.isErrorEnabled()) log.error("Could not convert {} to {}; running on the configuration alone", legacy, overlay, ex); + return live; + } + } - if (log.isInfoEnabled()) log.info("Dataspace <{}> restored from {}; the configuration for it is not in effect", name.getURI(), overlay); - }); + UpdateRequest changes = read(overlay); + UpdateAction.execute(changes, live); + if (log.isInfoEnabled() && !changes.getOperations().isEmpty()) log.info("Applied the runtime changes in {} to the configuration", overlay); return live; } @@ -108,22 +157,85 @@ public void persist(Dataset updated) throws IOException return; } - Dataset changes = DatasetFactory.create(); - updated.listModelNames().forEachRemaining(name -> + QuadDataAcc removed = new QuadDataAcc(); + QuadDataAcc added = new QuadDataAcc(); + + Set names = new HashSet<>(); + configured.listModelNames().forEachRemaining(name -> names.add(name.getURI())); + updated.listModelNames().forEachRemaining(name -> names.add(name.getURI())); + + for (String uri : names) { - String uri = name.getURI(); - if (!configured.containsNamedModel(uri) || !configured.getNamedModel(uri).isIsomorphicWith(updated.getNamedModel(uri))) - changes.addNamedModel(uri, updated.getNamedModel(uri)); - }); + Node graph = NodeFactory.createURI(uri); + Model before = configured.containsNamedModel(uri) ? configured.getNamedModel(uri) : ModelFactory.createDefaultModel(); + Model after = updated.containsNamedModel(uri) ? updated.getNamedModel(uri) : ModelFactory.createDefaultModel(); + + before.difference(after).getGraph().find().forEachRemaining(triple -> + { + if (hasBlankNode(triple)) + { + if (log.isWarnEnabled()) log.warn("Removal of {} from <{}> is not persisted: it has a blank node", triple, uri); + } + else removed.addQuad(Quad.create(graph, triple)); + }); + after.difference(before).getGraph().find().forEachRemaining(triple -> added.addQuad(Quad.create(graph, triple))); + } + + UpdateRequest changes = new UpdateRequest(); + if (!removed.getQuads().isEmpty()) changes.add(new UpdateDataDelete(removed)); + if (!added.getQuads().isEmpty()) changes.add(new UpdateDataInsert(added)); if (overlay.getParentFile() != null) overlay.getParentFile().mkdirs(); - write(changes, overlay); + File temp = File.createTempFile(overlay.getName(), null, overlay.getParentFile()); + try (Writer out = new OutputStreamWriter(new FileOutputStream(temp), StandardCharsets.UTF_8)) + { + out.write(changes.toString()); + } + Files.move(temp.toPath(), overlay.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + + if (log.isInfoEnabled()) log.info("Wrote {} removed and {} added statement(s) to {}", removed.getQuads().size(), added.getQuads().size(), overlay); + } + + /** + * The copy-style overlay this one replaces: the same name, as TriG. + * + * @return the legacy overlay file, or null if the overlay has no name to derive it from + */ + protected File legacyOverlay() + { + String name = overlay.getName(); + int dot = name.lastIndexOf('.'); + if (dot <= 0) return null; + + return new File(overlay.getParentFile(), name.substring(0, dot) + ".trig"); + } + + /** + * Reads the overlay's SPARQL Update. + * + * @param file the overlay + * @return the changes it holds + */ + protected UpdateRequest read(File file) + { + try + { + return UpdateFactory.create(Files.readString(file.toPath(), StandardCharsets.UTF_8)); + } + catch (IOException ex) + { + throw new IllegalStateException("Could not read the settings overlay " + file, ex); + } + } - if (log.isInfoEnabled()) log.info("Wrote {} changed dataspace(s) to {}", changes.listModelNames().hasNext() ? "some" : "no", overlay); + private static boolean hasBlankNode(Triple triple) + { + return triple.getSubject().isBlank() || triple.getObject().isBlank(); } /** - * A dataset holding the same graphs as another, so that replacing one leaves the original alone. + * A dataset holding the same graphs as another, so that changing one leaves the original alone. Each graph is + * copied into a model of its own, because applying the overlay deletes from it. * * @param dataset the dataset to copy * @return the copy @@ -132,7 +244,7 @@ protected Dataset copy(Dataset dataset) { Dataset copy = DatasetFactory.create(); copy.setDefaultModel(dataset.getDefaultModel()); - dataset.listModelNames().forEachRemaining(name -> copy.addNamedModel(name.getURI(), dataset.getNamedModel(name.getURI()))); + dataset.listModelNames().forEachRemaining(name -> copy.addNamedModel(name.getURI(), ModelFactory.createDefaultModel().add(dataset.getNamedModel(name.getURI())))); return copy; } diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphLocks.java b/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphLocks.java new file mode 100644 index 0000000000..43449cef09 --- /dev/null +++ b/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphLocks.java @@ -0,0 +1,70 @@ +/** + * Copyright 2026 Martynas Jusevičius + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.atomgraph.linkeddatahub.server.util; + +import com.google.common.util.concurrent.Striped; +import java.net.URI; +import java.util.concurrent.locks.Lock; + +/** + * Locks that serialise the writes to a named graph within this instance. + *

+ * A write to a document is a read-modify-write spread over separate calls to the store: the graph is read, + * the If-Match precondition is evaluated against what came back, the change is applied in + * memory and validated, and the whole graph is written back. The store sees independent requests, so the + * precondition is only as good as the window between the read and the write. Two writers quoting the same + * entity tag that both read before either has written both pass it, and the second write silently undoes the + * first - the very lost update the precondition exists to refuse. The Graph Store Protocol has no + * compare-and-swap, so the check is made atomic here instead: a writer holds the graph's lock from the read + * to the write, and the writer behind it reads the graph as the first one left it, quotes a tag that no longer + * matches, and is answered 412. + *

+ * The locks are striped rather than one per URI so that the set stays bounded. Two graphs may share a stripe, + * which serialises writes that did not need serialising, but never lets two writes to the same graph + * interleave. They are reentrant, since a PATCH that empties a graph completes as a + * DELETE of it. + *

+ * This serialises the writers that go through this instance. A second instance writing to the same store is not + * covered, nor is anything that writes to the store directly. + * + * @author Martynas Jusevičius {@literal } + */ +public class GraphLocks +{ + + /** + * Number of stripes the graph URIs are spread over. + */ + public static final int STRIPES = 1024; + + private final Striped locks = Striped.lock(STRIPES); + + /** + * Returns the lock a write to the given graph has to hold from its read of the graph to its write. + * The same graph URI always yields the same lock. + * + * @param graphURI named graph URI + * @return reentrant lock for the graph + */ + public Lock get(URI graphURI) + { + if (graphURI == null) throw new IllegalArgumentException("Graph URI cannot be null"); + + return locks.get(graphURI); + } + +} diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphVersioningService.java b/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphVersioningService.java index 822fe2f417..2604e0283e 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphVersioningService.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/util/GraphVersioningService.java @@ -278,12 +278,10 @@ public Optional getTimeMap(String appURI, URI appBase, URI graphURI) if (repository == null) return Optional.empty(); String path = path(repository.pathPrefix(), appBase, graphURI); - List commits = repository.client().listCommits(path); - // a TimeMap is a list of Mementos; without any, there is no history to describe and the Original Resource - // would not be derivable from the model either (it is reached through prov:specializationOf) - if (commits.isEmpty()) return Optional.empty(); - - return Optional.of(toTimeMap(graphURI, commits)); + // a document of a versioned dataspace has a TimeMap whether or not it has been written since versioning + // began - every one is advertised with rel=timemap - so one with no commits yet has an empty TimeMap + // rather than none: a 404 there was a History link leading nowhere for every document that predated it + return Optional.of(toTimeMap(graphURI, repository.client().listCommits(path))); } /** diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/util/Link.java b/src/main/java/com/atomgraph/linkeddatahub/server/util/Link.java index 7c4d552adc..3ada5c32f8 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/util/Link.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/util/Link.java @@ -16,39 +16,288 @@ */ package com.atomgraph.linkeddatahub.server.util; +import jakarta.ws.rs.core.UriBuilder; +import jakarta.ws.rs.ext.RuntimeDelegate; import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** - * Link header value that quotes its type parameter. - * RFC 8288 allows a parameter value to be either a token or a quoted-string. A media type such as - * application/link-format contains a solidus, which is not a tchar, so it - * can only be conveyed as a quoted-string. + * A web link (RFC 8288) that keeps its target URI exactly as given. + * + * Jersey's own implementation of {@link jakarta.ws.rs.core.Link} holds its target in a {@link UriBuilder}, + * which drops an empty fragment: https://localhost:4443/ns# - the shape of every dataspace's + * ontology namespace - comes out as https://localhost:4443/ns, a different URI, whether the + * link is built or parsed. This one stores the {@link URI} itself, and Jersey's header delegate, which + * serializes from {@link #getUri()}, writes it intact. Everything else - the header syntax, the quoting + * of relation types, parameter parsing - stays Jersey's. * * @author Martynas Jusevičius {@literal } - * @see RFC 8288: Web Linking + * @see RFC 8288: Web Linking */ -public class Link extends com.atomgraph.core.util.Link +public class Link extends jakarta.ws.rs.core.Link { + /** The target of a link-value, and the parameters after it */ + private static final Pattern LINK_VALUE = Pattern.compile("^\\s*<([^>]*)>(.*)$", Pattern.DOTALL); + + /** Stands in for the target when Jersey parses the parameters, so its URI handling never sees the real one */ + private static final String PLACEHOLDER = ""; + + private final URI uri; + private final Map params; + + /** + * @param uri the link target, kept as given + * @param params the link parameters, rel, type and title included + */ + protected Link(URI uri, Map params) + { + if (uri == null) throw new IllegalArgumentException("Link URI cannot be null"); + if (params == null) throw new IllegalArgumentException("Link params cannot be null"); + + this.uri = uri; + this.params = Collections.unmodifiableMap(new LinkedHashMap<>(params)); + } + + /** + * Starts a link to the given target. + * + * @param uri link target + * @return link builder + */ + public static Builder fromUri(URI uri) + { + return new Builder().uri(uri); + } + + /** + * Starts a link to the given target. + * + * @param uri link target + * @return link builder + */ + public static Builder fromUri(String uri) + { + return new Builder().uri(uri); + } + /** - * Constructs a link from a target URI, relation type and media type. + * Parses a link-value. The target is taken from between the angle brackets as it is written; Jersey + * parses the parameters. * - * @param href target URI - * @param rel relation type - * @param type media type of the target, or null + * @param value link-value, e.g. <https://localhost:4443/ns#>; rel="https://w3id.org/atomgraph/linkeddatahub/dataspaces#ontology" + * @return the link + * @throws IllegalArgumentException if the value is not a link-value */ - public Link(URI href, String rel, String type) + public static Link valueOf(String value) + { + if (value == null) throw new IllegalArgumentException("Link value cannot be null"); + + Matcher matcher = LINK_VALUE.matcher(value); + if (!matcher.matches()) throw new IllegalArgumentException("Not a link-value: " + value); + + return new Link(URI.create(matcher.group(1).trim()), jakarta.ws.rs.core.Link.valueOf(PLACEHOLDER + matcher.group(2)).getParams()); + } + + @Override + public URI getUri() + { + return uri; + } + + @Override + public UriBuilder getUriBuilder() + { + return UriBuilder.fromUri(getUri()); + } + + @Override + public String getRel() + { + return getParams().get(REL); + } + + @Override + public List getRels() + { + return getRel() == null ? Collections.emptyList() : Arrays.asList(getRel().trim().split("\\s+")); + } + + @Override + public String getTitle() { - super(href, rel, type); + return getParams().get(TITLE); } + @Override + public String getType() + { + return getParams().get(TYPE); + } + + @Override + public Map getParams() + { + return params; + } + + /** + * Serializes the link as a Link header value, with Jersey's header delegate. + * + * @return the link-value + */ @Override public String toString() { - StringBuilder builder = new StringBuilder("<"); - builder.append(getHref()).append(">; rel=").append(getRel()); - if (getType() != null) builder.append("; type=\"").append(getType()).append("\""); - return builder.toString(); + return RuntimeDelegate.getInstance().createHeaderDelegate(jakarta.ws.rs.core.Link.class).toString(this); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) return true; + if (!(obj instanceof jakarta.ws.rs.core.Link other)) return false; + + return getUri().equals(other.getUri()) && getParams().equals(other.getParams()); + } + + @Override + public int hashCode() + { + return Objects.hash(getUri(), getParams()); + } + + /** + * Builds a {@link Link}. Shaped like Jersey's builder, except that the target is a {@link URI} rather than + * a {@link UriBuilder}, so it is not normalized on the way through. + */ + public static class Builder implements jakarta.ws.rs.core.Link.Builder + { + + private URI uri; + private URI baseUri; + private final Map params = new LinkedHashMap<>(); + + @Override + public Builder link(jakarta.ws.rs.core.Link link) + { + uri(link.getUri()); + params.clear(); + params.putAll(link.getParams()); + return this; + } + + @Override + public Builder link(String link) + { + return link(valueOf(link)); + } + + @Override + public Builder uri(URI uri) + { + this.uri = uri; + return this; + } + + @Override + public Builder uri(String uri) + { + return uri(URI.create(uri)); + } + + @Override + public Builder baseUri(URI uri) + { + this.baseUri = uri; + return this; + } + + @Override + public Builder baseUri(String uri) + { + return baseUri(URI.create(uri)); + } + + /** + * Not supported: a {@link UriBuilder} is what loses the empty fragment. + * + * @param uriBuilder URI builder + * @return never + * @throws UnsupportedOperationException always + */ + @Override + public Builder uriBuilder(UriBuilder uriBuilder) + { + throw new UnsupportedOperationException("Build the URI first and pass it to uri(URI): a UriBuilder drops an empty fragment"); + } + + /** + * Adds a relation type. A repeated call adds another one, space-separated, as Jersey's builder does. + * + * @param rel relation type + * @return this builder + */ + @Override + public Builder rel(String rel) + { + if (rel == null) throw new IllegalArgumentException("Link relation type cannot be null"); + + params.merge(REL, rel, (existing, added) -> existing + " " + added); + return this; + } + + @Override + public Builder title(String title) + { + return param(TITLE, title); + } + + @Override + public Builder type(String type) + { + return param(TYPE, type); + } + + @Override + public Builder param(String name, String value) + { + if (name == null || value == null) throw new IllegalArgumentException("Link parameter name and value cannot be null"); + + params.put(name, value); + return this; + } + + /** + * Builds the link. The target is resolved against the base URI, if one was given. + * + * @param values URI template values; not supported, since the target is not a template + * @return the link + */ + @Override + public Link build(Object... values) + { + if (values != null && values.length > 0) throw new UnsupportedOperationException("Link URI templates are not supported"); + if (uri == null) throw new IllegalArgumentException("Link URI cannot be null"); + + return new Link(baseUri != null ? baseUri.resolve(uri) : uri, params); + } + + @Override + public Link buildRelativized(URI uri, Object... values) + { + Link link = build(values); + + return new Link(uri.relativize(link.getUri()), link.getParams()); + } + } } diff --git a/src/main/java/com/atomgraph/linkeddatahub/vocabulary/ORCID.java b/src/main/java/com/atomgraph/linkeddatahub/vocabulary/ORCID.java index c64923c8e6..a5d9470c93 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/vocabulary/ORCID.java +++ b/src/main/java/com/atomgraph/linkeddatahub/vocabulary/ORCID.java @@ -46,4 +46,7 @@ public static String getURI() /** Client secret property */ public static final Property clientSecret = m_model.createDataProperty( NS + "clientSecret" ); + /** Issuer property: the ORCID environment the client is registered with, such as https://sandbox.orcid.org */ + public static final Property issuer = m_model.createDataProperty( NS + "issuer" ); + } diff --git a/src/main/java/com/atomgraph/linkeddatahub/writer/TimeMapWriter.java b/src/main/java/com/atomgraph/linkeddatahub/writer/TimeMapWriter.java index 838a4ce7d0..4a41d5803c 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/writer/TimeMapWriter.java +++ b/src/main/java/com/atomgraph/linkeddatahub/writer/TimeMapWriter.java @@ -17,6 +17,7 @@ package com.atomgraph.linkeddatahub.writer; import com.atomgraph.linkeddatahub.server.model.impl.DocumentHierarchyGraphStoreImpl; +import com.atomgraph.linkeddatahub.server.util.Link; import com.atomgraph.linkeddatahub.vocabulary.PROV; import jakarta.ws.rs.Produces; import jakarta.ws.rs.WebApplicationException; @@ -43,6 +44,7 @@ import java.util.List; import java.util.Locale; import java.util.Optional; +import java.util.stream.Collectors; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.Resource; @@ -54,7 +56,8 @@ * TimeMaps to support. The model is the PROV-O description built by * {@link com.atomgraph.linkeddatahub.server.util.GraphVersioningService#toTimeMap}: the TimeMap is the * prov:Collection, its prov:hadMember values are the Mementos, and the Original - * Resource is the prov:specializationOf target they share. + * Resource is the prov:specializationOf target they share - or, for a document not written since + * versioning began, which has no Mementos yet, the resource the request addresses. * * @author Martynas Jusevičius {@literal } * @see RFC 7089: TimeMap @@ -91,34 +94,53 @@ public void writeTo(Model model, Class type, Type genericType, Annotation[] a { Resource timeMap = getTimeMap(model); List mementos = getMementos(timeMap); - if (mementos.isEmpty()) throw new IllegalStateException("TimeMap <" + timeMap.getURI() + "> has no mementos"); - Resource original = mementos.get(0).getPropertyResourceValue(PROV.specializationOf); - Resource first = mementos.get(0), last = mementos.get(mementos.size() - 1); - - List links = new ArrayList<>(); - links.add("<" + original.getURI() + ">;rel=\"original\""); - links.add("<" + timeMap.getURI() + ">;rel=\"self\";type=\"" + APPLICATION_LINK_FORMAT + "\"" + - ";from=\"" + datetime(first) + "\";until=\"" + datetime(last) + "\""); + // the Mementos name the Original Resource; a TimeMap with none yet is served at the Original Resource's ?timemap + URI original = mementos.isEmpty() ? + getOriginalURI().orElseThrow(() -> new IllegalStateException("TimeMap <" + timeMap.getURI() + "> has no mementos and there is no request to name its Original Resource")) : + URI.create(mementos.get(0).getPropertyResourceValue(PROV.specializationOf).getURI()); + + List links = new ArrayList<>(); + links.add(Link.fromUri(original).rel("original").build()); + // from and until bound the Mementos, so an empty TimeMap states neither + Link.Builder self = Link.fromUri(timeMap.getURI()).rel("self").type(APPLICATION_LINK_FORMAT); + if (!mementos.isEmpty()) self.param("from", datetime(mementos.get(0))).param("until", datetime(mementos.get(mementos.size() - 1))); + links.add(self.build()); // the TimeGate is deployment hypermedia rather than part of the version history, so it comes from the request - getTimeGateURI().ifPresent(timeGate -> links.add("<" + timeGate + ">;rel=\"timegate\"")); + getTimeGateURI().ifPresent(timeGate -> links.add(Link.fromUri(timeGate).rel("timegate").build())); - for (Resource memento : mementos) + for (int i = 0; i < mementos.size(); i++) { - // a single memento is both the first and the last one known - List rels = new ArrayList<>(); - if (memento.equals(first)) rels.add("first"); - if (memento.equals(last)) rels.add("last"); - rels.add("memento"); - - links.add("<" + memento.getURI() + ">;rel=\"" + String.join(" ", rels) + "\";datetime=\"" + datetime(memento) + "\""); + Resource memento = mementos.get(i); + // a single memento is both the first and the last one known; the builder joins repeated rels with a space + Link.Builder link = Link.fromUri(memento.getURI()); + if (i == 0) link.rel("first"); + if (i == mementos.size() - 1) link.rel("last"); + links.add(link.rel("memento").param("datetime", datetime(memento)).build()); } Writer writer = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8); - writer.write(String.join(",\n", links)); + writer.write(links.stream().map(TimeMapWriter::linkFormat).collect(Collectors.joining(",\n"))); writer.flush(); } + /** + * Serializes a link as an RFC 6690 link-value. Not {@link Link#toString()}: Jersey writes the HTTP + * Link header form, which puts a space after each ;, while the link-format + * grammar is "<" URI-Reference ">" *( ";" link-param ) with no whitespace. + * + * @param link the link + * @return the link-value + * @see RFC 6690: Link Format + */ + public static String linkFormat(jakarta.ws.rs.core.Link link) + { + // parameters in the order they were added: rel and type lead, as in RFC 7089's examples + return "<" + link.getUri() + ">" + link.getParams().entrySet().stream(). + map(param -> ";" + param.getKey() + "=\"" + param.getValue() + "\""). + collect(Collectors.joining()); + } + /** * Returns the TimeGate URI of the resource being served, if there is a request to derive it from. * @@ -131,6 +153,19 @@ protected Optional getTimeGateURI() return Optional.of(URI.create(getUriInfo().getAbsolutePath() + "?" + DocumentHierarchyGraphStoreImpl.TIMEGATE_PARAM_NAME)); } + /** + * Returns the Original Resource of the TimeMap being served, if there is a request to derive it from: the + * request URI without the query that makes it a TimeMap. + * + * @return Original Resource URI, or empty outside a request + */ + protected Optional getOriginalURI() + { + if (getUriInfo() == null) return Optional.empty(); + + return Optional.of(getUriInfo().getAbsolutePath()); + } + /** * Returns the URI info of the current request. * diff --git a/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java b/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java index 7d3b8d8c52..2ca16a1eab 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java +++ b/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java @@ -24,8 +24,8 @@ import com.atomgraph.linkeddatahub.vocabulary.LDHT; import com.atomgraph.linkeddatahub.vocabulary.Google; import com.atomgraph.linkeddatahub.vocabulary.ORCID; +import com.atomgraph.linkeddatahub.server.util.Link; import com.atomgraph.linkeddatahub.vocabulary.LDS; -import com.atomgraph.core.util.Link; import com.atomgraph.linkeddatahub.server.security.AuthorizationContext; import com.atomgraph.linkeddatahub.vocabulary.FOAF; import com.atomgraph.linkeddatahub.vocabulary.LDHC; @@ -191,14 +191,14 @@ public URI getLinkURI(MultivaluedMap headerMap, Property propert { return Link.valueOf(header.trim()); } - catch (URISyntaxException ex) + catch (IllegalArgumentException ex) { - if (log.isWarnEnabled()) log.warn("Could not parse Link URI", ex); + if (log.isWarnEnabled()) log.warn("Could not parse Link header value: {}", header, ex); return null; } }). - filter(link -> link != null && link.getRel() != null && link.getRel().equals(property.getURI())). - map(link -> link.getHref()). + filter(link -> link != null && link.getRels().contains(property.getURI())). + map(Link::getUri). collect(Collectors.toList()); if (!baseLinks.isEmpty()) return baseLinks.get(0); diff --git a/src/main/java/com/atomgraph/server/mapper/ExceptionMapperBase.java b/src/main/java/com/atomgraph/server/mapper/ExceptionMapperBase.java index 220be7f397..571fe16510 100644 --- a/src/main/java/com/atomgraph/server/mapper/ExceptionMapperBase.java +++ b/src/main/java/com/atomgraph/server/mapper/ExceptionMapperBase.java @@ -31,7 +31,7 @@ import jakarta.ws.rs.core.Variant; import jakarta.ws.rs.ext.Provider; import com.atomgraph.core.MediaTypes; -import com.atomgraph.core.util.Link; +import com.atomgraph.linkeddatahub.server.util.Link; import com.atomgraph.linkeddatahub.vocabulary.LDS; import com.atomgraph.server.vocabulary.HTTP; import jakarta.inject.Inject; @@ -93,7 +93,7 @@ public Response.ResponseBuilder getResponseBuilder(Model model) return Response.ok(). // status will be overriden in the subclasses entity(model). variant(variant). - header(HttpHeaders.LINK, new Link(getUriInfo().getBaseUri(), LDS.base.getURI(), null)); + header(HttpHeaders.LINK, Link.fromUri(getUriInfo().getBaseUri()).rel(LDS.base.getURI()).build()); } /** diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/js/SPARQLBuilder.js b/src/main/webapp/static/com/atomgraph/linkeddatahub/js/SPARQLBuilder.js deleted file mode 100644 index a808c48855..0000000000 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/js/SPARQLBuilder.js +++ /dev/null @@ -1,2627 +0,0 @@ -window["SPARQLBuilder"] = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./src/com/atomgraph/linkeddatahub/query/SPARQLBuilder.ts"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ "./node_modules/process/browser.js": -/*!*****************************************!*\ - !*** ./node_modules/process/browser.js ***! - \*****************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), - -/***/ "./node_modules/sparqljs/lib/SparqlGenerator.js": -/*!******************************************************!*\ - !*** ./node_modules/sparqljs/lib/SparqlGenerator.js ***! - \******************************************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -var XSD_INTEGER = 'http://www.w3.org/2001/XMLSchema#integer'; - -function Generator(options, prefixes) { - this._options = options = options || {}; - - prefixes = prefixes || {}; - this._prefixByIri = {}; - var prefixIris = []; - for (var prefix in prefixes) { - var iri = prefixes[prefix]; - if (isString(iri)) { - this._prefixByIri[iri] = prefix; - prefixIris.push(iri); - } - } - var iriList = prefixIris.join('|').replace(/[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&'); - this._prefixRegex = new RegExp('^(' + iriList + ')([a-zA-Z][\\-_a-zA-Z0-9]*)$'); - this._usedPrefixes = {}; - this._indent = isString(options.indent) ? options.indent : ' '; - this._newline = isString(options.newline) ? options.newline : '\n'; -} - -// Converts the parsed query object into a SPARQL query -Generator.prototype.toQuery = function (q) { - var query = ''; - - if (q.queryType) - query += q.queryType.toUpperCase() + ' '; - if (q.reduced) - query += 'REDUCED '; - if (q.distinct) - query += 'DISTINCT '; - - if (q.variables) - query += mapJoin(q.variables, undefined, function (variable) { - return isString(variable) ? this.toEntity(variable) : - '(' + this.toExpression(variable.expression) + ' AS ' + variable.variable + ')'; - }, this) + ' '; - else if (q.template) - query += this.group(q.template, true) + this._newline; - - if (q.from) - query += mapJoin(q.from.default || [], '', function (g) { return 'FROM ' + this.toEntity(g) + this._newline; }, this) + - mapJoin(q.from.named || [], '', function (g) { return 'FROM NAMED ' + this.toEntity(g) + this._newline; }, this); - if (q.where) - query += 'WHERE ' + this.group(q.where, true) + this._newline; - - if (q.updates) - query += mapJoin(q.updates, ';' + this._newline, this.toUpdate, this); - - if (q.group) - query += 'GROUP BY ' + mapJoin(q.group, undefined, function (it) { - var result = isString(it.expression) ? it.expression : '(' + this.toExpression(it.expression) + ')'; - return it.variable ? '(' + result + ' AS ' + it.variable + ')' : result; - }, this) + this._newline; - if (q.having) - query += 'HAVING (' + mapJoin(q.having, undefined, this.toExpression, this) + ')' + this._newline; - if (q.order) - query += 'ORDER BY ' + mapJoin(q.order, undefined, function (it) { - var expr = '(' + this.toExpression(it.expression) + ')'; - return !it.descending ? expr : 'DESC ' + expr; - }, this) + this._newline; - - if (q.offset) - query += 'OFFSET ' + q.offset + this._newline; - if (q.limit) - query += 'LIMIT ' + q.limit + this._newline; - - if (q.values) - query += this.values(q); - - // stringify prefixes at the end to mark used ones - query = this.baseAndPrefixes(q) + query; - return query.trim(); -}; - -Generator.prototype.baseAndPrefixes = function (q) { - var base = q.base ? ('BASE <' + q.base + '>' + this._newline) : ''; - var prefixes = ''; - for (var key in q.prefixes) { - if (this._options.allPrefixes || this._usedPrefixes[key]) - prefixes += 'PREFIX ' + key + ': <' + q.prefixes[key] + '>' + this._newline; - } - return base + prefixes; -}; - -// Converts the parsed SPARQL pattern into a SPARQL pattern -Generator.prototype.toPattern = function (pattern) { - var type = pattern.type || (pattern instanceof Array) && 'array' || - (pattern.subject && pattern.predicate && pattern.object ? 'triple' : ''); - if (!(type in this)) - throw new Error('Unknown entry type: ' + type); - return this[type](pattern); -}; - -Generator.prototype.triple = function (t) { - return this.toEntity(t.subject) + ' ' + this.toEntity(t.predicate) + ' ' + this.toEntity(t.object) + '.'; -}; - -Generator.prototype.array = function (items) { - return mapJoin(items, this._newline, this.toPattern, this); -}; - -Generator.prototype.bgp = function (bgp) { - return this.encodeTriples(bgp.triples); -}; - -Generator.prototype.encodeTriples = function (triples) { - if (!triples.length) - return ''; - - var parts = [], subject = '', predicate = ''; - for (var i = 0; i < triples.length; i++) { - var triple = triples[i]; - // Triple with different subject - if (triple.subject !== subject) { - // Terminate previous triple - if (subject) - parts.push('.' + this._newline); - subject = triple.subject; - predicate = triple.predicate; - parts.push(this.toEntity(subject), ' ', this.toEntity(predicate)); - } - // Triple with same subject but different predicate - else if (triple.predicate !== predicate) { - predicate = triple.predicate; - parts.push(';' + this._newline, this._indent, this.toEntity(predicate)); - } - // Triple with same subject and predicate - else { - parts.push(','); - } - parts.push(' ', this.toEntity(triple.object)); - } - parts.push('.'); - - return parts.join(''); -} - -Generator.prototype.graph = function (graph) { - return 'GRAPH ' + this.toEntity(graph.name) + ' ' + this.group(graph); -}; - -Generator.prototype.group = function (group, inline) { - group = inline !== true ? this.array(group.patterns || group.triples) - : this.toPattern(group.type !== 'group' ? group : group.patterns); - return group.indexOf(this._newline) === -1 ? '{ ' + group + ' }' : '{' + this._newline + this.indent(group) + this._newline + '}'; -}; - -Generator.prototype.query = function (query) { - return this.toQuery(query); -}; - -Generator.prototype.filter = function (filter) { - return 'FILTER(' + this.toExpression(filter.expression) + ')'; -}; - -Generator.prototype.bind = function (bind) { - return 'BIND(' + this.toExpression(bind.expression) + ' AS ' + bind.variable + ')'; -}; - -Generator.prototype.optional = function (optional) { - return 'OPTIONAL ' + this.group(optional); -}; - -Generator.prototype.union = function (union) { - return mapJoin(union.patterns, this._newline + 'UNION' + this._newline, function (p) { return this.group(p, true); }, this); -}; - -Generator.prototype.minus = function (minus) { - return 'MINUS ' + this.group(minus); -}; - -Generator.prototype.values = function (valuesList) { - // Gather unique keys - var keys = Object.keys(valuesList.values.reduce(function (keyHash, values) { - for (var key in values) keyHash[key] = true; - return keyHash; - }, {})); - // Check whether simple syntax can be used - var lparen, rparen; - if (keys.length === 1) { - lparen = rparen = ''; - } else { - lparen = '('; - rparen = ')'; - } - // Create value rows - return 'VALUES ' + lparen + keys.join(' ') + rparen + ' {' + this._newline + - mapJoin(valuesList.values, this._newline, function (values) { - return ' ' + lparen + mapJoin(keys, undefined, function (key) { - return values[key] !== undefined ? this.toEntity(values[key]) : 'UNDEF'; - }, this) + rparen; - }, this) + this._newline + '}'; -}; - -Generator.prototype.service = function (service) { - return 'SERVICE ' + (service.silent ? 'SILENT ' : '') + this.toEntity(service.name) + ' ' + - this.group(service); -}; - -// Converts the parsed expression object into a SPARQL expression -Generator.prototype.toExpression = function (expr) { - if (isString(expr)) - return this.toEntity(expr); - - switch (expr.type.toLowerCase()) { - case 'aggregate': - return expr.aggregation.toUpperCase() + - '(' + (expr.distinct ? 'DISTINCT ' : '') + this.toExpression(expr.expression) + - (expr.separator ? '; SEPARATOR = ' + this.toEntity('"' + expr.separator + '"') : '') + ')'; - case 'functioncall': - return this.toEntity(expr.function) + '(' + mapJoin(expr.args, ', ', this.toExpression, this) + ')'; - case 'operation': - var operator = expr.operator.toUpperCase(), args = expr.args || []; - switch (expr.operator.toLowerCase()) { - // Infix operators - case '<': - case '>': - case '>=': - case '<=': - case '&&': - case '||': - case '=': - case '!=': - case '+': - case '-': - case '*': - case '/': - return (isString(args[0]) ? this.toEntity(args[0]) : '(' + this.toExpression(args[0]) + ')') + - ' ' + operator + ' ' + - (isString(args[1]) ? this.toEntity(args[1]) : '(' + this.toExpression(args[1]) + ')'); - // Unary operators - case '!': - return '!(' + this.toExpression(args[0]) + ')'; - // IN and NOT IN - case 'notin': - operator = 'NOT IN'; - case 'in': - return this.toExpression(args[0]) + ' ' + operator + - '(' + (isString(args[1]) ? args[1] : mapJoin(args[1], ', ', this.toExpression, this)) + ')'; - // EXISTS and NOT EXISTS - case 'notexists': - operator = 'NOT EXISTS'; - case 'exists': - return operator + ' ' + this.group(args[0], true); - // Other expressions - default: - return operator + '(' + mapJoin(args, ', ', this.toExpression, this) + ')'; - } - default: - throw new Error('Unknown expression type: ' + expr.type); - } -}; - -// Converts the parsed entity (or property path) into a SPARQL entity -Generator.prototype.toEntity = function (value) { - // regular entity - if (isString(value)) { - switch (value[0]) { - // variable, * selector, or blank node - case '?': - case '$': - case '*': - case '_': - return value; - // literal - case '"': - var match = value.match(/^"([^]*)"(?:(@.+)|\^\^(.+))?$/) || {}, - lexical = match[1] || '', language = match[2] || '', datatype = match[3]; - value = '"' + lexical.replace(escape, escapeReplacer) + '"' + language; - if (datatype) { - if (datatype === XSD_INTEGER && /^\d+$/.test(lexical)) - // Add space to avoid confusion with decimals in broken parsers - return lexical + ' '; - value += '^^' + this.encodeIRI(datatype); - } - return value; - // IRI - default: - return this.encodeIRI(value); - } - } - // property path - else { - var items = value.items.map(this.toEntity, this), path = value.pathType; - switch (path) { - // prefix operator - case '^': - case '!': - return path + items[0]; - // postfix operator - case '*': - case '+': - case '?': - return '(' + items[0] + path + ')'; - // infix operator - default: - return '(' + items.join(path) + ')'; - } - } -}; -var escape = /["\\\t\n\r\b\f]/g, - escapeReplacer = function (c) { return escapeReplacements[c]; }, - escapeReplacements = { '\\': '\\\\', '"': '\\"', '\t': '\\t', - '\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f' }; - -// Represent the IRI, as a prefixed name when possible -Generator.prototype.encodeIRI = function (iri) { - var prefixMatch = this._prefixRegex.exec(iri); - if (prefixMatch) { - var prefix = this._prefixByIri[prefixMatch[1]]; - this._usedPrefixes[prefix] = true; - return prefix + ':' + prefixMatch[2]; - } - return '<' + iri + '>'; -}; - -// Converts the parsed update object into a SPARQL update clause -Generator.prototype.toUpdate = function (update) { - switch (update.type || update.updateType) { - case 'load': - return 'LOAD' + (update.source ? ' ' + this.toEntity(update.source) : '') + - (update.destination ? ' INTO GRAPH ' + this.toEntity(update.destination) : ''); - case 'insert': - return 'INSERT DATA ' + this.group(update.insert, true); - case 'delete': - return 'DELETE DATA ' + this.group(update.delete, true); - case 'deletewhere': - return 'DELETE WHERE ' + this.group(update.delete, true); - case 'insertdelete': - return (update.graph ? 'WITH ' + this.toEntity(update.graph) + this._newline : '') + - (update.delete.length ? 'DELETE ' + this.group(update.delete, true) + this._newline : '') + - (update.insert.length ? 'INSERT ' + this.group(update.insert, true) + this._newline : '') + - 'WHERE ' + this.group(update.where, true); - case 'add': - case 'copy': - case 'move': - return update.type.toUpperCase() + (update.source.default ? ' DEFAULT ' : ' ') + - 'TO ' + this.toEntity(update.destination.name); - case 'create': - case 'clear': - case 'drop': - return update.type.toUpperCase() + (update.silent ? ' SILENT ' : ' ') + ( - update.graph.default ? 'DEFAULT' : - update.graph.named ? 'NAMED' : - update.graph.all ? 'ALL' : - ('GRAPH ' + this.toEntity(update.graph.name)) - ); - default: - throw new Error('Unknown update query type: ' + update.type); - } -}; - -// Indents each line of the string -Generator.prototype.indent = function(text) { return text.replace(/^/gm, this._indent); } - -// Checks whether the object is a string -function isString(object) { return typeof object === 'string'; } - -// Maps the array with the given function, and joins the results using the separator -function mapJoin(array, sep, func, self) { - return array.map(func, self).join(isString(sep) ? sep : ' '); -} - -/** - * @param options { - * allPrefixes: boolean, - * indentation: string, - * newline: string - * } - */ -module.exports = function SparqlGenerator(options) { - return { - stringify: function (q) { return new Generator(options, q.prefixes).toQuery(q); } - }; -}; - - -/***/ }), - -/***/ "./node_modules/sparqljs/lib/SparqlParser.js": -/*!***************************************************!*\ - !*** ./node_modules/sparqljs/lib/SparqlParser.js ***! - \***************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process, module) {/* parser generated by jison 0.4.18 */ -/* - Returns a Parser object of the following structure: - - Parser: { - yy: {} - } - - Parser.prototype: { - yy: {}, - trace: function(), - symbols_: {associative list: name ==> number}, - terminals_: {associative list: number ==> name}, - productions_: [...], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), - table: [...], - defaultActions: {...}, - parseError: function(str, hash), - parse: function(input), - - lexer: { - EOF: 1, - parseError: function(str, hash), - setInput: function(input), - input: function(), - unput: function(str), - more: function(), - less: function(n), - pastInput: function(), - upcomingInput: function(), - showPosition: function(), - test_match: function(regex_match_array, rule_index), - next: function(), - lex: function(), - begin: function(condition), - popState: function(), - _currentRules: function(), - topState: function(), - pushState: function(condition), - - options: { - ranges: boolean (optional: true ==> token location info will include a .range[] member) - flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) - backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) - }, - - performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), - rules: [...], - conditions: {associative list: name ==> set}, - } - } - - - token location info (@$, _$, etc.): { - first_line: n, - last_line: n, - first_column: n, - last_column: n, - range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) - } - - - the parseError function receives a 'hash' object with these members for lexer and parser errors: { - text: (matched text) - token: (the produced terminal token, if any) - line: (yylineno) - } - while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { - loc: (yylloc) - expected: (string describing the set of expected tokens) - recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) - } -*/ -var SparqlParser = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,12,15,24,34,43,48,99,109,112,114,115,124,125,130,298,299,300,301,302],$V1=[2,196],$V2=[99,109,112,114,115,124,125,130,298,299,300,301,302],$V3=[1,18],$V4=[1,27],$V5=[6,83],$V6=[38,39,51],$V7=[38,51],$V8=[1,55],$V9=[1,57],$Va=[1,53],$Vb=[1,56],$Vc=[28,29,293],$Vd=[13,16,286],$Ve=[111,133,296,303],$Vf=[13,16,111,133,286],$Vg=[1,80],$Vh=[1,84],$Vi=[1,86],$Vj=[111,133,296,297,303],$Vk=[13,16,111,133,286,297],$Vl=[1,92],$Vm=[2,236],$Vn=[1,91],$Vo=[13,16,28,29,80,86,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$Vp=[6,38,39,51,61,68,71,79,81,83],$Vq=[6,13,16,28,38,39,51,61,68,71,79,81,83,286],$Vr=[6,13,16,28,29,31,32,38,39,41,51,61,68,71,79,80,81,83,86,92,108,111,124,125,127,132,159,160,162,165,166,183,187,208,213,215,216,218,219,223,227,231,246,251,268,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,304,306,307,309,310,311,312,313,314,315,316],$Vs=[1,107],$Vt=[1,108],$Vu=[6,13,16,28,29,39,41,80,83,86,111,159,160,162,165,166,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,304],$Vv=[2,295],$Vw=[1,125],$Vx=[1,123],$Vy=[6,183],$Vz=[2,312],$VA=[2,300],$VB=[38,127],$VC=[6,41,68,71,79,81,83],$VD=[2,238],$VE=[1,139],$VF=[1,141],$VG=[1,151],$VH=[1,157],$VI=[1,160],$VJ=[1,156],$VK=[1,158],$VL=[1,154],$VM=[1,155],$VN=[1,161],$VO=[1,162],$VP=[1,165],$VQ=[1,166],$VR=[1,167],$VS=[1,168],$VT=[1,169],$VU=[1,170],$VV=[1,171],$VW=[1,172],$VX=[1,173],$VY=[1,174],$VZ=[1,175],$V_=[1,176],$V$=[6,61,68,71,79,81,83],$V01=[28,29,38,39,51],$V11=[13,16,28,29,80,248,249,250,252,254,255,257,258,261,263,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,316,317,318,319,320,321],$V21=[2,409],$V31=[1,189],$V41=[1,190],$V51=[1,191],$V61=[13,16,41,80,92,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$V71=[41,86],$V81=[28,32],$V91=[6,108,183],$Va1=[41,111],$Vb1=[6,41,71,79,81,83],$Vc1=[2,324],$Vd1=[2,316],$Ve1=[1,226],$Vf1=[1,228],$Vg1=[41,111,304],$Vh1=[13,16,28,29,32,39,41,80,83,86,111,159,160,162,165,166,183,187,208,213,215,216,218,219,251,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,304],$Vi1=[13,16,28,29,31,32,39,41,80,83,86,92,111,159,160,162,165,166,183,187,208,213,215,216,218,219,223,227,231,246,251,268,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,304,307,310,311,312,313,314,315,316],$Vj1=[13,16,28,29,31,32,39,41,80,83,86,92,111,159,160,162,165,166,183,187,208,213,215,216,218,219,223,227,231,246,251,268,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,304,307,310,311,312,313,314,315,316],$Vk1=[31,32,183,223,251],$Vl1=[31,32,183,223,227,251],$Vm1=[31,32,183,223,227,231,246,251,268,280,281,282,283,284,285,310,311,312,313,314,315,316],$Vn1=[31,32,183,223,227,231,246,251,268,280,281,282,283,284,285,293,307,310,311,312,313,314,315,316],$Vo1=[1,260],$Vp1=[1,261],$Vq1=[1,263],$Vr1=[1,264],$Vs1=[1,265],$Vt1=[1,266],$Vu1=[1,268],$Vv1=[1,269],$Vw1=[2,416],$Vx1=[1,271],$Vy1=[1,272],$Vz1=[1,273],$VA1=[1,279],$VB1=[1,274],$VC1=[1,275],$VD1=[1,276],$VE1=[1,277],$VF1=[1,278],$VG1=[1,286],$VH1=[1,299],$VI1=[6,41,79,81,83],$VJ1=[1,316],$VK1=[1,315],$VL1=[39,41,83,111,159,160,162,165,166],$VM1=[1,324],$VN1=[1,325],$VO1=[41,111,183,216,304],$VP1=[2,354],$VQ1=[13,16,28,29,32,80,86,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$VR1=[13,16,28,29,32,39,41,80,83,86,111,159,160,162,165,166,183,215,216,218,219,251,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,304],$VS1=[13,16,28,29,80,208,246,248,249,250,252,254,255,257,258,261,263,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,310,316,317,318,319,320,321],$VT1=[1,349],$VU1=[1,350],$VV1=[1,352],$VW1=[1,351],$VX1=[6,13,16,28,29,31,32,39,41,68,71,74,76,79,80,81,83,86,111,159,160,162,165,166,183,215,218,219,223,227,231,246,248,249,250,251,252,254,255,257,258,261,263,268,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,304,307,310,311,312,313,314,315,316,317,318,319,320,321],$VY1=[1,360],$VZ1=[1,359],$V_1=[29,86],$V$1=[13,16,32,41,80,92,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$V02=[29,41],$V12=[2,315],$V22=[6,41,83],$V32=[6,13,16,29,41,71,79,81,83,248,249,250,252,254,255,257,258,261,263,286,316,317,318,319,320,321],$V42=[6,13,16,28,29,39,41,71,74,76,79,80,81,83,86,111,159,160,162,165,166,215,218,219,248,249,250,252,254,255,257,258,261,263,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,304,316,317,318,319,320,321],$V52=[6,13,16,28,29,41,68,71,79,81,83,248,249,250,252,254,255,257,258,261,263,286,316,317,318,319,320,321],$V62=[6,13,16,28,29,31,32,39,41,61,68,71,74,76,79,80,81,83,86,111,159,160,162,165,166,183,215,218,219,223,227,231,246,248,249,250,251,252,254,255,257,258,261,263,268,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,304,305,307,310,311,312,313,314,315,316,317,318,319,320,321],$V72=[13,16,29,187,208,213,286],$V82=[2,366],$V92=[1,401],$Va2=[39,41,83,111,159,160,162,165,166,304],$Vb2=[13,16,28,29,32,39,41,80,83,86,111,159,160,162,165,166,183,187,215,216,218,219,251,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,304],$Vc2=[13,16,28,29,80,208,246,248,249,250,252,254,255,257,258,261,263,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,310,316,317,318,319,320,321],$Vd2=[1,450],$Ve2=[1,447],$Vf2=[1,448],$Vg2=[13,16,28,29,39,41,80,83,86,111,159,160,162,165,166,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$Vh2=[13,16,28,286],$Vi2=[13,16,28,29,39,41,80,83,86,111,159,160,162,165,166,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,304],$Vj2=[2,327],$Vk2=[39,41,83,111,159,160,162,165,166,183,216,304],$Vl2=[6,13,16,28,29,41,74,76,79,81,83,248,249,250,252,254,255,257,258,261,263,286,316,317,318,319,320,321],$Vm2=[2,322],$Vn2=[13,16,29,187,208,286],$Vo2=[13,16,32,80,92,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$Vp2=[13,16,28,29,41,80,86,111,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286],$Vq2=[13,16,28,29,32,80,86,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,306,307],$Vr2=[13,16,28,29,32,80,86,215,218,219,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,293,306,307,309,310],$Vs2=[1,561],$Vt2=[1,562],$Vu2=[2,310],$Vv2=[13,16,32,187,213,286]; -var parser = {trace: function trace () { }, -yy: {}, -symbols_: {"error":2,"QueryOrUpdate":3,"Prologue":4,"QueryOrUpdate_group0":5,"EOF":6,"Prologue_repetition0":7,"Query":8,"Query_group0":9,"Query_option0":10,"BaseDecl":11,"BASE":12,"IRIREF":13,"PrefixDecl":14,"PREFIX":15,"PNAME_NS":16,"SelectQuery":17,"SelectClause":18,"SelectQuery_repetition0":19,"WhereClause":20,"SolutionModifier":21,"SubSelect":22,"SubSelect_option0":23,"SELECT":24,"SelectClause_option0":25,"SelectClause_group0":26,"SelectClauseItem":27,"VAR":28,"(":29,"Expression":30,"AS":31,")":32,"ConstructQuery":33,"CONSTRUCT":34,"ConstructTemplate":35,"ConstructQuery_repetition0":36,"ConstructQuery_repetition1":37,"WHERE":38,"{":39,"ConstructQuery_option0":40,"}":41,"DescribeQuery":42,"DESCRIBE":43,"DescribeQuery_group0":44,"DescribeQuery_repetition0":45,"DescribeQuery_option0":46,"AskQuery":47,"ASK":48,"AskQuery_repetition0":49,"DatasetClause":50,"FROM":51,"DatasetClause_option0":52,"iri":53,"WhereClause_option0":54,"GroupGraphPattern":55,"SolutionModifier_option0":56,"SolutionModifier_option1":57,"SolutionModifier_option2":58,"SolutionModifier_option3":59,"GroupClause":60,"GROUP":61,"BY":62,"GroupClause_repetition_plus0":63,"GroupCondition":64,"BuiltInCall":65,"FunctionCall":66,"HavingClause":67,"HAVING":68,"HavingClause_repetition_plus0":69,"OrderClause":70,"ORDER":71,"OrderClause_repetition_plus0":72,"OrderCondition":73,"ASC":74,"BrackettedExpression":75,"DESC":76,"Constraint":77,"LimitOffsetClauses":78,"LIMIT":79,"INTEGER":80,"OFFSET":81,"ValuesClause":82,"VALUES":83,"InlineData":84,"InlineData_repetition0":85,"NIL":86,"InlineData_repetition1":87,"InlineData_repetition_plus2":88,"InlineData_repetition3":89,"DataBlockValue":90,"Literal":91,"UNDEF":92,"DataBlockValueList":93,"DataBlockValueList_repetition_plus0":94,"Update":95,"Update_repetition0":96,"Update1":97,"Update_option0":98,"LOAD":99,"Update1_option0":100,"Update1_option1":101,"Update1_group0":102,"Update1_option2":103,"GraphRefAll":104,"Update1_group1":105,"Update1_option3":106,"GraphOrDefault":107,"TO":108,"CREATE":109,"Update1_option4":110,"GRAPH":111,"INSERTDATA":112,"QuadPattern":113,"DELETEDATA":114,"DELETEWHERE":115,"Update1_option5":116,"InsertClause":117,"Update1_option6":118,"Update1_repetition0":119,"Update1_option7":120,"DeleteClause":121,"Update1_option8":122,"Update1_repetition1":123,"DELETE":124,"INSERT":125,"UsingClause":126,"USING":127,"UsingClause_option0":128,"WithClause":129,"WITH":130,"IntoGraphClause":131,"INTO":132,"DEFAULT":133,"GraphOrDefault_option0":134,"GraphRefAll_group0":135,"QuadPattern_option0":136,"QuadPattern_repetition0":137,"QuadsNotTriples":138,"QuadsNotTriples_group0":139,"QuadsNotTriples_option0":140,"QuadsNotTriples_option1":141,"QuadsNotTriples_option2":142,"TriplesTemplate":143,"TriplesTemplate_repetition0":144,"TriplesSameSubject":145,"TriplesTemplate_option0":146,"GroupGraphPatternSub":147,"GroupGraphPatternSub_option0":148,"GroupGraphPatternSub_repetition0":149,"GroupGraphPatternSubTail":150,"GraphPatternNotTriples":151,"GroupGraphPatternSubTail_option0":152,"GroupGraphPatternSubTail_option1":153,"TriplesBlock":154,"TriplesBlock_repetition0":155,"TriplesSameSubjectPath":156,"TriplesBlock_option0":157,"GraphPatternNotTriples_repetition0":158,"OPTIONAL":159,"MINUS":160,"GraphPatternNotTriples_group0":161,"SERVICE":162,"GraphPatternNotTriples_option0":163,"GraphPatternNotTriples_group1":164,"FILTER":165,"BIND":166,"FunctionCall_option0":167,"FunctionCall_repetition0":168,"ExpressionList":169,"ExpressionList_repetition0":170,"ConstructTemplate_option0":171,"ConstructTriples":172,"ConstructTriples_repetition0":173,"ConstructTriples_option0":174,"VarOrTerm":175,"PropertyListNotEmpty":176,"TriplesNode":177,"PropertyList":178,"PropertyList_option0":179,"VerbObjectList":180,"PropertyListNotEmpty_repetition0":181,"SemiOptionalVerbObjectList":182,";":183,"SemiOptionalVerbObjectList_option0":184,"Verb":185,"ObjectList":186,"a":187,"ObjectList_repetition0":188,"GraphNode":189,"PropertyListPathNotEmpty":190,"TriplesNodePath":191,"TriplesSameSubjectPath_option0":192,"PropertyListPathNotEmpty_group0":193,"PropertyListPathNotEmpty_repetition0":194,"GraphNodePath":195,"PropertyListPathNotEmpty_repetition1":196,"PropertyListPathNotEmptyTail":197,"PropertyListPathNotEmptyTail_group0":198,"Path":199,"Path_repetition0":200,"PathSequence":201,"PathSequence_repetition0":202,"PathEltOrInverse":203,"PathElt":204,"PathPrimary":205,"PathElt_option0":206,"PathEltOrInverse_option0":207,"!":208,"PathNegatedPropertySet":209,"PathOneInPropertySet":210,"PathNegatedPropertySet_repetition0":211,"PathNegatedPropertySet_option0":212,"^":213,"TriplesNode_repetition_plus0":214,"[":215,"]":216,"TriplesNodePath_repetition_plus0":217,"BLANK_NODE_LABEL":218,"ANON":219,"ConditionalAndExpression":220,"Expression_repetition0":221,"ExpressionTail":222,"||":223,"RelationalExpression":224,"ConditionalAndExpression_repetition0":225,"ConditionalAndExpressionTail":226,"&&":227,"AdditiveExpression":228,"RelationalExpression_group0":229,"RelationalExpression_option0":230,"IN":231,"MultiplicativeExpression":232,"AdditiveExpression_repetition0":233,"AdditiveExpressionTail":234,"AdditiveExpressionTail_group0":235,"NumericLiteralPositive":236,"AdditiveExpressionTail_repetition0":237,"NumericLiteralNegative":238,"AdditiveExpressionTail_repetition1":239,"UnaryExpression":240,"MultiplicativeExpression_repetition0":241,"MultiplicativeExpressionTail":242,"MultiplicativeExpressionTail_group0":243,"UnaryExpression_option0":244,"PrimaryExpression":245,"-":246,"Aggregate":247,"FUNC_ARITY0":248,"FUNC_ARITY1":249,"FUNC_ARITY2":250,",":251,"IF":252,"BuiltInCall_group0":253,"BOUND":254,"BNODE":255,"BuiltInCall_option0":256,"EXISTS":257,"COUNT":258,"Aggregate_option0":259,"Aggregate_group0":260,"FUNC_AGGREGATE":261,"Aggregate_option1":262,"GROUP_CONCAT":263,"Aggregate_option2":264,"Aggregate_option3":265,"GroupConcatSeparator":266,"SEPARATOR":267,"=":268,"String":269,"LANGTAG":270,"^^":271,"DECIMAL":272,"DOUBLE":273,"true":274,"false":275,"STRING_LITERAL1":276,"STRING_LITERAL2":277,"STRING_LITERAL_LONG1":278,"STRING_LITERAL_LONG2":279,"INTEGER_POSITIVE":280,"DECIMAL_POSITIVE":281,"DOUBLE_POSITIVE":282,"INTEGER_NEGATIVE":283,"DECIMAL_NEGATIVE":284,"DOUBLE_NEGATIVE":285,"PNAME_LN":286,"QueryOrUpdate_group0_option0":287,"Prologue_repetition0_group0":288,"SelectClause_option0_group0":289,"DISTINCT":290,"REDUCED":291,"SelectClause_group0_repetition_plus0":292,"*":293,"DescribeQuery_group0_repetition_plus0_group0":294,"DescribeQuery_group0_repetition_plus0":295,"NAMED":296,"SILENT":297,"CLEAR":298,"DROP":299,"ADD":300,"MOVE":301,"COPY":302,"ALL":303,".":304,"UNION":305,"|":306,"/":307,"PathElt_option0_group0":308,"?":309,"+":310,"!=":311,"<":312,">":313,"<=":314,">=":315,"NOT":316,"CONCAT":317,"COALESCE":318,"SUBSTR":319,"REGEX":320,"REPLACE":321,"$accept":0,"$end":1}, -terminals_: {2:"error",6:"EOF",12:"BASE",13:"IRIREF",15:"PREFIX",16:"PNAME_NS",24:"SELECT",28:"VAR",29:"(",31:"AS",32:")",34:"CONSTRUCT",38:"WHERE",39:"{",41:"}",43:"DESCRIBE",48:"ASK",51:"FROM",61:"GROUP",62:"BY",68:"HAVING",71:"ORDER",74:"ASC",76:"DESC",79:"LIMIT",80:"INTEGER",81:"OFFSET",83:"VALUES",86:"NIL",92:"UNDEF",99:"LOAD",108:"TO",109:"CREATE",111:"GRAPH",112:"INSERTDATA",114:"DELETEDATA",115:"DELETEWHERE",124:"DELETE",125:"INSERT",127:"USING",130:"WITH",132:"INTO",133:"DEFAULT",159:"OPTIONAL",160:"MINUS",162:"SERVICE",165:"FILTER",166:"BIND",183:";",187:"a",208:"!",213:"^",215:"[",216:"]",218:"BLANK_NODE_LABEL",219:"ANON",223:"||",227:"&&",231:"IN",246:"-",248:"FUNC_ARITY0",249:"FUNC_ARITY1",250:"FUNC_ARITY2",251:",",252:"IF",254:"BOUND",255:"BNODE",257:"EXISTS",258:"COUNT",261:"FUNC_AGGREGATE",263:"GROUP_CONCAT",267:"SEPARATOR",268:"=",270:"LANGTAG",271:"^^",272:"DECIMAL",273:"DOUBLE",274:"true",275:"false",276:"STRING_LITERAL1",277:"STRING_LITERAL2",278:"STRING_LITERAL_LONG1",279:"STRING_LITERAL_LONG2",280:"INTEGER_POSITIVE",281:"DECIMAL_POSITIVE",282:"DOUBLE_POSITIVE",283:"INTEGER_NEGATIVE",284:"DECIMAL_NEGATIVE",285:"DOUBLE_NEGATIVE",286:"PNAME_LN",290:"DISTINCT",291:"REDUCED",293:"*",296:"NAMED",297:"SILENT",298:"CLEAR",299:"DROP",300:"ADD",301:"MOVE",302:"COPY",303:"ALL",304:".",305:"UNION",306:"|",307:"/",309:"?",310:"+",311:"!=",312:"<",313:">",314:"<=",315:">=",316:"NOT",317:"CONCAT",318:"COALESCE",319:"SUBSTR",320:"REGEX",321:"REPLACE"}, -productions_: [0,[3,3],[4,1],[8,2],[11,2],[14,3],[17,4],[22,4],[18,3],[27,1],[27,5],[33,5],[33,7],[42,5],[47,4],[50,3],[20,2],[21,4],[60,3],[64,1],[64,1],[64,3],[64,5],[64,1],[67,2],[70,3],[73,2],[73,2],[73,1],[73,1],[78,2],[78,2],[78,4],[78,4],[82,2],[84,4],[84,4],[84,6],[90,1],[90,1],[90,1],[93,3],[95,3],[97,4],[97,3],[97,5],[97,4],[97,2],[97,2],[97,2],[97,6],[97,6],[121,2],[117,2],[126,3],[129,2],[131,3],[107,1],[107,2],[104,2],[104,1],[113,4],[138,7],[143,3],[55,3],[55,3],[147,2],[150,3],[154,3],[151,2],[151,2],[151,2],[151,3],[151,4],[151,2],[151,6],[151,1],[77,1],[77,1],[77,1],[66,2],[66,6],[169,1],[169,4],[35,3],[172,3],[145,2],[145,2],[178,1],[176,2],[182,2],[180,2],[185,1],[185,1],[185,1],[186,2],[156,2],[156,2],[190,4],[197,1],[197,3],[199,2],[201,2],[204,2],[203,2],[205,1],[205,1],[205,2],[205,3],[209,1],[209,1],[209,4],[210,1],[210,1],[210,2],[210,2],[177,3],[177,3],[191,3],[191,3],[189,1],[189,1],[195,1],[195,1],[175,1],[175,1],[175,1],[175,1],[175,1],[175,1],[30,2],[222,2],[220,2],[226,2],[224,1],[224,3],[224,4],[228,2],[234,2],[234,2],[234,2],[232,2],[242,2],[240,2],[240,2],[240,2],[245,1],[245,1],[245,1],[245,1],[245,1],[245,1],[75,3],[65,1],[65,2],[65,4],[65,6],[65,8],[65,2],[65,4],[65,2],[65,4],[65,3],[247,5],[247,5],[247,6],[266,4],[91,1],[91,2],[91,3],[91,1],[91,1],[91,1],[91,1],[91,1],[91,1],[91,1],[269,1],[269,1],[269,1],[269,1],[236,1],[236,1],[236,1],[238,1],[238,1],[238,1],[53,1],[53,1],[53,1],[287,0],[287,1],[5,1],[5,1],[288,1],[288,1],[7,0],[7,2],[9,1],[9,1],[9,1],[9,1],[10,0],[10,1],[19,0],[19,2],[23,0],[23,1],[289,1],[289,1],[25,0],[25,1],[292,1],[292,2],[26,1],[26,1],[36,0],[36,2],[37,0],[37,2],[40,0],[40,1],[294,1],[294,1],[295,1],[295,2],[44,1],[44,1],[45,0],[45,2],[46,0],[46,1],[49,0],[49,2],[52,0],[52,1],[54,0],[54,1],[56,0],[56,1],[57,0],[57,1],[58,0],[58,1],[59,0],[59,1],[63,1],[63,2],[69,1],[69,2],[72,1],[72,2],[85,0],[85,2],[87,0],[87,2],[88,1],[88,2],[89,0],[89,2],[94,1],[94,2],[96,0],[96,4],[98,0],[98,2],[100,0],[100,1],[101,0],[101,1],[102,1],[102,1],[103,0],[103,1],[105,1],[105,1],[105,1],[106,0],[106,1],[110,0],[110,1],[116,0],[116,1],[118,0],[118,1],[119,0],[119,2],[120,0],[120,1],[122,0],[122,1],[123,0],[123,2],[128,0],[128,1],[134,0],[134,1],[135,1],[135,1],[135,1],[136,0],[136,1],[137,0],[137,2],[139,1],[139,1],[140,0],[140,1],[141,0],[141,1],[142,0],[142,1],[144,0],[144,3],[146,0],[146,1],[148,0],[148,1],[149,0],[149,2],[152,0],[152,1],[153,0],[153,1],[155,0],[155,3],[157,0],[157,1],[158,0],[158,3],[161,1],[161,1],[163,0],[163,1],[164,1],[164,1],[167,0],[167,1],[168,0],[168,3],[170,0],[170,3],[171,0],[171,1],[173,0],[173,3],[174,0],[174,1],[179,0],[179,1],[181,0],[181,2],[184,0],[184,1],[188,0],[188,3],[192,0],[192,1],[193,1],[193,1],[194,0],[194,3],[196,0],[196,2],[198,1],[198,1],[200,0],[200,3],[202,0],[202,3],[308,1],[308,1],[308,1],[206,0],[206,1],[207,0],[207,1],[211,0],[211,3],[212,0],[212,1],[214,1],[214,2],[217,1],[217,2],[221,0],[221,2],[225,0],[225,2],[229,1],[229,1],[229,1],[229,1],[229,1],[229,1],[230,0],[230,1],[233,0],[233,2],[235,1],[235,1],[237,0],[237,2],[239,0],[239,2],[241,0],[241,2],[243,1],[243,1],[244,0],[244,1],[253,1],[253,1],[253,1],[253,1],[253,1],[256,0],[256,1],[259,0],[259,1],[260,1],[260,1],[262,0],[262,1],[264,0],[264,1],[265,0],[265,1]], -performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { -/* this == yyval */ - -var $0 = $$.length - 1; -switch (yystate) { -case 1: - - $$[$0-1] = $$[$0-1] || {}; - if (Parser.base) - $$[$0-1].base = Parser.base; - Parser.base = base = basePath = baseRoot = ''; - $$[$0-1].prefixes = Parser.prefixes; - Parser.prefixes = null; - return $$[$0-1]; - -break; -case 3: -this.$ = extend($$[$0-1], $$[$0], { type: 'query' }); -break; -case 4: - - Parser.base = resolveIRI($$[$0]) - base = basePath = baseRoot = ''; - -break; -case 5: - - if (!Parser.prefixes) Parser.prefixes = {}; - $$[$0-1] = $$[$0-1].substr(0, $$[$0-1].length - 1); - $$[$0] = resolveIRI($$[$0]); - Parser.prefixes[$$[$0-1]] = $$[$0]; - -break; -case 6: -this.$ = extend($$[$0-3], groupDatasets($$[$0-2]), $$[$0-1], $$[$0]); -break; -case 7: -this.$ = extend($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], { type: 'query' }); -break; -case 8: -this.$ = extend({ queryType: 'SELECT', variables: $$[$0] === '*' ? ['*'] : $$[$0] }, $$[$0-1] && ($$[$0-2] = lowercase($$[$0-1]), $$[$0-1] = {}, $$[$0-1][$$[$0-2]] = true, $$[$0-1])); -break; -case 9: case 92: case 124: case 151: -this.$ = toVar($$[$0]); -break; -case 10: case 22: -this.$ = expression($$[$0-3], { variable: toVar($$[$0-1]) }); -break; -case 11: -this.$ = extend({ queryType: 'CONSTRUCT', template: $$[$0-3] }, groupDatasets($$[$0-2]), $$[$0-1], $$[$0]); -break; -case 12: -this.$ = extend({ queryType: 'CONSTRUCT', template: $$[$0-2] = ($$[$0-2] ? $$[$0-2].triples : []) }, groupDatasets($$[$0-5]), { where: [ { type: 'bgp', triples: appendAllTo([], $$[$0-2]) } ] }, $$[$0]); -break; -case 13: -this.$ = extend({ queryType: 'DESCRIBE', variables: $$[$0-3] === '*' ? ['*'] : $$[$0-3].map(toVar) }, groupDatasets($$[$0-2]), $$[$0-1], $$[$0]); -break; -case 14: -this.$ = extend({ queryType: 'ASK' }, groupDatasets($$[$0-2]), $$[$0-1], $$[$0]); -break; -case 15: case 54: -this.$ = { iri: $$[$0], named: !!$$[$0-1] }; -break; -case 16: -this.$ = { where: $$[$0].patterns }; -break; -case 17: -this.$ = extend($$[$0-3], $$[$0-2], $$[$0-1], $$[$0]); -break; -case 18: -this.$ = { group: $$[$0] }; -break; -case 19: case 20: case 26: case 28: -this.$ = expression($$[$0]); -break; -case 21: -this.$ = expression($$[$0-1]); -break; -case 23: case 29: -this.$ = expression(toVar($$[$0])); -break; -case 24: -this.$ = { having: $$[$0] }; -break; -case 25: -this.$ = { order: $$[$0] }; -break; -case 27: -this.$ = expression($$[$0], { descending: true }); -break; -case 30: -this.$ = { limit: toInt($$[$0]) }; -break; -case 31: -this.$ = { offset: toInt($$[$0]) }; -break; -case 32: -this.$ = { limit: toInt($$[$0-2]), offset: toInt($$[$0]) }; -break; -case 33: -this.$ = { limit: toInt($$[$0]), offset: toInt($$[$0-2]) }; -break; -case 34: -this.$ = { type: 'values', values: $$[$0] }; -break; -case 35: - - $$[$0-3] = toVar($$[$0-3]); - this.$ = $$[$0-1].map(function(v) { var o = {}; o[$$[$0-3]] = v; return o; }) - -break; -case 36: - - this.$ = $$[$0-1].map(function() { return {}; }) - -break; -case 37: - - var length = $$[$0-4].length; - $$[$0-4] = $$[$0-4].map(toVar); - this.$ = $$[$0-1].map(function (values) { - if (values.length !== length) - throw Error('Inconsistent VALUES length'); - var valuesObject = {}; - for(var i = 0; i TERROR) { - expected.push('\'' + this.terminals_[p] + '\''); - } - } - if (lexer.showPosition) { - errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; - } else { - errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); - } - this.parseError(errStr, { - text: lexer.match, - token: this.terminals_[symbol] || symbol, - line: lexer.yylineno, - loc: yyloc, - expected: expected - }); - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(lexer.yytext); - lstack.push(lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = lexer.yyleng; - yytext = lexer.yytext; - yylineno = lexer.yylineno; - yyloc = lexer.yylloc; - if (recovering > 0) { - recovering--; - } - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { - first_line: lstack[lstack.length - (len || 1)].first_line, - last_line: lstack[lstack.length - 1].last_line, - first_column: lstack[lstack.length - (len || 1)].first_column, - last_column: lstack[lstack.length - 1].last_column - }; - if (ranges) { - yyval._$.range = [ - lstack[lstack.length - (len || 1)].range[0], - lstack[lstack.length - 1].range[1] - ]; - } - r = this.performAction.apply(yyval, [ - yytext, - yyleng, - yylineno, - sharedState.yy, - action[1], - vstack, - lstack - ].concat(args)); - if (typeof r !== 'undefined') { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; -}}; - - /* - SPARQL parser in the Jison parser generator format. - */ - - // Common namespaces and entities - var RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_TYPE = RDF + 'type', - RDF_FIRST = RDF + 'first', - RDF_REST = RDF + 'rest', - RDF_NIL = RDF + 'nil', - XSD = 'http://www.w3.org/2001/XMLSchema#', - XSD_INTEGER = XSD + 'integer', - XSD_DECIMAL = XSD + 'decimal', - XSD_DOUBLE = XSD + 'double', - XSD_BOOLEAN = XSD + 'boolean', - XSD_TRUE = '"true"^^' + XSD_BOOLEAN, - XSD_FALSE = '"false"^^' + XSD_BOOLEAN; - - var base = '', basePath = '', baseRoot = ''; - - // Returns a lowercase version of the given string - function lowercase(string) { - return string.toLowerCase(); - } - - // Appends the item to the array and returns the array - function appendTo(array, item) { - return array.push(item), array; - } - - // Appends the items to the array and returns the array - function appendAllTo(array, items) { - return array.push.apply(array, items), array; - } - - // Extends a base object with properties of other objects - function extend(base) { - if (!base) base = {}; - for (var i = 1, l = arguments.length, arg; i < l && (arg = arguments[i] || {}); i++) - for (var name in arg) - base[name] = arg[name]; - return base; - } - - // Creates an array that contains all items of the given arrays - function unionAll() { - var union = []; - for (var i = 0, l = arguments.length; i < l; i++) - union = union.concat.apply(union, arguments[i]); - return union; - } - - // Resolves an IRI against a base path - function resolveIRI(iri) { - // Strip off possible angular brackets - if (iri[0] === '<') - iri = iri.substring(1, iri.length - 1); - // Return absolute IRIs unmodified - if (/^[a-z]+:/.test(iri)) - return iri; - if (!Parser.base) - throw new Error('Cannot resolve relative IRI ' + iri + ' because no base IRI was set.'); - if (!base) { - base = Parser.base; - basePath = base.replace(/[^\/:]*$/, ''); - baseRoot = base.match(/^(?:[a-z]+:\/*)?[^\/]*/)[0]; - } - switch (iri[0]) { - // An empty relative IRI indicates the base IRI - case undefined: - return base; - // Resolve relative fragment IRIs against the base IRI - case '#': - return base + iri; - // Resolve relative query string IRIs by replacing the query string - case '?': - return base.replace(/(?:\?.*)?$/, iri); - // Resolve root relative IRIs at the root of the base IRI - case '/': - return baseRoot + iri; - // Resolve all other IRIs at the base IRI's path - default: - return basePath + iri; - } - } - - // If the item is a variable, ensures it starts with a question mark - function toVar(variable) { - if (variable) { - var first = variable[0]; - if (first === '?') return variable; - if (first === '$') return '?' + variable.substr(1); - } - return variable; - } - - // Creates an operation with the given name and arguments - function operation(operatorName, args) { - return { type: 'operation', operator: operatorName, args: args || [] }; - } - - // Creates an expression with the given type and attributes - function expression(expr, attr) { - var expression = { expression: expr }; - if (attr) - for (var a in attr) - expression[a] = attr[a]; - return expression; - } - - // Creates a path with the given type and items - function path(type, items) { - return { type: 'path', pathType: type, items: items }; - } - - // Transforms a list of operations types and arguments into a tree of operations - function createOperationTree(initialExpression, operationList) { - for (var i = 0, l = operationList.length, item; i < l && (item = operationList[i]); i++) - initialExpression = operation(item[0], [initialExpression, item[1]]); - return initialExpression; - } - - // Group datasets by default and named - function groupDatasets(fromClauses) { - var defaults = [], named = [], l = fromClauses.length, fromClause; - for (var i = 0; i < l && (fromClause = fromClauses[i]); i++) - (fromClause.named ? named : defaults).push(fromClause.iri); - return l ? { from: { default: defaults, named: named } } : null; - } - - // Converts the number to a string - function toInt(string) { - return parseInt(string, 10); - } - - // Transforms a possibly single group into its patterns - function degroupSingle(group) { - return group.type === 'group' && group.patterns.length === 1 ? group.patterns[0] : group; - } - - // Creates a literal with the given value and type - function createLiteral(value, type) { - return '"' + value + '"^^' + type; - } - - // Creates a triple with the given subject, predicate, and object - function triple(subject, predicate, object) { - var triple = {}; - if (subject != null) triple.subject = subject; - if (predicate != null) triple.predicate = predicate; - if (object != null) triple.object = object; - return triple; - } - - // Creates a new blank node identifier - function blank() { - return '_:b' + blankId++; - }; - var blankId = 0; - Parser._resetBlanks = function () { blankId = 0; } - - // Regular expression and replacement strings to escape strings - var escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\(.)/g, - escapeReplacements = { '\\': '\\', "'": "'", '"': '"', - 't': '\t', 'b': '\b', 'n': '\n', 'r': '\r', 'f': '\f' }, - fromCharCode = String.fromCharCode; - - // Translates escape codes in the string into their textual equivalent - function unescapeString(string, trimLength) { - string = string.substring(trimLength, string.length - trimLength); - try { - string = string.replace(escapeSequence, function (sequence, unicode4, unicode8, escapedChar) { - var charCode; - if (unicode4) { - charCode = parseInt(unicode4, 16); - if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance - return fromCharCode(charCode); - } - else if (unicode8) { - charCode = parseInt(unicode8, 16); - if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance - if (charCode < 0xFFFF) return fromCharCode(charCode); - return fromCharCode(0xD800 + ((charCode -= 0x10000) >> 10), 0xDC00 + (charCode & 0x3FF)); - } - else { - var replacement = escapeReplacements[escapedChar]; - if (!replacement) throw new Error(); - return replacement; - } - }); - } - catch (error) { return ''; } - return '"' + string + '"'; - } - - // Creates a list, collecting its (possibly blank) items and triples associated with those items - function createList(objects) { - var list = blank(), head = list, listItems = [], listTriples, triples = []; - objects.forEach(function (o) { listItems.push(o.entity); appendAllTo(triples, o.triples); }); - - // Build an RDF list out of the items - for (var i = 0, j = 0, l = listItems.length, listTriples = Array(l * 2); i < l;) - listTriples[j++] = triple(head, RDF_FIRST, listItems[i]), - listTriples[j++] = triple(head, RDF_REST, head = ++i < l ? blank() : RDF_NIL); - - // Return the list's identifier, its triples, and the triples associated with its items - return { entity: list, triples: appendAllTo(listTriples, triples) }; - } - - // Creates a blank node identifier, collecting triples with that blank node as subject - function createAnonymousObject(propertyList) { - var entity = blank(); - return { - entity: entity, - triples: propertyList.map(function (t) { return extend(triple(entity), t); }) - }; - } - - // Collects all (possibly blank) objects, and triples that have them as subject - function objectListToTriples(predicate, objectList, otherTriples) { - var objects = [], triples = []; - objectList.forEach(function (l) { - objects.push(triple(null, predicate, l.entity)); - appendAllTo(triples, l.triples); - }); - return unionAll(objects, otherTriples || [], triples); - } - - // Simplifies groups by merging adjacent BGPs - function mergeAdjacentBGPs(groups) { - var merged = [], currentBgp; - for (var i = 0, group; group = groups[i]; i++) { - switch (group.type) { - // Add a BGP's triples to the current BGP - case 'bgp': - if (group.triples.length) { - if (!currentBgp) - appendTo(merged, currentBgp = group); - else - appendAllTo(currentBgp.triples, group.triples); - } - break; - // All other groups break up a BGP - default: - // Only add the group if its pattern is non-empty - if (!group.patterns || group.patterns.length > 0) { - appendTo(merged, group); - currentBgp = null; - } - } - } - return merged; - } -/* generated by jison-lex 0.3.4 */ -var lexer = (function(){ -var lexer = ({ - -EOF:1, - -parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - -// resets the lexer, sets new input -setInput:function (input, yy) { - this.yy = yy || this.yy || {}; - this._input = input; - this._more = this._backtrack = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { - first_line: 1, - first_column: 0, - last_line: 1, - last_column: 0 - }; - if (this.options.ranges) { - this.yylloc.range = [0,0]; - } - this.offset = 0; - return this; - }, - -// consumes and returns one char from the input -input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) { - this.yylloc.range[1]++; - } - - this._input = this._input.slice(1); - return ch; - }, - -// unshifts one char (or a string) into the input -unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); - - if (lines.length - 1) { - this.yylineno -= lines.length - 1; - } - var r = this.yylloc.range; - - this.yylloc = { - first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) - + oldLines[oldLines.length - lines.length].length - lines[0].length : - this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - this.yyleng = this.yytext.length; - return this; - }, - -// When called from action, caches matched text and appends it on next action -more:function () { - this._more = true; - return this; - }, - -// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. -reject:function () { - if (this.options.backtrack_lexer) { - this._backtrack = true; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - - } - return this; - }, - -// retain first n characters of the match -less:function (n) { - this.unput(this.match.slice(n)); - }, - -// displays already matched input, i.e. for error messages -pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, - -// displays upcoming input, i.e. for error messages -upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, - -// displays the character position where the lexing error occurred, i.e. for error messages -showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, - -// test the lexed token: return FALSE when not a match, otherwise return token -test_match:function(match, indexed_rule) { - var token, - lines, - backup; - - if (this.options.backtrack_lexer) { - // save context - backup = { - yylineno: this.yylineno, - yylloc: { - first_line: this.yylloc.first_line, - last_line: this.last_line, - first_column: this.yylloc.first_column, - last_column: this.yylloc.last_column - }, - yytext: this.yytext, - match: this.match, - matches: this.matches, - matched: this.matched, - yyleng: this.yyleng, - offset: this.offset, - _more: this._more, - _input: this._input, - yy: this.yy, - conditionStack: this.conditionStack.slice(0), - done: this.done - }; - if (this.options.ranges) { - backup.yylloc.range = this.yylloc.range.slice(0); - } - } - - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno += lines.length; - } - this.yylloc = { - first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? - lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : - this.yylloc.last_column + match[0].length - }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._backtrack = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) { - this.done = false; - } - if (token) { - return token; - } else if (this._backtrack) { - // recover context - for (var k in backup) { - this[k] = backup[k]; - } - return false; // rule action called reject() implying the next rule should be tested instead. - } - return false; - }, - -// return next match in input -next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) { - this.done = true; - } - - var token, - match, - tempMatch, - index; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (this.options.backtrack_lexer) { - token = this.test_match(tempMatch, rules[i]); - if (token !== false) { - return token; - } else if (this._backtrack) { - match = false; - continue; // rule action called reject() implying a rule MISmatch. - } else { - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - } else if (!this.options.flex) { - break; - } - } - } - if (match) { - token = this.test_match(match, rules[index]); - if (token !== false) { - return token; - } - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - } - }, - -// return next match that has a token -lex:function lex () { - var r = this.next(); - if (r) { - return r; - } else { - return this.lex(); - } - }, - -// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) -begin:function begin (condition) { - this.conditionStack.push(condition); - }, - -// pop the previously active lexer condition state off the condition stack -popState:function popState () { - var n = this.conditionStack.length - 1; - if (n > 0) { - return this.conditionStack.pop(); - } else { - return this.conditionStack[0]; - } - }, - -// produce the lexer rule set which is active for the currently active lexer condition state -_currentRules:function _currentRules () { - if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - } else { - return this.conditions["INITIAL"].rules; - } - }, - -// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available -topState:function topState (n) { - n = this.conditionStack.length - 1 - Math.abs(n || 0); - if (n >= 0) { - return this.conditionStack[n]; - } else { - return "INITIAL"; - } - }, - -// alias for begin(condition) -pushState:function pushState (condition) { - this.begin(condition); - }, - -// return the number of states currently on the stack -stateStackSize:function stateStackSize() { - return this.conditionStack.length; - }, -options: {"flex":true,"case-insensitive":true}, -performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { -var YYSTATE=YY_START; -switch($avoiding_name_collisions) { -case 0:/* ignore */ -break; -case 1:return 12 -break; -case 2:return 15 -break; -case 3:return 24 -break; -case 4:return 290 -break; -case 5:return 291 -break; -case 6:return 29 -break; -case 7:return 31 -break; -case 8:return 32 -break; -case 9:return 293 -break; -case 10:return 34 -break; -case 11:return 38 -break; -case 12:return 39 -break; -case 13:return 41 -break; -case 14:return 43 -break; -case 15:return 48 -break; -case 16:return 51 -break; -case 17:return 296 -break; -case 18:return 61 -break; -case 19:return 62 -break; -case 20:return 68 -break; -case 21:return 71 -break; -case 22:return 74 -break; -case 23:return 76 -break; -case 24:return 79 -break; -case 25:return 81 -break; -case 26:return 83 -break; -case 27:return 183 -break; -case 28:return 99 -break; -case 29:return 297 -break; -case 30:return 132 -break; -case 31:return 298 -break; -case 32:return 299 -break; -case 33:return 109 -break; -case 34:return 300 -break; -case 35:return 108 -break; -case 36:return 301 -break; -case 37:return 302 -break; -case 38:return 112 -break; -case 39:return 114 -break; -case 40:return 115 -break; -case 41:return 130 -break; -case 42:return 124 -break; -case 43:return 125 -break; -case 44:return 127 -break; -case 45:return 133 -break; -case 46:return 111 -break; -case 47:return 303 -break; -case 48:return 304 -break; -case 49:return 159 -break; -case 50:return 162 -break; -case 51:return 166 -break; -case 52:return 92 -break; -case 53:return 160 -break; -case 54:return 305 -break; -case 55:return 165 -break; -case 56:return 251 -break; -case 57:return 187 -break; -case 58:return 306 -break; -case 59:return 307 -break; -case 60:return 213 -break; -case 61:return 309 -break; -case 62:return 310 -break; -case 63:return 208 -break; -case 64:return 215 -break; -case 65:return 216 -break; -case 66:return 223 -break; -case 67:return 227 -break; -case 68:return 268 -break; -case 69:return 311 -break; -case 70:return 312 -break; -case 71:return 313 -break; -case 72:return 314 -break; -case 73:return 315 -break; -case 74:return 231 -break; -case 75:return 316 -break; -case 76:return 246 -break; -case 77:return 254 -break; -case 78:return 255 -break; -case 79:return 248 -break; -case 80:return 249 -break; -case 81:return 250 -break; -case 82:return 317 -break; -case 83:return 318 -break; -case 84:return 252 -break; -case 85:return 320 -break; -case 86:return 319 -break; -case 87:return 321 -break; -case 88:return 257 -break; -case 89:return 258 -break; -case 90:return 261 -break; -case 91:return 263 -break; -case 92:return 267 -break; -case 93:return 271 -break; -case 94:return 274 -break; -case 95:return 275 -break; -case 96:return 13 -break; -case 97:return 16 -break; -case 98:return 286 -break; -case 99:return 218 -break; -case 100:return 28 -break; -case 101:return 270 -break; -case 102:return 80 -break; -case 103:return 272 -break; -case 104:return 273 -break; -case 105:return 280 -break; -case 106:return 281 -break; -case 107:return 282 -break; -case 108:return 283 -break; -case 109:return 284 -break; -case 110:return 285 -break; -case 111:return 'EXPONENT' -break; -case 112:return 276 -break; -case 113:return 277 -break; -case 114:return 278 -break; -case 115:return 279 -break; -case 116:return 86 -break; -case 117:return 219 -break; -case 118:return 6 -break; -case 119:return 'INVALID' -break; -case 120:console.log(yy_.yytext); -break; -} -}, -rules: [/^(?:\s+|#[^\n\r]*)/i,/^(?:BASE)/i,/^(?:PREFIX)/i,/^(?:SELECT)/i,/^(?:DISTINCT)/i,/^(?:REDUCED)/i,/^(?:\()/i,/^(?:AS)/i,/^(?:\))/i,/^(?:\*)/i,/^(?:CONSTRUCT)/i,/^(?:WHERE)/i,/^(?:\{)/i,/^(?:\})/i,/^(?:DESCRIBE)/i,/^(?:ASK)/i,/^(?:FROM)/i,/^(?:NAMED)/i,/^(?:GROUP)/i,/^(?:BY)/i,/^(?:HAVING)/i,/^(?:ORDER)/i,/^(?:ASC)/i,/^(?:DESC)/i,/^(?:LIMIT)/i,/^(?:OFFSET)/i,/^(?:VALUES)/i,/^(?:;)/i,/^(?:LOAD)/i,/^(?:SILENT)/i,/^(?:INTO)/i,/^(?:CLEAR)/i,/^(?:DROP)/i,/^(?:CREATE)/i,/^(?:ADD)/i,/^(?:TO)/i,/^(?:MOVE)/i,/^(?:COPY)/i,/^(?:INSERT\s+DATA)/i,/^(?:DELETE\s+DATA)/i,/^(?:DELETE\s+WHERE)/i,/^(?:WITH)/i,/^(?:DELETE)/i,/^(?:INSERT)/i,/^(?:USING)/i,/^(?:DEFAULT)/i,/^(?:GRAPH)/i,/^(?:ALL)/i,/^(?:\.)/i,/^(?:OPTIONAL)/i,/^(?:SERVICE)/i,/^(?:BIND)/i,/^(?:UNDEF)/i,/^(?:MINUS)/i,/^(?:UNION)/i,/^(?:FILTER)/i,/^(?:,)/i,/^(?:a)/i,/^(?:\|)/i,/^(?:\/)/i,/^(?:\^)/i,/^(?:\?)/i,/^(?:\+)/i,/^(?:!)/i,/^(?:\[)/i,/^(?:\])/i,/^(?:\|\|)/i,/^(?:&&)/i,/^(?:=)/i,/^(?:!=)/i,/^(?:<)/i,/^(?:>)/i,/^(?:<=)/i,/^(?:>=)/i,/^(?:IN)/i,/^(?:NOT)/i,/^(?:-)/i,/^(?:BOUND)/i,/^(?:BNODE)/i,/^(?:(RAND|NOW|UUID|STRUUID))/i,/^(?:(LANG|DATATYPE|IRI|URI|ABS|CEIL|FLOOR|ROUND|STRLEN|STR|UCASE|LCASE|ENCODE_FOR_URI|YEAR|MONTH|DAY|HOURS|MINUTES|SECONDS|TIMEZONE|TZ|MD5|SHA1|SHA256|SHA384|SHA512|isIRI|isURI|isBLANK|isLITERAL|isNUMERIC))/i,/^(?:(LANGMATCHES|CONTAINS|STRSTARTS|STRENDS|STRBEFORE|STRAFTER|STRLANG|STRDT|sameTerm))/i,/^(?:CONCAT)/i,/^(?:COALESCE)/i,/^(?:IF)/i,/^(?:REGEX)/i,/^(?:SUBSTR)/i,/^(?:REPLACE)/i,/^(?:EXISTS)/i,/^(?:COUNT)/i,/^(?:SUM|MIN|MAX|AVG|SAMPLE)/i,/^(?:GROUP_CONCAT)/i,/^(?:SEPARATOR)/i,/^(?:\^\^)/i,/^(?:true)/i,/^(?:false)/i,/^(?:(<([^<>\"\{\}\|\^`\\\u0000-\u0020])*>))/i,/^(?:((([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])(((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])|\.)*(((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]))?)?:))/i,/^(?:(((([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])(((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])|\.)*(((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]))?)?:)((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|:|[0-9]|((%([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f]))|(\\(_|~|\.|-|!|\$|&|'|\(|\)|\*|\+|,|;|=|\/|\?|#|@|%))))(((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])|\.|:|((%([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f]))|(\\(_|~|\.|-|!|\$|&|'|\(|\)|\*|\+|,|;|=|\/|\?|#|@|%))))*((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])|:|((%([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f]))|(\\(_|~|\.|-|!|\$|&|'|\(|\)|\*|\+|,|;|=|\/|\?|#|@|%)))))?)))/i,/^(?:(_:(((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|[0-9])(((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])|\.)*(((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|-|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]))?))/i,/^(?:([\?\$]((((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|[0-9])(((?:([A-Z]|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|[\uD800-\uDB7F][\uDC00-\uDFFF])|_))|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040])*)))/i,/^(?:(@[a-zA-Z]+(-[a-zA-Z0-9]+)*))/i,/^(?:([0-9]+))/i,/^(?:([0-9]*\.[0-9]+))/i,/^(?:([0-9]+\.[0-9]*([eE][+-]?[0-9]+)|\.([0-9])+([eE][+-]?[0-9]+)|([0-9])+([eE][+-]?[0-9]+)))/i,/^(?:(\+([0-9]+)))/i,/^(?:(\+([0-9]*\.[0-9]+)))/i,/^(?:(\+([0-9]+\.[0-9]*([eE][+-]?[0-9]+)|\.([0-9])+([eE][+-]?[0-9]+)|([0-9])+([eE][+-]?[0-9]+))))/i,/^(?:(-([0-9]+)))/i,/^(?:(-([0-9]*\.[0-9]+)))/i,/^(?:(-([0-9]+\.[0-9]*([eE][+-]?[0-9]+)|\.([0-9])+([eE][+-]?[0-9]+)|([0-9])+([eE][+-]?[0-9]+))))/i,/^(?:([eE][+-]?[0-9]+))/i,/^(?:('(([^\u0027\u005C\u000A\u000D])|(\\[tbnrf\\\"']|\\u([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])|\\U([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])))*'))/i,/^(?:("(([^\u0022\u005C\u000A\u000D])|(\\[tbnrf\\\"']|\\u([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])|\\U([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])))*"))/i,/^(?:('''(('|'')?([^'\\]|(\\[tbnrf\\\"']|\\u([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])|\\U([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f]))))*'''))/i,/^(?:("""(("|"")?([^\"\\]|(\\[tbnrf\\\"']|\\u([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])|\\U([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f])([0-9]|[A-F]|[a-f]))))*"""))/i,/^(?:(\((\u0020|\u0009|\u000D|\u000A)*\)))/i,/^(?:(\[(\u0020|\u0009|\u000D|\u000A)*\]))/i,/^(?:$)/i,/^(?:.)/i,/^(?:.)/i], -conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120],"inclusive":true}} -}); -return lexer; -})(); -parser.lexer = lexer; -function Parser () { - this.yy = {}; -} -Parser.prototype = parser;parser.Parser = Parser; -return new Parser; -})(); - - -if (true) { -exports.parser = SparqlParser; -exports.Parser = SparqlParser.Parser; -exports.parse = function () { return SparqlParser.parse.apply(SparqlParser, arguments); }; -exports.main = function commonjsMain (args) { - if (!args[1]) { - console.log('Usage: '+args[0]+' FILE'); - process.exit(1); - } - var source = __webpack_require__(/*! fs */ 0).readFileSync(__webpack_require__(/*! path */ 1).normalize(args[1]), "utf8"); - return exports.parser.parse(source); -}; -if ( true && __webpack_require__.c[__webpack_require__.s] === module) { - exports.main(process.argv.slice(1)); -} -} -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../process/browser.js */ "./node_modules/process/browser.js"), __webpack_require__(/*! ./../../webpack/buildin/module.js */ "./node_modules/webpack/buildin/module.js")(module))) - -/***/ }), - -/***/ "./node_modules/sparqljs/sparql.js": -/*!*****************************************!*\ - !*** ./node_modules/sparqljs/sparql.js ***! - \*****************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -var Parser = __webpack_require__(/*! ./lib/SparqlParser */ "./node_modules/sparqljs/lib/SparqlParser.js").Parser; -var Generator = __webpack_require__(/*! ./lib/SparqlGenerator */ "./node_modules/sparqljs/lib/SparqlGenerator.js"); - -module.exports = { - /** - * Creates a SPARQL parser with the given pre-defined prefixes and base IRI - * @param prefixes { [prefix: string]: string } - * @param baseIRI string - */ - Parser: function (prefixes, baseIRI) { - // Create a copy of the prefixes - var prefixesCopy = {}; - for (var prefix in prefixes || {}) - prefixesCopy[prefix] = prefixes[prefix]; - - // Create a new parser with the given prefixes - // (Workaround for https://github.com/zaach/jison/issues/241) - var parser = new Parser(); - parser.parse = function () { - Parser.base = baseIRI || ''; - Parser.prefixes = Object.create(prefixesCopy); - return Parser.prototype.parse.apply(parser, arguments); - }; - parser._resetBlanks = Parser._resetBlanks; - return parser; - }, - Generator: Generator, -}; - - -/***/ }), - -/***/ "./node_modules/webpack/buildin/module.js": -/*!***********************************!*\ - !*** (webpack)/buildin/module.js ***! - \***********************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if (!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if (!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), - -/***/ "./src/com/atomgraph/linkeddatahub/query/DescribeBuilder.ts": -/*!******************************************************************!*\ - !*** ./src/com/atomgraph/linkeddatahub/query/DescribeBuilder.ts ***! - \******************************************************************/ -/*! exports provided: DescribeBuilder */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DescribeBuilder", function() { return DescribeBuilder; }); -/* harmony import */ var sparqljs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sparqljs */ "./node_modules/sparqljs/sparql.js"); -/* harmony import */ var sparqljs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sparqljs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var _QueryBuilder__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./QueryBuilder */ "./src/com/atomgraph/linkeddatahub/query/QueryBuilder.ts"); - - -class DescribeBuilder extends _QueryBuilder__WEBPACK_IMPORTED_MODULE_1__["QueryBuilder"] { - constructor(describe) { - super(describe); - } - static fromString(queryString, prefixes, baseIRI) { - let query = new sparqljs__WEBPACK_IMPORTED_MODULE_0__["Parser"](prefixes, baseIRI).parse(queryString); - if (!query) - throw new Error("Only DESCIBE is supported"); - return new DescribeBuilder(query); - } - static fromQuery(query) { - return new DescribeBuilder(query); - } - static new() { - return new DescribeBuilder({ - "queryType": "DESCRIBE", - "variables": [ - "*" - ], - "type": "query", - "prefixes": {} - }); - } - variablesAll() { - this.getQuery().variables = ["*"]; - return this; - } - variables(variables) { - this.getQuery().variables = variables; - return this; - } - variable(term) { - this.getQuery().variables.push(term); - return this; - } - isVariable(term) { - return this.getQuery().variables.includes(term); - } - getQuery() { - return super.getQuery(); - } - build() { - return super.build(); - } -} - - -/***/ }), - -/***/ "./src/com/atomgraph/linkeddatahub/query/QueryBuilder.ts": -/*!***************************************************************!*\ - !*** ./src/com/atomgraph/linkeddatahub/query/QueryBuilder.ts ***! - \***************************************************************/ -/*! exports provided: QueryBuilder */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "QueryBuilder", function() { return QueryBuilder; }); -/* harmony import */ var sparqljs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sparqljs */ "./node_modules/sparqljs/sparql.js"); -/* harmony import */ var sparqljs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sparqljs__WEBPACK_IMPORTED_MODULE_0__); - -class QueryBuilder { - constructor(query) { - this.query = query; - this.generator = new sparqljs__WEBPACK_IMPORTED_MODULE_0__["Generator"](); - if (!this.query.prefixes) - this.query.prefixes = {}; - } - static fromQuery(query) { - return new QueryBuilder(query); - } - static fromString(queryString, prefixes, baseIRI) { - let query = new sparqljs__WEBPACK_IMPORTED_MODULE_0__["Parser"](prefixes, baseIRI).parse(queryString); - if (!query) - throw new Error("Only SPARQL queries are supported, not updates"); - return new QueryBuilder(query); - } - where(pattern) { - this.getQuery().where = pattern; - return this; - } - wherePattern(pattern) { - if (!this.getQuery().where) - this.where([]); - this.getQuery().where.push(pattern); - return this; - } - bgpTriples(triples) { - // if the last pattern is BGP, append triples to it instead of adding new BGP - if (this.getQuery().where) { - let lastPattern = this.getQuery().where[this.getQuery().where.length - 1]; - if (lastPattern.type === "bgp") { - lastPattern.triples = lastPattern.triples.concat(triples); - return this; - } - } - return this.wherePattern(QueryBuilder.bgp(triples)); - } - bgpTriple(triple) { - return this.bgpTriples([triple]); - } - getQuery() { - return this.query; - } - getGenerator() { - return this.generator; - } - build() { - return this.getQuery(); - } - toString() { - return this.getGenerator().stringify(this.getQuery()); - } - static term(value) { - return value; - } - static var(varName) { - return ("?" + varName); - } - static literal(value) { - return ("\"" + value + "\""); - } - static typedLiteral(value, datatype) { - return ("\"" + value + "\"^^" + datatype); - } - static uri(value) { - return value; - } - static triple(subject, predicate, object) { - return { - "subject": subject, - "predicate": predicate, - "object": object - }; - } - static bgp(triples) { - return { - "type": "bgp", - "triples": triples - }; - } - static graph(name, patterns) { - return { - "type": "graph", - "name": name, - "patterns": patterns - }; - } - static group(patterns) { - return { - "type": "group", - "patterns": patterns - }; - } - static union(patterns) { - return { - "type": "union", - "patterns": patterns - }; - } - static filter(expression) { - return { - "type": "filter", - "expression": expression - }; - } - static operation(operator, args) { - return { - "type": "operation", - "operator": operator, - "args": args - }; - } - static in(term, list) { - return QueryBuilder.operation("in", [term, list]); - } - static regex(term, pattern, caseInsensitive) { - let expression = { - "type": "operation", - "operator": "regex", - "args": [term, ("\"" + pattern + "\"")] - }; - if (caseInsensitive) - expression.args.push("\"i\""); - return expression; - } - static eq(arg1, arg2) { - return QueryBuilder.operation("=", [arg1, arg2]); - } - static str(arg) { - return QueryBuilder.operation("str", [arg]); - } -} - - -/***/ }), - -/***/ "./src/com/atomgraph/linkeddatahub/query/SPARQLBuilder.ts": -/*!****************************************************************!*\ - !*** ./src/com/atomgraph/linkeddatahub/query/SPARQLBuilder.ts ***! - \****************************************************************/ -/*! exports provided: QueryBuilder, SelectBuilder, DescribeBuilder */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _QueryBuilder__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./QueryBuilder */ "./src/com/atomgraph/linkeddatahub/query/QueryBuilder.ts"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "QueryBuilder", function() { return _QueryBuilder__WEBPACK_IMPORTED_MODULE_0__["QueryBuilder"]; }); - -/* harmony import */ var _SelectBuilder__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./SelectBuilder */ "./src/com/atomgraph/linkeddatahub/query/SelectBuilder.ts"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SelectBuilder", function() { return _SelectBuilder__WEBPACK_IMPORTED_MODULE_1__["SelectBuilder"]; }); - -/* harmony import */ var _DescribeBuilder__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./DescribeBuilder */ "./src/com/atomgraph/linkeddatahub/query/DescribeBuilder.ts"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DescribeBuilder", function() { return _DescribeBuilder__WEBPACK_IMPORTED_MODULE_2__["DescribeBuilder"]; }); - - - - - - -/***/ }), - -/***/ "./src/com/atomgraph/linkeddatahub/query/SelectBuilder.ts": -/*!****************************************************************!*\ - !*** ./src/com/atomgraph/linkeddatahub/query/SelectBuilder.ts ***! - \****************************************************************/ -/*! exports provided: SelectBuilder */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SelectBuilder", function() { return SelectBuilder; }); -/* harmony import */ var sparqljs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sparqljs */ "./node_modules/sparqljs/sparql.js"); -/* harmony import */ var sparqljs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sparqljs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var _QueryBuilder__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./QueryBuilder */ "./src/com/atomgraph/linkeddatahub/query/QueryBuilder.ts"); - - -class SelectBuilder extends _QueryBuilder__WEBPACK_IMPORTED_MODULE_1__["QueryBuilder"] { - constructor(select) { - super(select); - } - static fromString(queryString, prefixes, baseIRI) { - let query = new sparqljs__WEBPACK_IMPORTED_MODULE_0__["Parser"](prefixes, baseIRI).parse(queryString); - if (!query) - throw new Error("Only SELECT is supported"); - return new SelectBuilder(query); - } - static fromQuery(query) { - return new SelectBuilder(query); - } - variablesAll() { - this.getQuery().variables = ["*"]; - return this; - } - variables(variables) { - this.getQuery().variables = variables; - return this; - } - variable(term) { - this.getQuery().variables.push(term); - return this; - } - isVariable(term) { - return this.getQuery().variables.includes(term); - } - orderBy(ordering) { - if (!this.getQuery().order) - this.getQuery().order = []; - this.getQuery().order.push(ordering); - return this; - } - offset(offset) { - this.getQuery().offset = offset; - return this; - } - limit(limit) { - this.getQuery().limit = limit; - return this; - } - getQuery() { - return super.getQuery(); - } - build() { - return super.build(); - } - static ordering(expr, desc) { - let ordering = { - "expression": expr, - }; - if (desc !== undefined && desc == true) - ordering.descending = desc; - return ordering; - } -} - - -/***/ }), - -/***/ 0: -/*!********************!*\ - !*** fs (ignored) ***! - \********************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -/* (ignored) */ - -/***/ }), - -/***/ 1: -/*!**********************!*\ - !*** path (ignored) ***! - \**********************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -/* (ignored) */ - -/***/ }) - -/******/ }); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9TUEFSUUxCdWlsZGVyL3dlYnBhY2svYm9vdHN0cmFwIiwid2VicGFjazovL1NQQVJRTEJ1aWxkZXIvLi9ub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzIiwid2VicGFjazovL1NQQVJRTEJ1aWxkZXIvLi9ub2RlX21vZHVsZXMvc3BhcnFsanMvbGliL1NwYXJxbEdlbmVyYXRvci5qcyIsIndlYnBhY2s6Ly9TUEFSUUxCdWlsZGVyLy4vbm9kZV9tb2R1bGVzL3NwYXJxbGpzL2xpYi9TcGFycWxQYXJzZXIuanMiLCJ3ZWJwYWNrOi8vU1BBUlFMQnVpbGRlci8uL25vZGVfbW9kdWxlcy9zcGFycWxqcy9zcGFycWwuanMiLCJ3ZWJwYWNrOi8vU1BBUlFMQnVpbGRlci8od2VicGFjaykvYnVpbGRpbi9tb2R1bGUuanMiLCJ3ZWJwYWNrOi8vU1BBUlFMQnVpbGRlci8uL3NyYy9jb20vYXRvbWdyYXBoL2xpbmtlZGRhdGFodWIvcXVlcnkvRGVzY3JpYmVCdWlsZGVyLnRzIiwid2VicGFjazovL1NQQVJRTEJ1aWxkZXIvLi9zcmMvY29tL2F0b21ncmFwaC9saW5rZWRkYXRhaHViL3F1ZXJ5L1F1ZXJ5QnVpbGRlci50cyIsIndlYnBhY2s6Ly9TUEFSUUxCdWlsZGVyLy4vc3JjL2NvbS9hdG9tZ3JhcGgvbGlua2VkZGF0YWh1Yi9xdWVyeS9TUEFSUUxCdWlsZGVyLnRzIiwid2VicGFjazovL1NQQVJRTEJ1aWxkZXIvLi9zcmMvY29tL2F0b21ncmFwaC9saW5rZWRkYXRhaHViL3F1ZXJ5L1NlbGVjdEJ1aWxkZXIudHMiLCJ3ZWJwYWNrOi8vU1BBUlFMQnVpbGRlci9mcyAoaWdub3JlZCkiLCJ3ZWJwYWNrOi8vU1BBUlFMQnVpbGRlci9wYXRoIChpZ25vcmVkKSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFF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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0RBQStEO0FBQy9EO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsOENBQThDLG1DQUFtQyxFQUFFO0FBQ25GO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5QyxPQUFPO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7O0FBRUE7QUFDQTtBQUNBLHNCQUFzQjtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7O0FBRUE7QUFDQTtBQUNBLG1EQUFtRCxvQ0FBb0M7QUFDdkY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQix3Q0FBd0M7QUFDM0Q7QUFDQSxnQkFBZ0IsUUFBUSxrQ0FBa0MsRUFBRTtBQUM1RDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQ0FBcUMsYUFBYTs7QUFFbEQ7QUFDQSx3Q0FBd0MsRUFBRSxrQkFBa0IsRUFBRTtBQUM5RCw0QkFBNEI7QUFDNUIsb0ZBQW9GO0FBQ3BGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQ7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQ7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLG1CQUFtQixXQUFXO0FBQzlCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLDBCQUEwQixpQ0FBaUMsRUFBRTs7QUFFL0Y7QUFDQSw0RUFBNEUsT0FBTztBQUNuRjtBQUNBOztBQUVBO0FBQ0EsWUFBWTtBQUNaOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsa0NBQWtDLEVBQUU7QUFDbEY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsbUJBQW1CO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLGtCQUFrQjtBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0EsaUNBQWlDO0FBQ2pDLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLEtBQUs7O0FBRUwscURBQXFEO0FBQ3JEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLFVBQVUsb0NBQW9DO0FBQzlDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FB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SUFFTSxLQUFLLENBQUMsS0FBYTtRQUV0QixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUU5QixPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBRVMsUUFBUTtRQUVkLE9BQW9CLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRU0sS0FBSztRQUVSLE9BQW9CLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN0QyxDQUFDO0lBRU0sTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFnQixFQUFFLElBQWM7UUFFbkQsSUFBSSxRQUFRLEdBQWE7WUFDdkIsWUFBWSxFQUFFLElBQUk7U0FDbkIsQ0FBQztRQUVGLElBQUksSUFBSSxLQUFLLFNBQVMsSUFBSSxJQUFJLElBQUksSUFBSTtZQUFFLFFBQVEsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1FBRW5FLE9BQU8sUUFBUSxDQUFDO0lBQ3BCLENBQUM7Q0FFSjs7Ozs7Ozs7Ozs7O0FDN0ZELGU7Ozs7Ozs7Ozs7O0FDQUEsZSIsImZpbGUiOiJTUEFSUUxCdWlsZGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9zcmMvY29tL2F0b21ncmFwaC9saW5rZWRkYXRhaHViL3F1ZXJ5L1NQQVJRTEJ1aWxkZXIudHNcIik7XG4iLCIvLyBzaGltIGZvciB1c2luZyBwcm9jZXNzIGluIGJyb3dzZXJcbnZhciBwcm9jZXNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLy8gY2FjaGVkIGZyb20gd2hhdGV2ZXIgZ2xvYmFsIGlzIHByZXNlbnQgc28gdGhhdCB0ZXN0IHJ1bm5lcnMgdGhhdCBzdHViIGl0XG4vLyBkb24ndCBicmVhayB0aGluZ3MuICBCdXQgd2UgbmVlZCB0byB3cmFwIGl0IGluIGEgdHJ5IGNhdGNoIGluIGNhc2UgaXQgaXNcbi8vIHdyYXBwZWQgaW4gc3RyaWN0IG1vZGUgY29kZSB3aGljaCBkb2Vzbid0IGRlZmluZSBhbnkgZ2xvYmFscy4gIEl0J3MgaW5zaWRlIGFcbi8vIGZ1bmN0aW9uIGJlY2F1c2UgdHJ5L2NhdGNoZXMgZGVvcHRpbWl6ZSBpbiBjZXJ0YWluIGVuZ2luZXMuXG5cbnZhciBjYWNoZWRTZXRUaW1lb3V0O1xudmFyIGNhY2hlZENsZWFyVGltZW91dDtcblxuZnVuY3Rpb24gZGVmYXVsdFNldFRpbW91dCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NldFRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbmZ1bmN0aW9uIGRlZmF1bHRDbGVhclRpbWVvdXQgKCkge1xuICAgIHRocm93IG5ldyBFcnJvcignY2xlYXJUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJyk7XG59XG4oZnVuY3Rpb24gKCkge1xuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0VGltZW91dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IGRlZmF1bHRTZXRUaW1vdXQ7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2YgY2xlYXJUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBjbGVhclRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgIH1cbn0gKCkpXG5mdW5jdGlvbiBydW5UaW1lb3V0KGZ1bikge1xuICAgIGlmIChjYWNoZWRTZXRUaW1lb3V0ID09PSBzZXRUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICAvLyBpZiBzZXRUaW1lb3V0IHdhc24ndCBhdmFpbGFibGUgYnV0IHdhcyBsYXR0ZXIgZGVmaW5lZFxuICAgIGlmICgoY2FjaGVkU2V0VGltZW91dCA9PT0gZGVmYXVsdFNldFRpbW91dCB8fCAhY2FjaGVkU2V0VGltZW91dCkgJiYgc2V0VGltZW91dCkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gd2hlbiB3aGVuIHNvbWVib2R5IGhhcyBzY3Jld2VkIHdpdGggc2V0VGltZW91dCBidXQgbm8gSS5FLiBtYWRkbmVzc1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dChmdW4sIDApO1xuICAgIH0gY2F0Y2goZSl7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBXaGVuIHdlIGFyZSBpbiBJLkUuIGJ1dCB0aGUgc2NyaXB0IGhhcyBiZWVuIGV2YWxlZCBzbyBJLkUuIGRvZXNuJ3QgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwobnVsbCwgZnVuLCAwKTtcbiAgICAgICAgfSBjYXRjaChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yXG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dC5jYWxsKHRoaXMsIGZ1biwgMCk7XG4gICAgICAgIH1cbiAgICB9XG5cblxufVxuZnVuY3Rpb24gcnVuQ2xlYXJUaW1lb3V0KG1hcmtlcikge1xuICAgIGlmIChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGNsZWFyVGltZW91dCkge1xuICAgICAgICAvL25vcm1hbCBlbnZpcm9tZW50cyBpbiBzYW5lIHNpdHVhdGlvbnNcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICAvLyBpZiBjbGVhclRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGRlZmF1bHRDbGVhclRpbWVvdXQgfHwgIWNhY2hlZENsZWFyVGltZW91dCkgJiYgY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCAgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQuY2FsbChudWxsLCBtYXJrZXIpO1xuICAgICAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yLlxuICAgICAgICAgICAgLy8gU29tZSB2ZXJzaW9ucyBvZiBJLkUuIGhhdmUgZGlmZmVyZW50IHJ1bGVzIGZvciBjbGVhclRpbWVvdXQgdnMgc2V0VGltZW91dFxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKHRoaXMsIG1hcmtlcik7XG4gICAgICAgIH1cbiAgICB9XG5cblxuXG59XG52YXIgcXVldWUgPSBbXTtcbnZhciBkcmFpbmluZyA9IGZhbHNlO1xudmFyIGN1cnJlbnRRdWV1ZTtcbnZhciBxdWV1ZUluZGV4ID0gLTE7XG5cbmZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpIHtcbiAgICBpZiAoIWRyYWluaW5nIHx8ICFjdXJyZW50UXVldWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGlmIChjdXJyZW50UXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHF1ZXVlID0gY3VycmVudFF1ZXVlLmNvbmNhdChxdWV1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgIH1cbiAgICBpZiAocXVldWUubGVuZ3RoKSB7XG4gICAgICAgIGRyYWluUXVldWUoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRyYWluUXVldWUoKSB7XG4gICAgaWYgKGRyYWluaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHRpbWVvdXQgPSBydW5UaW1lb3V0KGNsZWFuVXBOZXh0VGljayk7XG4gICAgZHJhaW5pbmcgPSB0cnVlO1xuXG4gICAgdmFyIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB3aGlsZShsZW4pIHtcbiAgICAgICAgY3VycmVudFF1ZXVlID0gcXVldWU7XG4gICAgICAgIHF1ZXVlID0gW107XG4gICAgICAgIHdoaWxlICgrK3F1ZXVlSW5kZXggPCBsZW4pIHtcbiAgICAgICAgICAgIGlmIChjdXJyZW50UXVldWUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UXVldWVbcXVldWVJbmRleF0ucnVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgICAgICBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgfVxuICAgIGN1cnJlbnRRdWV1ZSA9IG51bGw7XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBydW5DbGVhclRpbWVvdXQodGltZW91dCk7XG59XG5cbnByb2Nlc3MubmV4dFRpY2sgPSBmdW5jdGlvbiAoZnVuKSB7XG4gICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCAtIDEpO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcXVldWUucHVzaChuZXcgSXRlbShmdW4sIGFyZ3MpKTtcbiAgICBpZiAocXVldWUubGVuZ3RoID09PSAxICYmICFkcmFpbmluZykge1xuICAgICAgICBydW5UaW1lb3V0KGRyYWluUXVldWUpO1xuICAgIH1cbn07XG5cbi8vIHY4IGxpa2VzIHByZWRpY3RpYmxlIG9iamVjdHNcbmZ1bmN0aW9uIEl0ZW0oZnVuLCBhcnJheSkge1xuICAgIHRoaXMuZnVuID0gZnVuO1xuICAgIHRoaXMuYXJyYXkgPSBhcnJheTtcbn1cbkl0ZW0ucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZ1bi5hcHBseShudWxsLCB0aGlzLmFycmF5KTtcbn07XG5wcm9jZXNzLnRpdGxlID0gJ2Jyb3dzZXInO1xucHJvY2Vzcy5icm93c2VyID0gdHJ1ZTtcbnByb2Nlc3MuZW52ID0ge307XG5wcm9jZXNzLmFyZ3YgPSBbXTtcbnByb2Nlc3MudmVyc2lvbiA9ICcnOyAvLyBlbXB0eSBzdHJpbmcgdG8gYXZvaWQgcmVnZXhwIGlzc3Vlc1xucHJvY2Vzcy52ZXJzaW9ucyA9IHt9O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxucHJvY2Vzcy5vbiA9IG5vb3A7XG5wcm9jZXNzLmFkZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3Mub25jZSA9IG5vb3A7XG5wcm9jZXNzLm9mZiA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUxpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlQWxsTGlzdGVuZXJzID0gbm9vcDtcbnByb2Nlc3MuZW1pdCA9IG5vb3A7XG5wcm9jZXNzLnByZXBlbmRMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLnByZXBlbmRPbmNlTGlzdGVuZXIgPSBub29wO1xuXG5wcm9jZXNzLmxpc3RlbmVycyA9IGZ1bmN0aW9uIChuYW1lKSB7IHJldHVybiBbXSB9XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcblxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5wcm9jZXNzLnVtYXNrID0gZnVuY3Rpb24oKSB7IHJldHVybiAwOyB9O1xuIiwidmFyIFhTRF9JTlRFR0VSID0gJ2h0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI2ludGVnZXInO1xuXG5mdW5jdGlvbiBHZW5lcmF0b3Iob3B0aW9ucywgcHJlZml4ZXMpIHtcbiAgdGhpcy5fb3B0aW9ucyA9IG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gIHByZWZpeGVzID0gcHJlZml4ZXMgfHwge307XG4gIHRoaXMuX3ByZWZpeEJ5SXJpID0ge307XG4gIHZhciBwcmVmaXhJcmlzID0gW107XG4gIGZvciAodmFyIHByZWZpeCBpbiBwcmVmaXhlcykge1xuICAgIHZhciBpcmkgPSBwcmVmaXhlc1twcmVmaXhdO1xuICAgIGlmIChpc1N0cmluZyhpcmkpKSB7XG4gICAgICB0aGlzLl9wcmVmaXhCeUlyaVtpcmldID0gcHJlZml4O1xuICAgICAgcHJlZml4SXJpcy5wdXNoKGlyaSk7XG4gICAgfVxuICB9XG4gIHZhciBpcmlMaXN0ID0gcHJlZml4SXJpcy5qb2luKCd8JykucmVwbGFjZSgvW1xcXVxcL1xcKFxcKVxcKlxcK1xcP1xcLlxcXFxcXCRdL2csICdcXFxcJCYnKTtcbiAgdGhpcy5fcHJlZml4UmVnZXggPSBuZXcgUmVnRXhwKCdeKCcgKyBpcmlMaXN0ICsgJykoW2EtekEtWl1bXFxcXC1fYS16QS1aMC05XSopJCcpO1xuICB0aGlzLl91c2VkUHJlZml4ZXMgPSB7fTtcbiAgdGhpcy5faW5kZW50ID0gIGlzU3RyaW5nKG9wdGlvbnMuaW5kZW50KSAgPyBvcHRpb25zLmluZGVudCAgOiAnICAnO1xuICB0aGlzLl9uZXdsaW5lID0gaXNTdHJpbmcob3B0aW9ucy5uZXdsaW5lKSA/IG9wdGlvbnMubmV3bGluZSA6ICdcXG4nO1xufVxuXG4vLyBDb252ZXJ0cyB0aGUgcGFyc2VkIHF1ZXJ5IG9iamVjdCBpbnRvIGEgU1BBUlFMIHF1ZXJ5XG5HZW5lcmF0b3IucHJvdG90eXBlLnRvUXVlcnkgPSBmdW5jdGlvbiAocSkge1xuICB2YXIgcXVlcnkgPSAnJztcblxuICBpZiAocS5xdWVyeVR5cGUpXG4gICAgcXVlcnkgKz0gcS5xdWVyeVR5cGUudG9VcHBlckNhc2UoKSArICcgJztcbiAgaWYgKHEucmVkdWNlZClcbiAgICBxdWVyeSArPSAnUkVEVUNFRCAnO1xuICBpZiAocS5kaXN0aW5jdClcbiAgICBxdWVyeSArPSAnRElTVElOQ1QgJztcblxuICBpZiAocS52YXJpYWJsZXMpXG4gICAgcXVlcnkgKz0gbWFwSm9pbihxLnZhcmlhYmxlcywgdW5kZWZpbmVkLCBmdW5jdGlvbiAodmFyaWFibGUpIHtcbiAgICAgIHJldHVybiBpc1N0cmluZyh2YXJpYWJsZSkgPyB0aGlzLnRvRW50aXR5KHZhcmlhYmxlKSA6XG4gICAgICAgICAgICAgJygnICsgdGhpcy50b0V4cHJlc3Npb24odmFyaWFibGUuZXhwcmVzc2lvbikgKyAnIEFTICcgKyB2YXJpYWJsZS52YXJpYWJsZSArICcpJztcbiAgICB9LCB0aGlzKSArICcgJztcbiAgZWxzZSBpZiAocS50ZW1wbGF0ZSlcbiAgICBxdWVyeSArPSB0aGlzLmdyb3VwKHEudGVtcGxhdGUsIHRydWUpICsgdGhpcy5fbmV3bGluZTtcblxuICBpZiAocS5mcm9tKVxuICAgIHF1ZXJ5ICs9IG1hcEpvaW4ocS5mcm9tLmRlZmF1bHQgfHwgW10sICcnLCBmdW5jdGlvbiAoZykgeyByZXR1cm4gJ0ZST00gJyArIHRoaXMudG9FbnRpdHkoZykgKyB0aGlzLl9uZXdsaW5lOyB9LCB0aGlzKSArXG4gICAgICAgICAgICAgbWFwSm9pbihxLmZyb20ubmFtZWQgfHwgW10sICcnLCBmdW5jdGlvbiAoZykgeyByZXR1cm4gJ0ZST00gTkFNRUQgJyArIHRoaXMudG9FbnRpdHkoZykgKyB0aGlzLl9uZXdsaW5lOyB9LCB0aGlzKTtcbiAgaWYgKHEud2hlcmUpXG4gICAgcXVlcnkgKz0gJ1dIRVJFICcgKyB0aGlzLmdyb3VwKHEud2hlcmUsIHRydWUpICsgdGhpcy5fbmV3bGluZTtcblxuICBpZiAocS51cGRhdGVzKVxuICAgIHF1ZXJ5ICs9IG1hcEpvaW4ocS51cGRhdGVzLCAnOycgKyB0aGlzLl9uZXdsaW5lLCB0aGlzLnRvVXBkYXRlLCB0aGlzKTtcblxuICBpZiAocS5ncm91cClcbiAgICBxdWVyeSArPSAnR1JPVVAgQlkgJyArIG1hcEpvaW4ocS5ncm91cCwgdW5kZWZpbmVkLCBmdW5jdGlvbiAoaXQpIHtcbiAgICAgIHZhciByZXN1bHQgPSBpc1N0cmluZyhpdC5leHByZXNzaW9uKSA/IGl0LmV4cHJlc3Npb24gOiAnKCcgKyB0aGlzLnRvRXhwcmVzc2lvbihpdC5leHByZXNzaW9uKSArICcpJztcbiAgICAgIHJldHVybiBpdC52YXJpYWJsZSA/ICcoJyArIHJlc3VsdCArICcgQVMgJyArIGl0LnZhcmlhYmxlICsgJyknIDogcmVzdWx0O1xuICAgIH0sIHRoaXMpICsgdGhpcy5fbmV3bGluZTtcbiAgaWYgKHEuaGF2aW5nKVxuICAgIHF1ZXJ5ICs9ICdIQVZJTkcgKCcgKyBtYXBKb2luKHEuaGF2aW5nLCB1bmRlZmluZWQsIHRoaXMudG9FeHByZXNzaW9uLCB0aGlzKSArICcpJyArIHRoaXMuX25ld2xpbmU7XG4gIGlmIChxLm9yZGVyKVxuICAgIHF1ZXJ5ICs9ICdPUkRFUiBCWSAnICsgbWFwSm9pbihxLm9yZGVyLCB1bmRlZmluZWQsIGZ1bmN0aW9uIChpdCkge1xuICAgICAgdmFyIGV4cHIgPSAnKCcgKyB0aGlzLnRvRXhwcmVzc2lvbihpdC5leHByZXNzaW9uKSArICcpJztcbiAgICAgIHJldHVybiAhaXQuZGVzY2VuZGluZyA/IGV4cHIgOiAnREVTQyAnICsgZXhwcjtcbiAgICB9LCB0aGlzKSArIHRoaXMuX25ld2xpbmU7XG5cbiAgaWYgKHEub2Zmc2V0KVxuICAgIHF1ZXJ5ICs9ICdPRkZTRVQgJyArIHEub2Zmc2V0ICsgdGhpcy5fbmV3bGluZTtcbiAgaWYgKHEubGltaXQpXG4gICAgcXVlcnkgKz0gJ0xJTUlUICcgKyBxLmxpbWl0ICsgdGhpcy5fbmV3bGluZTtcblxuICBpZiAocS52YWx1ZXMpXG4gICAgcXVlcnkgKz0gdGhpcy52YWx1ZXMocSk7XG5cbiAgLy8gc3RyaW5naWZ5IHByZWZpeGVzIGF0IHRoZSBlbmQgdG8gbWFyayB1c2VkIG9uZXNcbiAgcXVlcnkgPSB0aGlzLmJhc2VBbmRQcmVmaXhlcyhxKSArIHF1ZXJ5O1xuICByZXR1cm4gcXVlcnkudHJpbSgpO1xufTtcblxuR2VuZXJhdG9yLnByb3RvdHlwZS5iYXNlQW5kUHJlZml4ZXMgPSBmdW5jdGlvbiAocSkge1xuICB2YXIgYmFzZSA9IHEuYmFzZSA/ICgnQkFTRSA8JyArIHEuYmFzZSArICc+JyArIHRoaXMuX25ld2xpbmUpIDogJyc7XG4gIHZhciBwcmVmaXhlcyA9ICcnO1xuICBmb3IgKHZhciBrZXkgaW4gcS5wcmVmaXhlcykge1xuICAgIGlmICh0aGlzLl9vcHRpb25zLmFsbFByZWZpeGVzIHx8IHRoaXMuX3VzZWRQcmVmaXhlc1trZXldKVxuICAgICAgcHJlZml4ZXMgKz0gJ1BSRUZJWCAnICsga2V5ICsgJzogPCcgKyBxLnByZWZpeGVzW2tleV0gKyAnPicgKyB0aGlzLl9uZXdsaW5lO1xuICB9XG4gIHJldHVybiBiYXNlICsgcHJlZml4ZXM7XG59O1xuXG4vLyBDb252ZXJ0cyB0aGUgcGFyc2VkIFNQQVJRTCBwYXR0ZXJuIGludG8gYSBTUEFSUUwgcGF0dGVyblxuR2VuZXJhdG9yLnByb3RvdHlwZS50b1BhdHRlcm4gPSBmdW5jdGlvbiAocGF0dGVybikge1xuICB2YXIgdHlwZSA9IHBhdHRlcm4udHlwZSB8fCAocGF0dGVybiBpbnN0YW5jZW9mIEFycmF5KSAmJiAnYXJyYXknIHx8XG4gICAgICAgICAgICAgKHBhdHRlcm4uc3ViamVjdCAmJiBwYXR0ZXJuLnByZWRpY2F0ZSAmJiBwYXR0ZXJuLm9iamVjdCA/ICd0cmlwbGUnIDogJycpO1xuICBpZiAoISh0eXBlIGluIHRoaXMpKVxuICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93biBlbnRyeSB0eXBlOiAnICsgdHlwZSk7XG4gIHJldHVybiB0aGlzW3R5cGVdKHBhdHRlcm4pO1xufTtcblxuR2VuZXJhdG9yLnByb3RvdHlwZS50cmlwbGUgPSBmdW5jdGlvbiAodCkge1xuICByZXR1cm4gdGhpcy50b0VudGl0eSh0LnN1YmplY3QpICsgJyAnICsgdGhpcy50b0VudGl0eSh0LnByZWRpY2F0ZSkgKyAnICcgKyB0aGlzLnRvRW50aXR5KHQub2JqZWN0KSArICcuJztcbn07XG5cbkdlbmVyYXRvci5wcm90b3R5cGUuYXJyYXkgPSBmdW5jdGlvbiAoaXRlbXMpIHtcbiAgcmV0dXJuIG1hcEpvaW4oaXRlbXMsIHRoaXMuX25ld2xpbmUsIHRoaXMudG9QYXR0ZXJuLCB0aGlzKTtcbn07XG5cbkdlbmVyYXRvci5wcm90b3R5cGUuYmdwID0gZnVuY3Rpb24gKGJncCkge1xuICByZXR1cm4gdGhpcy5lbmNvZGVUcmlwbGVzKGJncC50cmlwbGVzKTtcbn07XG5cbkdlbmVyYXRvci5wcm90b3R5cGUuZW5jb2RlVHJpcGxlcyA9IGZ1bmN0aW9uICh0cmlwbGVzKSB7XG4gIGlmICghdHJpcGxlcy5sZW5ndGgpXG4gICAgcmV0dXJuICcnO1xuXG4gIHZhciBwYXJ0cyA9IFtdLCBzdWJqZWN0ID0gJycsIHByZWRpY2F0ZSA9ICcnO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHRyaXBsZXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgdHJpcGxlID0gdHJpcGxlc1tpXTtcbiAgICAvLyBUcmlwbGUgd2l0aCBkaWZmZXJlbnQgc3ViamVjdFxuICAgIGlmICh0cmlwbGUuc3ViamVjdCAhPT0gc3ViamVjdCkge1xuICAgICAgLy8gVGVybWluYXRlIHByZXZpb3VzIHRyaXBsZVxuICAgICAgaWYgKHN1YmplY3QpXG4gICAgICAgIHBhcnRzLnB1c2goJy4nICsgdGhpcy5fbmV3bGluZSk7XG4gICAgICBzdWJqZWN0ID0gdHJpcGxlLnN1YmplY3Q7XG4gICAgICBwcmVkaWNhdGUgPSB0cmlwbGUucHJlZGljYXRlO1xuICAgICAgcGFydHMucHVzaCh0aGlzLnRvRW50aXR5KHN1YmplY3QpLCAnICcsIHRoaXMudG9FbnRpdHkocHJlZGljYXRlKSk7XG4gICAgfVxuICAgIC8vIFRyaXBsZSB3aXRoIHNhbWUgc3ViamVjdCBidXQgZGlmZmVyZW50IHByZWRpY2F0ZVxuICAgIGVsc2UgaWYgKHRyaXBsZS5wcmVkaWNhdGUgIT09IHByZWRpY2F0ZSkge1xuICAgICAgcHJlZGljYXRlID0gdHJpcGxlLnByZWRpY2F0ZTtcbiAgICAgIHBhcnRzLnB1c2goJzsnICsgdGhpcy5fbmV3bGluZSwgdGhpcy5faW5kZW50LCB0aGlzLnRvRW50aXR5KHByZWRpY2F0ZSkpO1xuICAgIH1cbiAgICAvLyBUcmlwbGUgd2l0aCBzYW1lIHN1YmplY3QgYW5kIHByZWRpY2F0ZVxuICAgIGVsc2Uge1xuICAgICAgcGFydHMucHVzaCgnLCcpO1xuICAgIH1cbiAgICBwYXJ0cy5wdXNoKCcgJywgdGhpcy50b0VudGl0eSh0cmlwbGUub2JqZWN0KSk7XG4gIH1cbiAgcGFydHMucHVzaCgnLicpO1xuXG4gIHJldHVybiBwYXJ0cy5qb2luKCcnKTtcbn1cblxuR2VuZXJhdG9yLnByb3RvdHlwZS5ncmFwaCA9IGZ1bmN0aW9uIChncmFwaCkge1xuICByZXR1cm4gJ0dSQVBIICcgKyB0aGlzLnRvRW50aXR5KGdyYXBoLm5hbWUpICsgJyAnICsgdGhpcy5ncm91cChncmFwaCk7XG59O1xuXG5HZW5lcmF0b3IucHJvdG90eXBlLmdyb3VwID0gZnVuY3Rpb24gKGdyb3VwLCBpbmxpbmUpIHtcbiAgZ3JvdXAgPSBpbmxpbmUgIT09IHRydWUgPyB0aGlzLmFycmF5KGdyb3VwLnBhdHRlcm5zIHx8IGdyb3VwLnRyaXBsZXMpXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDogdGhpcy50b1BhdHRlcm4oZ3JvdXAudHlwZSAhPT0gJ2dyb3VwJyA/IGdyb3VwIDogZ3JvdXAucGF0dGVybnMpO1xuICByZXR1cm4gZ3JvdXAuaW5kZXhPZih0aGlzLl9uZXdsaW5lKSA9PT0gLTEgPyAneyAnICsgZ3JvdXAgKyAnIH0nIDogJ3snICsgdGhpcy5fbmV3bGluZSArIHRoaXMuaW5kZW50KGdyb3VwKSArIHRoaXMuX25ld2xpbmUgKyAnfSc7XG59O1xuXG5HZW5lcmF0b3IucHJvdG90eXBlLnF1ZXJ5ID0gZnVuY3Rpb24gKHF1ZXJ5KSB7XG4gIHJldHVybiB0aGlzLnRvUXVlcnkocXVlcnkpO1xufTtcblxuR2VuZXJhdG9yLnByb3RvdHlwZS5maWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gIHJldHVybiAnRklMVEVSKCcgKyB0aGlzLnRvRXhwcmVzc2lvbihmaWx0ZXIuZXhwcmVzc2lvbikgKyAnKSc7XG59O1xuXG5HZW5lcmF0b3IucHJvdG90eXBlLmJpbmQgPSBmdW5jdGlvbiAoYmluZCkge1xuICByZXR1cm4gJ0JJTkQoJyArIHRoaXMudG9FeHByZXNzaW9uKGJpbmQuZXhwcmVzc2lvbikgKyAnIEFTICcgKyBiaW5kLnZhcmlhYmxlICsgJyknO1xufTtcblxuR2VuZXJhdG9yLnByb3RvdHlwZS5vcHRpb25hbCA9IGZ1bmN0aW9uIChvcHRpb25hbCkge1xuICByZXR1cm4gJ09QVElPTkFMICcgKyB0aGlzLmdyb3VwKG9wdGlvbmFsKTtcbn07XG5cbkdlbmVyYXRvci5wcm90b3R5cGUudW5pb24gPSBmdW5jdGlvbiAodW5pb24pIHtcbiAgcmV0dXJuIG1hcEpvaW4odW5pb24ucGF0dGVybnMsIHRoaXMuX25ld2xpbmUgKyAnVU5JT04nICsgdGhpcy5fbmV3bGluZSwgZnVuY3Rpb24gKHApIHsgcmV0dXJuIHRoaXMuZ3JvdXAocCwgdHJ1ZSk7IH0sIHRoaXMpO1xufTtcblxuR2VuZXJhdG9yLnByb3RvdHlwZS5taW51cyA9IGZ1bmN0aW9uIChtaW51cykge1xuICByZXR1cm4gJ01JTlVTICcgKyB0aGlzLmdyb3VwKG1pbnVzKTtcbn07XG5cbkdlbmVyYXRvci5wcm90b3R5cGUudmFsdWVzID0gZnVuY3Rpb24gKHZhbHVlc0xpc3QpIHtcbiAgLy8gR2F0aGVyIHVuaXF1ZSBrZXlzXG4gIHZhciBrZXlzID0gT2JqZWN0LmtleXModmFsdWVzTGlzdC52YWx1ZXMucmVkdWNlKGZ1bmN0aW9uIChrZXlIYXNoLCB2YWx1ZXMpIHtcbiAgICBmb3IgKHZhciBrZXkgaW4gdmFsdWVzKSBrZXlIYXNoW2tleV0gPSB0cnVlO1xuICAgIHJldHVybiBrZXlIYXNoO1xuICB9LCB7fSkpO1xuICAvLyBDaGVjayB3aGV0aGVyIHNpbXBsZSBzeW50YXggY2FuIGJlIHVzZWRcbiAgdmFyIGxwYXJlbiwgcnBhcmVuO1xuICBpZiAoa2V5cy5sZW5ndGggPT09IDEpIHtcbiAgICBscGFyZW4gPSBycGFyZW4gPSAnJztcbiAgfSBlbHNlIHtcbiAgICBscGFyZW4gPSAnKCc7XG4gICAgcnBhcmVuID0gJyknO1xuICB9XG4gIC8vIENyZWF0ZSB2YWx1ZSByb3dzXG4gIHJldHVybiAnVkFMVUVTICcgKyBscGFyZW4gKyBrZXlzLmpvaW4oJyAnKSArIHJwYXJlbiArICcgeycgKyB0aGlzLl9uZXdsaW5lICtcbiAgICBtYXBKb2luKHZhbHVlc0xpc3QudmFsdWVzLCB0aGlzLl9uZXdsaW5lLCBmdW5jdGlvbiAodmFsdWVzKSB7XG4gICAgICByZXR1cm4gJyAgJyArIGxwYXJlbiArIG1hcEpvaW4oa2V5cywgdW5kZWZpbmVkLCBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgIHJldHVybiB2YWx1ZXNba2V5XSAhPT0gdW5kZWZpbmVkID8gdGhpcy50b0VudGl0eSh2YWx1ZXNba2V5XSkgOiAnVU5ERUYnO1xuICAgICAgfSwgdGhpcykgKyBycGFyZW47XG4gICAgfSwgdGhpcykgKyB0aGlzLl9uZXdsaW5lICsgJ30nO1xufTtcblxuR2VuZXJhdG9yLnByb3RvdHlwZS5zZXJ2aWNlID0gZnVuY3Rpb24gKHNlcnZpY2UpIHtcbiAgcmV0dXJuICdTRVJWSUNFICcgKyAoc2VydmljZS5zaWxlbnQgPyAnU0lMRU5UICcgOiAnJykgKyB0aGlzLnRvRW50aXR5KHNlcnZpY2UubmFtZSkgKyAnICcgK1xuICAgICAgICAgdGhpcy5ncm91cChzZXJ2aWNlKTtcbn07XG5cbi8vIENvbnZlcnRzIHRoZSBwYXJzZWQgZXhwcmVzc2lvbiBvYmplY3QgaW50byBhIFNQQVJRTCBleHByZXNzaW9uXG5HZW5lcmF0b3IucHJvdG90eXBlLnRvRXhwcmVzc2lvbiA9IGZ1bmN0aW9uIChleHByKSB7XG4gIGlmIChpc1N0cmluZyhleHByKSlcbiAgICByZXR1cm4gdGhpcy50b0VudGl0eShleHByKTtcblxuICBzd2l0Y2ggKGV4cHIudHlwZS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgY2FzZSAnYWdncmVnYXRlJzpcbiAgICAgIHJldHVybiBleHByLmFnZ3JlZ2F0aW9uLnRvVXBwZXJDYXNlKCkgK1xuICAgICAgICAgICAgICcoJyArIChleHByLmRpc3RpbmN0ID8gJ0RJU1RJTkNUICcgOiAnJykgKyB0aGlzLnRvRXhwcmVzc2lvbihleHByLmV4cHJlc3Npb24pICtcbiAgICAgICAgICAgICAoZXhwci5zZXBhcmF0b3IgPyAnOyBTRVBBUkFUT1IgPSAnICsgdGhpcy50b0VudGl0eSgnXCInICsgZXhwci5zZXBhcmF0b3IgKyAnXCInKSA6ICcnKSArICcpJztcbiAgICBjYXNlICdmdW5jdGlvbmNhbGwnOlxuICAgICAgcmV0dXJuIHRoaXMudG9FbnRpdHkoZXhwci5mdW5jdGlvbikgKyAnKCcgKyBtYXBKb2luKGV4cHIuYXJncywgJywgJywgdGhpcy50b0V4cHJlc3Npb24sIHRoaXMpICsgJyknO1xuICAgIGNhc2UgJ29wZXJhdGlvbic6XG4gICAgICB2YXIgb3BlcmF0b3IgPSBleHByLm9wZXJhdG9yLnRvVXBwZXJDYXNlKCksIGFyZ3MgPSBleHByLmFyZ3MgfHwgW107XG4gICAgICBzd2l0Y2ggKGV4cHIub3BlcmF0b3IudG9Mb3dlckNhc2UoKSkge1xuICAgICAgLy8gSW5maXggb3BlcmF0b3JzXG4gICAgICBjYXNlICc8JzpcbiAgICAgIGNhc2UgJz4nOlxuICAgICAgY2FzZSAnPj0nOlxuICAgICAgY2FzZSAnPD0nOlxuICAgICAgY2FzZSAnJiYnOlxuICAgICAgY2FzZSAnfHwnOlxuICAgICAgY2FzZSAnPSc6XG4gICAgICBjYXNlICchPSc6XG4gICAgICBjYXNlICcrJzpcbiAgICAgIGNhc2UgJy0nOlxuICAgICAgY2FzZSAnKic6XG4gICAgICBjYXNlICcvJzpcbiAgICAgICAgICByZXR1cm4gKGlzU3RyaW5nKGFyZ3NbMF0pID8gdGhpcy50b0VudGl0eShhcmdzWzBdKSA6ICcoJyArIHRoaXMudG9FeHByZXNzaW9uKGFyZ3NbMF0pICsgJyknKSArXG4gICAgICAgICAgICAgICAgICcgJyArIG9wZXJhdG9yICsgJyAnICtcbiAgICAgICAgICAgICAgICAgKGlzU3RyaW5nKGFyZ3NbMV0pID8gdGhpcy50b0VudGl0eShhcmdzWzFdKSA6ICcoJyArIHRoaXMudG9FeHByZXNzaW9uKGFyZ3NbMV0pICsgJyknKTtcbiAgICAgIC8vIFVuYXJ5IG9wZXJhdG9yc1xuICAgICAgY2FzZSAnISc6XG4gICAgICAgIHJldHVybiAnISgnICsgdGhpcy50b0V4cHJlc3Npb24oYXJnc1swXSkgKyAnKSc7XG4gICAgICAvLyBJTiBhbmQgTk9UIElOXG4gICAgICBjYXNlICdub3Rpbic6XG4gICAgICAgIG9wZXJhdG9yID0gJ05PVCBJTic7XG4gICAgICBjYXNlICdpbic6XG4gICAgICAgIHJldHVybiB0aGlzLnRvRXhwcmVzc2lvbihhcmdzWzBdKSArICcgJyArIG9wZXJhdG9yICtcbiAgICAgICAgICAgICAgICcoJyArIChpc1N0cmluZyhhcmdzWzFdKSA/IGFyZ3NbMV0gOiBtYXBKb2luKGFyZ3NbMV0sICcsICcsIHRoaXMudG9FeHByZXNzaW9uLCB0aGlzKSkgKyAnKSc7XG4gICAgICAvLyBFWElTVFMgYW5kIE5PVCBFWElTVFNcbiAgICAgIGNhc2UgJ25vdGV4aXN0cyc6XG4gICAgICAgIG9wZXJhdG9yID0gJ05PVCBFWElTVFMnO1xuICAgICAgY2FzZSAnZXhpc3RzJzpcbiAgICAgICAgcmV0dXJuIG9wZXJhdG9yICsgJyAnICsgdGhpcy5ncm91cChhcmdzWzBdLCB0cnVlKTtcbiAgICAgIC8vIE90aGVyIGV4cHJlc3Npb25zXG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gb3BlcmF0b3IgKyAnKCcgKyBtYXBKb2luKGFyZ3MsICcsICcsIHRoaXMudG9FeHByZXNzaW9uLCB0aGlzKSArICcpJztcbiAgICAgIH1cbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmtub3duIGV4cHJlc3Npb24gdHlwZTogJyArIGV4cHIudHlwZSk7XG4gIH1cbn07XG5cbi8vIENvbnZlcnRzIHRoZSBwYXJzZWQgZW50aXR5IChvciBwcm9wZXJ0eSBwYXRoKSBpbnRvIGEgU1BBUlFMIGVudGl0eVxuR2VuZXJhdG9yLnByb3RvdHlwZS50b0VudGl0eSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAvLyByZWd1bGFyIGVudGl0eVxuICBpZiAoaXNTdHJpbmcodmFsdWUpKSB7XG4gICAgc3dpdGNoICh2YWx1ZVswXSkge1xuICAgIC8vIHZhcmlhYmxlLCAqIHNlbGVjdG9yLCBvciBibGFuayBub2RlXG4gICAgY2FzZSAnPyc6XG4gICAgY2FzZSAnJCc6XG4gICAgY2FzZSAnKic6XG4gICAgY2FzZSAnXyc6XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgLy8gbGl0ZXJhbFxuICAgIGNhc2UgJ1wiJzpcbiAgICAgIHZhciBtYXRjaCA9IHZhbHVlLm1hdGNoKC9eXCIoW15dKilcIig/OihALispfFxcXlxcXiguKykpPyQvKSB8fCB7fSxcbiAgICAgICAgICBsZXhpY2FsID0gbWF0Y2hbMV0gfHwgJycsIGxhbmd1YWdlID0gbWF0Y2hbMl0gfHwgJycsIGRhdGF0eXBlID0gbWF0Y2hbM107XG4gICAgICB2YWx1ZSA9ICdcIicgKyBsZXhpY2FsLnJlcGxhY2UoZXNjYXBlLCBlc2NhcGVSZXBsYWNlcikgKyAnXCInICsgbGFuZ3VhZ2U7XG4gICAgICBpZiAoZGF0YXR5cGUpIHtcbiAgICAgICAgaWYgKGRhdGF0eXBlID09PSBYU0RfSU5URUdFUiAmJiAvXlxcZCskLy50ZXN0KGxleGljYWwpKVxuICAgICAgICAgIC8vIEFkZCBzcGFjZSB0byBhdm9pZCBjb25mdXNpb24gd2l0aCBkZWNpbWFscyBpbiBicm9rZW4gcGFyc2Vyc1xuICAgICAgICAgIHJldHVybiBsZXhpY2FsICsgJyAnO1xuICAgICAgICB2YWx1ZSArPSAnXl4nICsgdGhpcy5lbmNvZGVJUkkoZGF0YXR5cGUpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIC8vIElSSVxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdGhpcy5lbmNvZGVJUkkodmFsdWUpO1xuICAgIH1cbiAgfVxuICAvLyBwcm9wZXJ0eSBwYXRoXG4gIGVsc2Uge1xuICAgIHZhciBpdGVtcyA9IHZhbHVlLml0ZW1zLm1hcCh0aGlzLnRvRW50aXR5LCB0aGlzKSwgcGF0aCA9IHZhbHVlLnBhdGhUeXBlO1xuICAgIHN3aXRjaCAocGF0aCkge1xuICAgIC8vIHByZWZpeCBvcGVyYXRvclxuICAgIGNhc2UgJ14nOlxuICAgIGNhc2UgJyEnOlxuICAgICAgcmV0dXJuIHBhdGggKyBpdGVtc1swXTtcbiAgICAvLyBwb3N0Zml4IG9wZXJhdG9yXG4gICAgY2FzZSAnKic6XG4gICAgY2FzZSAnKyc6XG4gICAgY2FzZSAnPyc6XG4gICAgICByZXR1cm4gJygnICsgaXRlbXNbMF0gKyBwYXRoICsgJyknO1xuICAgIC8vIGluZml4IG9wZXJhdG9yXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAnKCcgKyBpdGVtcy5qb2luKHBhdGgpICsgJyknO1xuICAgIH1cbiAgfVxufTtcbnZhciBlc2NhcGUgPSAvW1wiXFxcXFxcdFxcblxcclxcYlxcZl0vZyxcbiAgICBlc2NhcGVSZXBsYWNlciA9IGZ1bmN0aW9uIChjKSB7IHJldHVybiBlc2NhcGVSZXBsYWNlbWVudHNbY107IH0sXG4gICAgZXNjYXBlUmVwbGFjZW1lbnRzID0geyAnXFxcXCc6ICdcXFxcXFxcXCcsICdcIic6ICdcXFxcXCInLCAnXFx0JzogJ1xcXFx0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICdcXG4nOiAnXFxcXG4nLCAnXFxyJzogJ1xcXFxyJywgJ1xcYic6ICdcXFxcYicsICdcXGYnOiAnXFxcXGYnIH07XG5cbi8vIFJlcHJlc2VudCB0aGUgSVJJLCBhcyBhIHByZWZpeGVkIG5hbWUgd2hlbiBwb3NzaWJsZVxuR2VuZXJhdG9yLnByb3RvdHlwZS5lbmNvZGVJUkkgPSBmdW5jdGlvbiAoaXJpKSB7XG4gIHZhciBwcmVmaXhNYXRjaCA9IHRoaXMuX3ByZWZpeFJlZ2V4LmV4ZWMoaXJpKTtcbiAgaWYgKHByZWZpeE1hdGNoKSB7XG4gICAgdmFyIHByZWZpeCA9IHRoaXMuX3ByZWZpeEJ5SXJpW3ByZWZpeE1hdGNoWzFdXTtcbiAgICB0aGlzLl91c2VkUHJlZml4ZXNbcHJlZml4XSA9IHRydWU7XG4gICAgcmV0dXJuIHByZWZpeCArICc6JyArIHByZWZpeE1hdGNoWzJdO1xuICB9XG4gIHJldHVybiAnPCcgKyBpcmkgKyAnPic7XG59O1xuXG4vLyBDb252ZXJ0cyB0aGUgcGFyc2VkIHVwZGF0ZSBvYmplY3QgaW50byBhIFNQQVJRTCB1cGRhdGUgY2xhdXNlXG5HZW5lcmF0b3IucHJvdG90eXBlLnRvVXBkYXRlID0gZnVuY3Rpb24gKHVwZGF0ZSkge1xuICBzd2l0Y2ggKHVwZGF0ZS50eXBlIHx8IHVwZGF0ZS51cGRhdGVUeXBlKSB7XG4gIGNhc2UgJ2xvYWQnOlxuICAgIHJldHVybiAnTE9BRCcgKyAodXBkYXRlLnNvdXJjZSA/ICcgJyArIHRoaXMudG9FbnRpdHkodXBkYXRlLnNvdXJjZSkgOiAnJykgK1xuICAgICAgICAgICAodXBkYXRlLmRlc3RpbmF0aW9uID8gJyBJTlRPIEdSQVBIICcgKyB0aGlzLnRvRW50aXR5KHVwZGF0ZS5kZXN0aW5hdGlvbikgOiAnJyk7XG4gIGNhc2UgJ2luc2VydCc6XG4gICAgcmV0dXJuICdJTlNFUlQgREFUQSAnICArIHRoaXMuZ3JvdXAodXBkYXRlLmluc2VydCwgdHJ1ZSk7XG4gIGNhc2UgJ2RlbGV0ZSc6XG4gICAgcmV0dXJuICdERUxFVEUgREFUQSAnICArIHRoaXMuZ3JvdXAodXBkYXRlLmRlbGV0ZSwgdHJ1ZSk7XG4gIGNhc2UgJ2RlbGV0ZXdoZXJlJzpcbiAgICByZXR1cm4gJ0RFTEVURSBXSEVSRSAnICsgdGhpcy5ncm91cCh1cGRhdGUuZGVsZXRlLCB0cnVlKTtcbiAgY2FzZSAnaW5zZXJ0ZGVsZXRlJzpcbiAgICByZXR1cm4gKHVwZGF0ZS5ncmFwaCA/ICdXSVRIICcgKyB0aGlzLnRvRW50aXR5KHVwZGF0ZS5ncmFwaCkgKyB0aGlzLl9uZXdsaW5lIDogJycpICtcbiAgICAgICAgICAgKHVwZGF0ZS5kZWxldGUubGVuZ3RoID8gJ0RFTEVURSAnICsgdGhpcy5ncm91cCh1cGRhdGUuZGVsZXRlLCB0cnVlKSArIHRoaXMuX25ld2xpbmUgOiAnJykgK1xuICAgICAgICAgICAodXBkYXRlLmluc2VydC5sZW5ndGggPyAnSU5TRVJUICcgKyB0aGlzLmdyb3VwKHVwZGF0ZS5pbnNlcnQsIHRydWUpICsgdGhpcy5fbmV3bGluZSA6ICcnKSArXG4gICAgICAgICAgICdXSEVSRSAnICsgdGhpcy5ncm91cCh1cGRhdGUud2hlcmUsIHRydWUpO1xuICBjYXNlICdhZGQnOlxuICBjYXNlICdjb3B5JzpcbiAgY2FzZSAnbW92ZSc6XG4gICAgcmV0dXJuIHVwZGF0ZS50eXBlLnRvVXBwZXJDYXNlKCkgKyAodXBkYXRlLnNvdXJjZS5kZWZhdWx0ID8gJyBERUZBVUxUICcgOiAnICcpICtcbiAgICAgICAgICAgJ1RPICcgKyB0aGlzLnRvRW50aXR5KHVwZGF0ZS5kZXN0aW5hdGlvbi5uYW1lKTtcbiAgY2FzZSAnY3JlYXRlJzpcbiAgY2FzZSAnY2xlYXInOlxuICBjYXNlICdkcm9wJzpcbiAgICByZXR1cm4gdXBkYXRlLnR5cGUudG9VcHBlckNhc2UoKSArICh1cGRhdGUuc2lsZW50ID8gJyBTSUxFTlQgJyA6ICcgJykgKyAoXG4gICAgICB1cGRhdGUuZ3JhcGguZGVmYXVsdCA/ICdERUZBVUxUJyA6XG4gICAgICB1cGRhdGUuZ3JhcGgubmFtZWQgPyAnTkFNRUQnIDpcbiAgICAgIHVwZGF0ZS5ncmFwaC5hbGwgPyAnQUxMJyA6XG4gICAgICAoJ0dSQVBIICcgKyB0aGlzLnRvRW50aXR5KHVwZGF0ZS5ncmFwaC5uYW1lKSlcbiAgICApO1xuICBkZWZhdWx0OlxuICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93biB1cGRhdGUgcXVlcnkgdHlwZTogJyArIHVwZGF0ZS50eXBlKTtcbiAgfVxufTtcblxuLy8gSW5kZW50cyBlYWNoIGxpbmUgb2YgdGhlIHN0cmluZ1xuR2VuZXJhdG9yLnByb3RvdHlwZS5pbmRlbnQgPSBmdW5jdGlvbih0ZXh0KSB7IHJldHVybiB0ZXh0LnJlcGxhY2UoL14vZ20sIHRoaXMuX2luZGVudCk7IH1cblxuLy8gQ2hlY2tzIHdoZXRoZXIgdGhlIG9iamVjdCBpcyBhIHN0cmluZ1xuZnVuY3Rpb24gaXNTdHJpbmcob2JqZWN0KSB7IHJldHVybiB0eXBlb2Ygb2JqZWN0ID09PSAnc3RyaW5nJzsgfVxuXG4vLyBNYXBzIHRoZSBhcnJheSB3aXRoIHRoZSBnaXZlbiBmdW5jdGlvbiwgYW5kIGpvaW5zIHRoZSByZXN1bHRzIHVzaW5nIHRoZSBzZXBhcmF0b3JcbmZ1bmN0aW9uIG1hcEpvaW4oYXJyYXksIHNlcCwgZnVuYywgc2VsZikge1xuICByZXR1cm4gYXJyYXkubWFwKGZ1bmMsIHNlbGYpLmpvaW4oaXNTdHJpbmcoc2VwKSA/IHNlcCA6ICcgJyk7XG59XG5cbi8qKlxuICogQHBhcmFtIG9wdGlvbnMge1xuICogICBhbGxQcmVmaXhlczogYm9vbGVhbixcbiAqICAgaW5kZW50YXRpb246IHN0cmluZyxcbiAqICAgbmV3bGluZTogc3RyaW5nXG4gKiB9XG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gU3BhcnFsR2VuZXJhdG9yKG9wdGlvbnMpIHtcbiAgcmV0dXJuIHtcbiAgICBzdHJpbmdpZnk6IGZ1bmN0aW9uIChxKSB7IHJldHVybiBuZXcgR2VuZXJhdG9yKG9wdGlvbnMsIHEucHJlZml4ZXMpLnRvUXVlcnkocSk7IH1cbiAgfTtcbn07XG4iLCIvKiBwYXJzZXIgZ2VuZXJhdGVkIGJ5IGppc29uIDAuNC4xOCAqL1xuLypcbiAgUmV0dXJucyBhIFBhcnNlciBvYmplY3Qgb2YgdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmU6XG5cbiAgUGFyc2VyOiB7XG4gICAgeXk6IHt9XG4gIH1cblxuICBQYXJzZXIucHJvdG90eXBlOiB7XG4gICAgeXk6IHt9LFxuICAgIHRyYWNlOiBmdW5jdGlvbigpLFxuICAgIHN5bWJvbHNfOiB7YXNzb2NpYXRpdmUgbGlzdDogbmFtZSA9PT4gbnVtYmVyfSxcbiAgICB0ZXJtaW5hbHNfOiB7YXNzb2NpYXRpdmUgbGlzdDogbnVtYmVyID09PiBuYW1lfSxcbiAgICBwcm9kdWN0aW9uc186IFsuLi5dLFxuICAgIHBlcmZvcm1BY3Rpb246IGZ1bmN0aW9uIGFub255bW91cyh5eXRleHQsIHl5bGVuZywgeXlsaW5lbm8sIHl5LCB5eXN0YXRlLCAkJCwgXyQpLFxuICAgIHRhYmxlOiBbLi4uXSxcbiAgICBkZWZhdWx0QWN0aW9uczogey4uLn0sXG4gICAgcGFyc2VFcnJvcjogZnVuY3Rpb24oc3RyLCBoYXNoKSxcbiAgICBwYXJzZTogZnVuY3Rpb24oaW5wdXQpLFxuXG4gICAgbGV4ZXI6IHtcbiAgICAgICAgRU9GOiAxLFxuICAgICAgICBwYXJzZUVycm9yOiBmdW5jdGlvbihzdHIsIGhhc2gpLFxuICAgICAgICBzZXRJbnB1dDogZnVuY3Rpb24oaW5wdXQpLFxuICAgICAgICBpbnB1dDogZnVuY3Rpb24oKSxcbiAgICAgICAgdW5wdXQ6IGZ1bmN0aW9uKHN0ciksXG4gICAgICAgIG1vcmU6IGZ1bmN0aW9uKCksXG4gICAgICAgIGxlc3M6IGZ1bmN0aW9uKG4pLFxuICAgICAgICBwYXN0SW5wdXQ6IGZ1bmN0aW9uKCksXG4gICAgICAgIHVwY29taW5nSW5wdXQ6IGZ1bmN0aW9uKCksXG4gICAgICAgIHNob3dQb3NpdGlvbjogZnVuY3Rpb24oKSxcbiAgICAgICAgdGVzdF9tYXRjaDogZnVuY3Rpb24ocmVnZXhfbWF0Y2hfYXJyYXksIHJ1bGVfaW5kZXgpLFxuICAgICAgICBuZXh0OiBmdW5jdGlvbigpLFxuICAgICAgICBsZXg6IGZ1bmN0aW9uKCksXG4gICAgICAgIGJlZ2luOiBmdW5jdGlvbihjb25kaXRpb24pLFxuICAgICAgICBwb3BTdGF0ZTogZnVuY3Rpb24oKSxcbiAgICAgICAgX2N1cnJlbnRSdWxlczogZnVuY3Rpb24oKSxcbiAgICAgICAgdG9wU3RhdGU6IGZ1bmN0aW9uKCksXG4gICAgICAgIHB1c2hTdGF0ZTogZnVuY3Rpb24oY29uZGl0aW9uKSxcblxuICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgICByYW5nZXM6IGJvb2xlYW4gICAgICAgICAgIChvcHRpb25hbDogdHJ1ZSA9PT4gdG9rZW4gbG9jYXRpb24gaW5mbyB3aWxsIGluY2x1ZGUgYSAucmFuZ2VbXSBtZW1iZXIpXG4gICAgICAgICAgICBmbGV4OiBib29sZWFuICAgICAgICAgICAgIChvcHRpb25hbDogdHJ1ZSA9PT4gZmxleC1saWtlIGxleGluZyBiZWhhdmlvdXIgd2hlcmUgdGhlIHJ1bGVzIGFyZSB0ZXN0ZWQgZXhoYXVzdGl2ZWx5IHRvIGZpbmQgdGhlIGxvbmdlc3QgbWF0Y2gpXG4gICAgICAgICAgICBiYWNrdHJhY2tfbGV4ZXI6IGJvb2xlYW4gIChvcHRpb25hbDogdHJ1ZSA9PT4gbGV4ZXIgcmVnZXhlcyBhcmUgdGVzdGVkIGluIG9yZGVyIGFuZCBmb3IgZWFjaCBtYXRjaGluZyByZWdleCB0aGUgYWN0aW9uIGNvZGUgaXMgaW52b2tlZDsgdGhlIGxleGVyIHRlcm1pbmF0ZXMgdGhlIHNjYW4gd2hlbiBhIHRva2VuIGlzIHJldHVybmVkIGJ5IHRoZSBhY3Rpb24gY29kZSlcbiAgICAgICAgfSxcblxuICAgICAgICBwZXJmb3JtQWN0aW9uOiBmdW5jdGlvbih5eSwgeXlfLCAkYXZvaWRpbmdfbmFtZV9jb2xsaXNpb25zLCBZWV9TVEFSVCksXG4gICAgICAgIHJ1bGVzOiBbLi4uXSxcbiAgICAgICAgY29uZGl0aW9uczoge2Fzc29jaWF0aXZlIGxpc3Q6IG5hbWUgPT0+IHNldH0sXG4gICAgfVxuICB9XG5cblxuICB0b2tlbiBsb2NhdGlvbiBpbmZvIChAJCwgXyQsIGV0Yy4pOiB7XG4gICAgZmlyc3RfbGluZTogbixcbiAgICBsYXN0X2xpbmU6IG4sXG4gICAgZmlyc3RfY29sdW1uOiBuLFxuICAgIGxhc3RfY29sdW1uOiBuLFxuICAgIHJhbmdlOiBbc3RhcnRfbnVtYmVyLCBlbmRfbnVtYmVyXSAgICAgICAod2hlcmUgdGhlIG51bWJlcnMgYXJlIGluZGV4ZXMgaW50byB0aGUgaW5wdXQgc3RyaW5nLCByZWd1bGFyIHplcm8tYmFzZWQpXG4gIH1cblxuXG4gIHRoZSBwYXJzZUVycm9yIGZ1bmN0aW9uIHJlY2VpdmVzIGEgJ2hhc2gnIG9iamVjdCB3aXRoIHRoZXNlIG1lbWJlcnMgZm9yIGxleGVyIGFuZCBwYXJzZXIgZXJyb3JzOiB7XG4gICAgdGV4dDogICAgICAgIChtYXRjaGVkIHRleHQpXG4gICAgdG9rZW46ICAgICAgICh0aGUgcHJvZHVjZWQgdGVybWluYWwgdG9rZW4sIGlmIGFueSlcbiAgICBsaW5lOiAgICAgICAgKHl5bGluZW5vKVxuICB9XG4gIHdoaWxlIHBhcnNlciAoZ3JhbW1hcikgZXJyb3JzIHdpbGwgYWxzbyBwcm92aWRlIHRoZXNlIG1lbWJlcnMsIGkuZS4gcGFyc2VyIGVycm9ycyBkZWxpdmVyIGEgc3VwZXJzZXQgb2YgYXR0cmlidXRlczoge1xuICAgIGxvYzogICAgICAgICAoeXlsbG9jKVxuICAgIGV4cGVjdGVkOiAgICAoc3RyaW5nIGRlc2NyaWJpbmcgdGhlIHNldCBvZiBleHBlY3RlZCB0b2tlbnMpXG4gICAgcmVjb3ZlcmFibGU6IChib29sZWFuOiBUUlVFIHdoZW4gdGhlIHBhcnNlciBoYXMgYSBlcnJvciByZWNvdmVyeSBydWxlIGF2YWlsYWJsZSBmb3IgdGhpcyBwYXJ0aWN1bGFyIGVycm9yKVxuICB9XG4qL1xudmFyIFNwYXJxbFBhcnNlciA9IChmdW5jdGlvbigpe1xudmFyIG89ZnVuY3Rpb24oayx2LG8sbCl7Zm9yKG89b3x8e30sbD1rLmxlbmd0aDtsLS07b1trW2xdXT12KTtyZXR1cm4gb30sJFYwPVs2LDEyLDE1LDI0LDM0LDQzLDQ4LDk5LDEwOSwxMTIsMTE0LDExNSwxMjQsMTI1LDEzMCwyOTgsMjk5LDMwMCwzMDEsMzAyXSwkVjE9WzIsMTk2XSwkVjI9Wzk5LDEwOSwxMTIsMTE0LDExNSwxMjQsMTI1LDEzMCwyOTgsMjk5LDMwMCwzMDEsMzAyXSwkVjM9WzEsMThdLCRWND1bMSwyN10sJFY1PVs2LDgzXSwkVjY9WzM4LDM5LDUxXSwkVjc9WzM4LDUxXSwkVjg9WzEsNTVdLCRWOT1bMSw1N10sJFZhPVsxLDUzXSwkVmI9WzEsNTZdLCRWYz1bMjgsMjksMjkzXSwkVmQ9WzEzLDE2LDI4Nl0sJFZlPVsxMTEsMTMzLDI5NiwzMDNdLCRWZj1bMTMsMTYsMTExLDEzMywyODZdLCRWZz1bMSw4MF0sJFZoPVsxLDg0XSwkVmk9WzEsODZdLCRWaj1bMTExLDEzMywyOTYsMjk3LDMwM10sJFZrPVsxMywxNiwxMTEsMTMzLDI4NiwyOTddLCRWbD1bMSw5Ml0sJFZtPVsyLDIzNl0sJFZuPVsxLDkxXSwkVm89WzEzLDE2LDI4LDI5LDgwLDg2LDIxNSwyMTgsMjE5LDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2XSwkVnA9WzYsMzgsMzksNTEsNjEsNjgsNzEsNzksODEsODNdLCRWcT1bNiwxMywxNiwyOCwzOCwzOSw1MSw2MSw2OCw3MSw3OSw4MSw4MywyODZdLCRWcj1bNiwxMywxNiwyOCwyOSwzMSwzMiwzOCwzOSw0MSw1MSw2MSw2OCw3MSw3OSw4MCw4MSw4Myw4Niw5MiwxMDgsMTExLDEyNCwxMjUsMTI3LDEzMiwxNTksMTYwLDE2MiwxNjUsMTY2LDE4MywxODcsMjA4LDIxMywyMTUsMjE2LDIxOCwyMTksMjIzLDIyNywyMzEsMjQ2LDI1MSwyNjgsMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODYsMjkzLDMwNCwzMDYsMzA3LDMwOSwzMTAsMzExLDMxMiwzMTMsMzE0LDMxNSwzMTZdLCRWcz1bMSwxMDddLCRWdD1bMSwxMDhdLCRWdT1bNiwxMywxNiwyOCwyOSwzOSw0MSw4MCw4Myw4NiwxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwyMTUsMjE4LDIxOSwyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4NiwzMDRdLCRWdj1bMiwyOTVdLCRWdz1bMSwxMjVdLCRWeD1bMSwxMjNdLCRWeT1bNiwxODNdLCRWej1bMiwzMTJdLCRWQT1bMiwzMDBdLCRWQj1bMzgsMTI3XSwkVkM9WzYsNDEsNjgsNzEsNzksODEsODNdLCRWRD1bMiwyMzhdLCRWRT1bMSwxMzldLCRWRj1bMSwxNDFdLCRWRz1bMSwxNTFdLCRWSD1bMSwxNTddLCRWST1bMSwxNjBdLCRWSj1bMSwxNTZdLCRWSz1bMSwxNThdLCRWTD1bMSwxNTRdLCRWTT1bMSwxNTVdLCRWTj1bMSwxNjFdLCRWTz1bMSwxNjJdLCRWUD1bMSwxNjVdLCRWUT1bMSwxNjZdLCRWUj1bMSwxNjddLCRWUz1bMSwxNjhdLCRWVD1bMSwxNjldLCRWVT1bMSwxNzBdLCRWVj1bMSwxNzFdLCRWVz1bMSwxNzJdLCRWWD1bMSwxNzNdLCRWWT1bMSwxNzRdLCRWWj1bMSwxNzVdLCRWXz1bMSwxNzZdLCRWJD1bNiw2MSw2OCw3MSw3OSw4MSw4M10sJFYwMT1bMjgsMjksMzgsMzksNTFdLCRWMTE9WzEzLDE2LDI4LDI5LDgwLDI0OCwyNDksMjUwLDI1MiwyNTQsMjU1LDI1NywyNTgsMjYxLDI2MywyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4NiwzMTYsMzE3LDMxOCwzMTksMzIwLDMyMV0sJFYyMT1bMiw0MDldLCRWMzE9WzEsMTg5XSwkVjQxPVsxLDE5MF0sJFY1MT1bMSwxOTFdLCRWNjE9WzEzLDE2LDQxLDgwLDkyLDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2XSwkVjcxPVs0MSw4Nl0sJFY4MT1bMjgsMzJdLCRWOTE9WzYsMTA4LDE4M10sJFZhMT1bNDEsMTExXSwkVmIxPVs2LDQxLDcxLDc5LDgxLDgzXSwkVmMxPVsyLDMyNF0sJFZkMT1bMiwzMTZdLCRWZTE9WzEsMjI2XSwkVmYxPVsxLDIyOF0sJFZnMT1bNDEsMTExLDMwNF0sJFZoMT1bMTMsMTYsMjgsMjksMzIsMzksNDEsODAsODMsODYsMTExLDE1OSwxNjAsMTYyLDE2NSwxNjYsMTgzLDE4NywyMDgsMjEzLDIxNSwyMTYsMjE4LDIxOSwyNTEsMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODYsMzA0XSwkVmkxPVsxMywxNiwyOCwyOSwzMSwzMiwzOSw0MSw4MCw4Myw4Niw5MiwxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwxODMsMTg3LDIwOCwyMTMsMjE1LDIxNiwyMTgsMjE5LDIyMywyMjcsMjMxLDI0NiwyNTEsMjY4LDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDI5MywzMDQsMzA3LDMxMCwzMTEsMzEyLDMxMywzMTQsMzE1LDMxNl0sJFZqMT1bMTMsMTYsMjgsMjksMzEsMzIsMzksNDEsODAsODMsODYsOTIsMTExLDE1OSwxNjAsMTYyLDE2NSwxNjYsMTgzLDE4NywyMDgsMjEzLDIxNSwyMTYsMjE4LDIxOSwyMjMsMjI3LDIzMSwyNDYsMjUxLDI2OCwyNzAsMjcxLDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDI5MywzMDQsMzA3LDMxMCwzMTEsMzEyLDMxMywzMTQsMzE1LDMxNl0sJFZrMT1bMzEsMzIsMTgzLDIyMywyNTFdLCRWbDE9WzMxLDMyLDE4MywyMjMsMjI3LDI1MV0sJFZtMT1bMzEsMzIsMTgzLDIyMywyMjcsMjMxLDI0NiwyNTEsMjY4LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDMxMCwzMTEsMzEyLDMxMywzMTQsMzE1LDMxNl0sJFZuMT1bMzEsMzIsMTgzLDIyMywyMjcsMjMxLDI0NiwyNTEsMjY4LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI5MywzMDcsMzEwLDMxMSwzMTIsMzEzLDMxNCwzMTUsMzE2XSwkVm8xPVsxLDI2MF0sJFZwMT1bMSwyNjFdLCRWcTE9WzEsMjYzXSwkVnIxPVsxLDI2NF0sJFZzMT1bMSwyNjVdLCRWdDE9WzEsMjY2XSwkVnUxPVsxLDI2OF0sJFZ2MT1bMSwyNjldLCRWdzE9WzIsNDE2XSwkVngxPVsxLDI3MV0sJFZ5MT1bMSwyNzJdLCRWejE9WzEsMjczXSwkVkExPVsxLDI3OV0sJFZCMT1bMSwyNzRdLCRWQzE9WzEsMjc1XSwkVkQxPVsxLDI3Nl0sJFZFMT1bMSwyNzddLCRWRjE9WzEsMjc4XSwkVkcxPVsxLDI4Nl0sJFZIMT1bMSwyOTldLCRWSTE9WzYsNDEsNzksODEsODNdLCRWSjE9WzEsMzE2XSwkVksxPVsxLDMxNV0sJFZMMT1bMzksNDEsODMsMTExLDE1OSwxNjAsMTYyLDE2NSwxNjZdLCRWTTE9WzEsMzI0XSwkVk4xPVsxLDMyNV0sJFZPMT1bNDEsMTExLDE4MywyMTYsMzA0XSwkVlAxPVsyLDM1NF0sJFZRMT1bMTMsMTYsMjgsMjksMzIsODAsODYsMjE1LDIxOCwyMTksMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODZdLCRWUjE9WzEzLDE2LDI4LDI5LDMyLDM5LDQxLDgwLDgzLDg2LDExMSwxNTksMTYwLDE2MiwxNjUsMTY2LDE4MywyMTUsMjE2LDIxOCwyMTksMjUxLDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDMwNF0sJFZTMT1bMTMsMTYsMjgsMjksODAsMjA4LDI0NiwyNDgsMjQ5LDI1MCwyNTIsMjU0LDI1NSwyNTcsMjU4LDI2MSwyNjMsMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODYsMzEwLDMxNiwzMTcsMzE4LDMxOSwzMjAsMzIxXSwkVlQxPVsxLDM0OV0sJFZVMT1bMSwzNTBdLCRWVjE9WzEsMzUyXSwkVlcxPVsxLDM1MV0sJFZYMT1bNiwxMywxNiwyOCwyOSwzMSwzMiwzOSw0MSw2OCw3MSw3NCw3Niw3OSw4MCw4MSw4Myw4NiwxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwxODMsMjE1LDIxOCwyMTksMjIzLDIyNywyMzEsMjQ2LDI0OCwyNDksMjUwLDI1MSwyNTIsMjU0LDI1NSwyNTcsMjU4LDI2MSwyNjMsMjY4LDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDI5MywzMDQsMzA3LDMxMCwzMTEsMzEyLDMxMywzMTQsMzE1LDMxNiwzMTcsMzE4LDMxOSwzMjAsMzIxXSwkVlkxPVsxLDM2MF0sJFZaMT1bMSwzNTldLCRWXzE9WzI5LDg2XSwkViQxPVsxMywxNiwzMiw0MSw4MCw5MiwyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4Nl0sJFYwMj1bMjksNDFdLCRWMTI9WzIsMzE1XSwkVjIyPVs2LDQxLDgzXSwkVjMyPVs2LDEzLDE2LDI5LDQxLDcxLDc5LDgxLDgzLDI0OCwyNDksMjUwLDI1MiwyNTQsMjU1LDI1NywyNTgsMjYxLDI2MywyODYsMzE2LDMxNywzMTgsMzE5LDMyMCwzMjFdLCRWNDI9WzYsMTMsMTYsMjgsMjksMzksNDEsNzEsNzQsNzYsNzksODAsODEsODMsODYsMTExLDE1OSwxNjAsMTYyLDE2NSwxNjYsMjE1LDIxOCwyMTksMjQ4LDI0OSwyNTAsMjUyLDI1NCwyNTUsMjU3LDI1OCwyNjEsMjYzLDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDMwNCwzMTYsMzE3LDMxOCwzMTksMzIwLDMyMV0sJFY1Mj1bNiwxMywxNiwyOCwyOSw0MSw2OCw3MSw3OSw4MSw4MywyNDgsMjQ5LDI1MCwyNTIsMjU0LDI1NSwyNTcsMjU4LDI2MSwyNjMsMjg2LDMxNiwzMTcsMzE4LDMxOSwzMjAsMzIxXSwkVjYyPVs2LDEzLDE2LDI4LDI5LDMxLDMyLDM5LDQxLDYxLDY4LDcxLDc0LDc2LDc5LDgwLDgxLDgzLDg2LDExMSwxNTksMTYwLDE2MiwxNjUsMTY2LDE4MywyMTUsMjE4LDIxOSwyMjMsMjI3LDIzMSwyNDYsMjQ4LDI0OSwyNTAsMjUxLDI1MiwyNTQsMjU1LDI1NywyNTgsMjYxLDI2MywyNjgsMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODYsMjkzLDMwNCwzMDUsMzA3LDMxMCwzMTEsMzEyLDMxMywzMTQsMzE1LDMxNiwzMTcsMzE4LDMxOSwzMjAsMzIxXSwkVjcyPVsxMywxNiwyOSwxODcsMjA4LDIxMywyODZdLCRWODI9WzIsMzY2XSwkVjkyPVsxLDQwMV0sJFZhMj1bMzksNDEsODMsMTExLDE1OSwxNjAsMTYyLDE2NSwxNjYsMzA0XSwkVmIyPVsxMywxNiwyOCwyOSwzMiwzOSw0MSw4MCw4Myw4NiwxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwxODMsMTg3LDIxNSwyMTYsMjE4LDIxOSwyNTEsMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODYsMzA0XSwkVmMyPVsxMywxNiwyOCwyOSw4MCwyMDgsMjQ2LDI0OCwyNDksMjUwLDI1MiwyNTQsMjU1LDI1NywyNTgsMjYxLDI2MywyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4NiwyOTMsMzEwLDMxNiwzMTcsMzE4LDMxOSwzMjAsMzIxXSwkVmQyPVsxLDQ1MF0sJFZlMj1bMSw0NDddLCRWZjI9WzEsNDQ4XSwkVmcyPVsxMywxNiwyOCwyOSwzOSw0MSw4MCw4Myw4NiwxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwyMTUsMjE4LDIxOSwyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4Nl0sJFZoMj1bMTMsMTYsMjgsMjg2XSwkVmkyPVsxMywxNiwyOCwyOSwzOSw0MSw4MCw4Myw4NiwxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwyMTUsMjE4LDIxOSwyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4NiwzMDRdLCRWajI9WzIsMzI3XSwkVmsyPVszOSw0MSw4MywxMTEsMTU5LDE2MCwxNjIsMTY1LDE2NiwxODMsMjE2LDMwNF0sJFZsMj1bNiwxMywxNiwyOCwyOSw0MSw3NCw3Niw3OSw4MSw4MywyNDgsMjQ5LDI1MCwyNTIsMjU0LDI1NSwyNTcsMjU4LDI2MSwyNjMsMjg2LDMxNiwzMTcsMzE4LDMxOSwzMjAsMzIxXSwkVm0yPVsyLDMyMl0sJFZuMj1bMTMsMTYsMjksMTg3LDIwOCwyODZdLCRWbzI9WzEzLDE2LDMyLDgwLDkyLDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2XSwkVnAyPVsxMywxNiwyOCwyOSw0MSw4MCw4NiwxMTEsMjE1LDIxOCwyMTksMjcyLDI3MywyNzQsMjc1LDI3NiwyNzcsMjc4LDI3OSwyODAsMjgxLDI4MiwyODMsMjg0LDI4NSwyODZdLCRWcTI9WzEzLDE2LDI4LDI5LDMyLDgwLDg2LDIxNSwyMTgsMjE5LDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDMwNiwzMDddLCRWcjI9WzEzLDE2LDI4LDI5LDMyLDgwLDg2LDIxNSwyMTgsMjE5LDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDI5MywzMDYsMzA3LDMwOSwzMTBdLCRWczI9WzEsNTYxXSwkVnQyPVsxLDU2Ml0sJFZ1Mj1bMiwzMTBdLCRWdjI9WzEzLDE2LDMyLDE4NywyMTMsMjg2XTtcbnZhciBwYXJzZXIgPSB7dHJhY2U6IGZ1bmN0aW9uIHRyYWNlICgpIHsgfSxcbnl5OiB7fSxcbnN5bWJvbHNfOiB7XCJlcnJvclwiOjIsXCJRdWVyeU9yVXBkYXRlXCI6MyxcIlByb2xvZ3VlXCI6NCxcIlF1ZXJ5T3JVcGRhdGVfZ3JvdXAwXCI6NSxcIkVPRlwiOjYsXCJQcm9sb2d1ZV9yZXBldGl0aW9uMFwiOjcsXCJRdWVyeVwiOjgsXCJRdWVyeV9ncm91cDBcIjo5LFwiUXVlcnlfb3B0aW9uMFwiOjEwLFwiQmFzZURlY2xcIjoxMSxcIkJBU0VcIjoxMixcIklSSVJFRlwiOjEzLFwiUHJlZml4RGVjbFwiOjE0LFwiUFJFRklYXCI6MTUsXCJQTkFNRV9OU1wiOjE2LFwiU2VsZWN0UXVlcnlcIjoxNyxcIlNlbGVjdENsYXVzZVwiOjE4LFwiU2VsZWN0UXVlcnlfcmVwZXRpdGlvbjBcIjoxOSxcIldoZXJlQ2xhdXNlXCI6MjAsXCJTb2x1dGlvbk1vZGlmaWVyXCI6MjEsXCJTdWJTZWxlY3RcIjoyMixcIlN1YlNlbGVjdF9vcHRpb24wXCI6MjMsXCJTRUxFQ1RcIjoyNCxcIlNlbGVjdENsYXVzZV9vcHRpb24wXCI6MjUsXCJTZWxlY3RDbGF1c2VfZ3JvdXAwXCI6MjYsXCJTZWxlY3RDbGF1c2VJdGVtXCI6MjcsXCJWQVJcIjoyOCxcIihcIjoyOSxcIkV4cHJlc3Npb25cIjozMCxcIkFTXCI6MzEsXCIpXCI6MzIsXCJDb25zdHJ1Y3RRdWVyeVwiOjMzLFwiQ09OU1RSVUNUXCI6MzQsXCJDb25zdHJ1Y3RUZW1wbGF0ZVwiOjM1LFwiQ29uc3RydWN0UXVlcnlfcmVwZXRpdGlvbjBcIjozNixcIkNvbnN0cnVjdFF1ZXJ5X3JlcGV0aXRpb24xXCI6MzcsXCJXSEVSRVwiOjM4LFwie1wiOjM5LFwiQ29uc3RydWN0UXVlcnlfb3B0aW9uMFwiOjQwLFwifVwiOjQxLFwiRGVzY3JpYmVRdWVyeVwiOjQyLFwiREVTQ1JJQkVcIjo0MyxcIkRlc2NyaWJlUXVlcnlfZ3JvdXAwXCI6NDQsXCJEZXNjcmliZVF1ZXJ5X3JlcGV0aXRpb24wXCI6NDUsXCJEZXNjcmliZVF1ZXJ5X29wdGlvbjBcIjo0NixcIkFza1F1ZXJ5XCI6NDcsXCJBU0tcIjo0OCxcIkFza1F1ZXJ5X3JlcGV0aXRpb24wXCI6NDksXCJEYXRhc2V0Q2xhdXNlXCI6NTAsXCJGUk9NXCI6NTEsXCJEYXRhc2V0Q2xhdXNlX29wdGlvbjBcIjo1MixcImlyaVwiOjUzLFwiV2hlcmVDbGF1c2Vfb3B0aW9uMFwiOjU0LFwiR3JvdXBHcmFwaFBhdHRlcm5cIjo1NSxcIlNvbHV0aW9uTW9kaWZpZXJfb3B0aW9uMFwiOjU2LFwiU29sdXRpb25Nb2RpZmllcl9vcHRpb24xXCI6NTcsXCJTb2x1dGlvbk1vZGlmaWVyX29wdGlvbjJcIjo1OCxcIlNvbHV0aW9uTW9kaWZpZXJfb3B0aW9uM1wiOjU5LFwiR3JvdXBDbGF1c2VcIjo2MCxcIkdST1VQXCI6NjEsXCJCWVwiOjYyLFwiR3JvdXBDbGF1c2VfcmVwZXRpdGlvbl9wbHVzMFwiOjYzLFwiR3JvdXBDb25kaXRpb25cIjo2NCxcIkJ1aWx0SW5DYWxsXCI6NjUsXCJGdW5jdGlvbkNhbGxcIjo2NixcIkhhdmluZ0NsYXVzZVwiOjY3LFwiSEFWSU5HXCI6NjgsXCJIYXZpbmdDbGF1c2VfcmVwZXRpdGlvbl9wbHVzMFwiOjY5LFwiT3JkZXJDbGF1c2VcIjo3MCxcIk9SREVSXCI6NzEsXCJPcmRlckNsYXVzZV9yZXBldGl0aW9uX3BsdXMwXCI6NzIsXCJPcmRlckNvbmRpdGlvblwiOjczLFwiQVNDXCI6NzQsXCJCcmFja2V0dGVkRXhwcmVzc2lvblwiOjc1LFwiREVTQ1wiOjc2LFwiQ29uc3RyYWludFwiOjc3LFwiTGltaXRPZmZzZXRDbGF1c2VzXCI6NzgsXCJMSU1JVFwiOjc5LFwiSU5URUdFUlwiOjgwLFwiT0ZGU0VUXCI6ODEsXCJWYWx1ZXNDbGF1c2VcIjo4MixcIlZBTFVFU1wiOjgzLFwiSW5saW5lRGF0YVwiOjg0LFwiSW5saW5lRGF0YV9yZXBldGl0aW9uMFwiOjg1LFwiTklMXCI6ODYsXCJJbmxpbmVEYXRhX3JlcGV0aXRpb24xXCI6ODcsXCJJbmxpbmVEYXRhX3JlcGV0aXRpb25fcGx1czJcIjo4OCxcIklubGluZURhdGFfcmVwZXRpdGlvbjNcIjo4OSxcIkRhdGFCbG9ja1ZhbHVlXCI6OTAsXCJMaXRlcmFsXCI6OTEsXCJVTkRFRlwiOjkyLFwiRGF0YUJsb2NrVmFsdWVMaXN0XCI6OTMsXCJEYXRhQmxvY2tWYWx1ZUxpc3RfcmVwZXRpdGlvbl9wbHVzMFwiOjk0LFwiVXBkYXRlXCI6OTUsXCJVcGRhdGVfcmVwZXRpdGlvbjBcIjo5NixcIlVwZGF0ZTFcIjo5NyxcIlVwZGF0ZV9vcHRpb24wXCI6OTgsXCJMT0FEXCI6OTksXCJVcGRhdGUxX29wdGlvbjBcIjoxMDAsXCJVcGRhdGUxX29wdGlvbjFcIjoxMDEsXCJVcGRhdGUxX2dyb3VwMFwiOjEwMixcIlVwZGF0ZTFfb3B0aW9uMlwiOjEwMyxcIkdyYXBoUmVmQWxsXCI6MTA0LFwiVXBkYXRlMV9ncm91cDFcIjoxMDUsXCJVcGRhdGUxX29wdGlvbjNcIjoxMDYsXCJHcmFwaE9yRGVmYXVsdFwiOjEwNyxcIlRPXCI6MTA4LFwiQ1JFQVRFXCI6MTA5LFwiVXBkYXRlMV9vcHRpb240XCI6MTEwLFwiR1JBUEhcIjoxMTEsXCJJTlNFUlREQVRBXCI6MTEyLFwiUXVhZFBhdHRlcm5cIjoxMTMsXCJERUxFVEVEQVRBXCI6MTE0LFwiREVMRVRFV0hFUkVcIjoxMTUsXCJVcGRhdGUxX29wdGlvbjVcIjoxMTYsXCJJbnNlcnRDbGF1c2VcIjoxMTcsXCJVcGRhdGUxX29wdGlvbjZcIjoxMTgsXCJVcGRhdGUxX3JlcGV0aXRpb24wXCI6MTE5LFwiVXBkYXRlMV9vcHRpb243XCI6MTIwLFwiRGVsZXRlQ2xhdXNlXCI6MTIxLFwiVXBkYXRlMV9vcHRpb244XCI6MTIyLFwiVXBkYXRlMV9yZXBldGl0aW9uMVwiOjEyMyxcIkRFTEVURVwiOjEyNCxcIklOU0VSVFwiOjEyNSxcIlVzaW5nQ2xhdXNlXCI6MTI2LFwiVVNJTkdcIjoxMjcsXCJVc2luZ0NsYXVzZV9vcHRpb24wXCI6MTI4LFwiV2l0aENsYXVzZVwiOjEyOSxcIldJVEhcIjoxMzAsXCJJbnRvR3JhcGhDbGF1c2VcIjoxMzEsXCJJTlRPXCI6MTMyLFwiREVGQVVMVFwiOjEzMyxcIkdyYXBoT3JEZWZhdWx0X29wdGlvbjBcIjoxMzQsXCJHcmFwaFJlZkFsbF9ncm91cDBcIjoxMzUsXCJRdWFkUGF0dGVybl9vcHRpb24wXCI6MTM2LFwiUXVhZFBhdHRlcm5fcmVwZXRpdGlvbjBcIjoxMzcsXCJRdWFkc05vdFRyaXBsZXNcIjoxMzgsXCJRdWFkc05vdFRyaXBsZXNfZ3JvdXAwXCI6MTM5LFwiUXVhZHNOb3RUcmlwbGVzX29wdGlvbjBcIjoxNDAsXCJRdWFkc05vdFRyaXBsZXNfb3B0aW9uMVwiOjE0MSxcIlF1YWRzTm90VHJpcGxlc19vcHRpb24yXCI6MTQyLFwiVHJpcGxlc1RlbXBsYXRlXCI6MTQzLFwiVHJpcGxlc1RlbXBsYXRlX3JlcGV0aXRpb24wXCI6MTQ0LFwiVHJpcGxlc1NhbWVTdWJqZWN0XCI6MTQ1LFwiVHJpcGxlc1RlbXBsYXRlX29wdGlvbjBcIjoxNDYsXCJHcm91cEdyYXBoUGF0dGVyblN1YlwiOjE0NyxcIkdyb3VwR3JhcGhQYXR0ZXJuU3ViX29wdGlvbjBcIjoxNDgsXCJHcm91cEdyYXBoUGF0dGVyblN1Yl9yZXBldGl0aW9uMFwiOjE0OSxcIkdyb3VwR3JhcGhQYXR0ZXJuU3ViVGFpbFwiOjE1MCxcIkdyYXBoUGF0dGVybk5vdFRyaXBsZXNcIjoxNTEsXCJHcm91cEdyYXBoUGF0dGVyblN1YlRhaWxfb3B0aW9uMFwiOjE1MixcIkdyb3VwR3JhcGhQYXR0ZXJuU3ViVGFpbF9vcHRpb24xXCI6MTUzLFwiVHJpcGxlc0Jsb2NrXCI6MTU0LFwiVHJpcGxlc0Jsb2NrX3JlcGV0aXRpb24wXCI6MTU1LFwiVHJpcGxlc1NhbWVTdWJqZWN0UGF0aFwiOjE1NixcIlRyaXBsZXNCbG9ja19vcHRpb24wXCI6MTU3LFwiR3JhcGhQYXR0ZXJuTm90VHJpcGxlc19yZXBldGl0aW9uMFwiOjE1OCxcIk9QVElPTkFMXCI6MTU5LFwiTUlOVVNcIjoxNjAsXCJHcmFwaFBhdHRlcm5Ob3RUcmlwbGVzX2dyb3VwMFwiOjE2MSxcIlNFUlZJQ0VcIjoxNjIsXCJHcmFwaFBhdHRlcm5Ob3RUcmlwbGVzX29wdGlvbjBcIjoxNjMsXCJHcmFwaFBhdHRlcm5Ob3RUcmlwbGVzX2dyb3VwMVwiOjE2NCxcIkZJTFRFUlwiOjE2NSxcIkJJTkRcIjoxNjYsXCJGdW5jdGlvbkNhbGxfb3B0aW9uMFwiOjE2NyxcIkZ1bmN0aW9uQ2FsbF9yZXBldGl0aW9uMFwiOjE2OCxcIkV4cHJlc3Npb25MaXN0XCI6MTY5LFwiRXhwcmVzc2lvbkxpc3RfcmVwZXRpdGlvbjBcIjoxNzAsXCJDb25zdHJ1Y3RUZW1wbGF0ZV9vcHRpb24wXCI6MTcxLFwiQ29uc3RydWN0VHJpcGxlc1wiOjE3MixcIkNvbnN0cnVjdFRyaXBsZXNfcmVwZXRpdGlvbjBcIjoxNzMsXCJDb25zdHJ1Y3RUcmlwbGVzX29wdGlvbjBcIjoxNzQsXCJWYXJPclRlcm1cIjoxNzUsXCJQcm9wZXJ0eUxpc3ROb3RFbXB0eVwiOjE3NixcIlRyaXBsZXNOb2RlXCI6MTc3LFwiUHJvcGVydHlMaXN0XCI6MTc4LFwiUHJvcGVydHlMaXN0X29wdGlvbjBcIjoxNzksXCJWZXJiT2JqZWN0TGlzdFwiOjE4MCxcIlByb3BlcnR5TGlzdE5vdEVtcHR5X3JlcGV0aXRpb24wXCI6MTgxLFwiU2VtaU9wdGlvbmFsVmVyYk9iamVjdExpc3RcIjoxODIsXCI7XCI6MTgzLFwiU2VtaU9wdGlvbmFsVmVyYk9iamVjdExpc3Rfb3B0aW9uMFwiOjE4NCxcIlZlcmJcIjoxODUsXCJPYmplY3RMaXN0XCI6MTg2LFwiYVwiOjE4NyxcIk9iamVjdExpc3RfcmVwZXRpdGlvbjBcIjoxODgsXCJHcmFwaE5vZGVcIjoxODksXCJQcm9wZXJ0eUxpc3RQYXRoTm90RW1wdHlcIjoxOTAsXCJUcmlwbGVzTm9kZVBhdGhcIjoxOTEsXCJUcmlwbGVzU2FtZVN1YmplY3RQYXRoX29wdGlvbjBcIjoxOTIsXCJQcm9wZXJ0eUxpc3RQYXRoTm90RW1wdHlfZ3JvdXAwXCI6MTkzLFwiUHJvcGVydHlMaXN0UGF0aE5vdEVtcHR5X3JlcGV0aXRpb24wXCI6MTk0LFwiR3JhcGhOb2RlUGF0aFwiOjE5NSxcIlByb3BlcnR5TGlzdFBhdGhOb3RFbXB0eV9yZXBldGl0aW9uMVwiOjE5NixcIlByb3BlcnR5TGlzdFBhdGhOb3RFbXB0eVRhaWxcIjoxOTcsXCJQcm9wZXJ0eUxpc3RQYXRoTm90RW1wdHlUYWlsX2dyb3VwMFwiOjE5OCxcIlBhdGhcIjoxOTksXCJQYXRoX3JlcGV0aXRpb24wXCI6MjAwLFwiUGF0aFNlcXVlbmNlXCI6MjAxLFwiUGF0aFNlcXVlbmNlX3JlcGV0aXRpb24wXCI6MjAyLFwiUGF0aEVsdE9ySW52ZXJzZVwiOjIwMyxcIlBhdGhFbHRcIjoyMDQsXCJQYXRoUHJpbWFyeVwiOjIwNSxcIlBhdGhFbHRfb3B0aW9uMFwiOjIwNixcIlBhdGhFbHRPckludmVyc2Vfb3B0aW9uMFwiOjIwNyxcIiFcIjoyMDgsXCJQYXRoTmVnYXRlZFByb3BlcnR5U2V0XCI6MjA5LFwiUGF0aE9uZUluUHJvcGVydHlTZXRcIjoyMTAsXCJQYXRoTmVnYXRlZFByb3BlcnR5U2V0X3JlcGV0aXRpb24wXCI6MjExLFwiUGF0aE5lZ2F0ZWRQcm9wZXJ0eVNldF9vcHRpb24wXCI6MjEyLFwiXlwiOjIxMyxcIlRyaXBsZXNOb2RlX3JlcGV0aXRpb25fcGx1czBcIjoyMTQsXCJbXCI6MjE1LFwiXVwiOjIxNixcIlRyaXBsZXNOb2RlUGF0aF9yZXBldGl0aW9uX3BsdXMwXCI6MjE3LFwiQkxBTktfTk9ERV9MQUJFTFwiOjIxOCxcIkFOT05cIjoyMTksXCJDb25kaXRpb25hbEFuZEV4cHJlc3Npb25cIjoyMjAsXCJFeHByZXNzaW9uX3JlcGV0aXRpb24wXCI6MjIxLFwiRXhwcmVzc2lvblRhaWxcIjoyMjIsXCJ8fFwiOjIyMyxcIlJlbGF0aW9uYWxFeHByZXNzaW9uXCI6MjI0LFwiQ29uZGl0aW9uYWxBbmRFeHByZXNzaW9uX3JlcGV0aXRpb24wXCI6MjI1LFwiQ29uZGl0aW9uYWxBbmRFeHByZXNzaW9uVGFpbFwiOjIyNixcIiYmXCI6MjI3LFwiQWRkaXRpdmVFeHByZXNzaW9uXCI6MjI4LFwiUmVsYXRpb25hbEV4cHJlc3Npb25fZ3JvdXAwXCI6MjI5LFwiUmVsYXRpb25hbEV4cHJlc3Npb25fb3B0aW9uMFwiOjIzMCxcIklOXCI6MjMxLFwiTXVsdGlwbGljYXRpdmVFeHByZXNzaW9uXCI6MjMyLFwiQWRkaXRpdmVFeHByZXNzaW9uX3JlcGV0aXRpb24wXCI6MjMzLFwiQWRkaXRpdmVFeHByZXNzaW9uVGFpbFwiOjIzNCxcIkFkZGl0aXZlRXhwcmVzc2lvblRhaWxfZ3JvdXAwXCI6MjM1LFwiTnVtZXJpY0xpdGVyYWxQb3NpdGl2ZVwiOjIzNixcIkFkZGl0aXZlRXhwcmVzc2lvblRhaWxfcmVwZXRpdGlvbjBcIjoyMzcsXCJOdW1lcmljTGl0ZXJhbE5lZ2F0aXZlXCI6MjM4LFwiQWRkaXRpdmVFeHByZXNzaW9uVGFpbF9yZXBldGl0aW9uMVwiOjIzOSxcIlVuYXJ5RXhwcmVzc2lvblwiOjI0MCxcIk11bHRpcGxpY2F0aXZlRXhwcmVzc2lvbl9yZXBldGl0aW9uMFwiOjI0MSxcIk11bHRpcGxpY2F0aXZlRXhwcmVzc2lvblRhaWxcIjoyNDIsXCJNdWx0aXBsaWNhdGl2ZUV4cHJlc3Npb25UYWlsX2dyb3VwMFwiOjI0MyxcIlVuYXJ5RXhwcmVzc2lvbl9vcHRpb24wXCI6MjQ0LFwiUHJpbWFyeUV4cHJlc3Npb25cIjoyNDUsXCItXCI6MjQ2LFwiQWdncmVnYXRlXCI6MjQ3LFwiRlVOQ19BUklUWTBcIjoyNDgsXCJGVU5DX0FSSVRZMVwiOjI0OSxcIkZVTkNfQVJJVFkyXCI6MjUwLFwiLFwiOjI1MSxcIklGXCI6MjUyLFwiQnVpbHRJbkNhbGxfZ3JvdXAwXCI6MjUzLFwiQk9VTkRcIjoyNTQsXCJCTk9ERVwiOjI1NSxcIkJ1aWx0SW5DYWxsX29wdGlvbjBcIjoyNTYsXCJFWElTVFNcIjoyNTcsXCJDT1VOVFwiOjI1OCxcIkFnZ3JlZ2F0ZV9vcHRpb24wXCI6MjU5LFwiQWdncmVnYXRlX2dyb3VwMFwiOjI2MCxcIkZVTkNfQUdHUkVHQVRFXCI6MjYxLFwiQWdncmVnYXRlX29wdGlvbjFcIjoyNjIsXCJHUk9VUF9DT05DQVRcIjoyNjMsXCJBZ2dyZWdhdGVfb3B0aW9uMlwiOjI2NCxcIkFnZ3JlZ2F0ZV9vcHRpb24zXCI6MjY1LFwiR3JvdXBDb25jYXRTZXBhcmF0b3JcIjoyNjYsXCJTRVBBUkFUT1JcIjoyNjcsXCI9XCI6MjY4LFwiU3RyaW5nXCI6MjY5LFwiTEFOR1RBR1wiOjI3MCxcIl5eXCI6MjcxLFwiREVDSU1BTFwiOjI3MixcIkRPVUJMRVwiOjI3MyxcInRydWVcIjoyNzQsXCJmYWxzZVwiOjI3NSxcIlNUUklOR19MSVRFUkFMMVwiOjI3NixcIlNUUklOR19MSVRFUkFMMlwiOjI3NyxcIlNUUklOR19MSVRFUkFMX0xPTkcxXCI6Mjc4LFwiU1RSSU5HX0xJVEVSQUxfTE9ORzJcIjoyNzksXCJJTlRFR0VSX1BPU0lUSVZFXCI6MjgwLFwiREVDSU1BTF9QT1NJVElWRVwiOjI4MSxcIkRPVUJMRV9QT1NJVElWRVwiOjI4MixcIklOVEVHRVJfTkVHQVRJVkVcIjoyODMsXCJERUNJTUFMX05FR0FUSVZFXCI6Mjg0LFwiRE9VQkxFX05FR0FUSVZFXCI6Mjg1LFwiUE5BTUVfTE5cIjoyODYsXCJRdWVyeU9yVXBkYXRlX2dyb3VwMF9vcHRpb24wXCI6Mjg3LFwiUHJvbG9ndWVfcmVwZXRpdGlvbjBfZ3JvdXAwXCI6Mjg4LFwiU2VsZWN0Q2xhdXNlX29wdGlvbjBfZ3JvdXAwXCI6Mjg5LFwiRElTVElOQ1RcIjoyOTAsXCJSRURVQ0VEXCI6MjkxLFwiU2VsZWN0Q2xhdXNlX2dyb3VwMF9yZXBldGl0aW9uX3BsdXMwXCI6MjkyLFwiKlwiOjI5MyxcIkRlc2NyaWJlUXVlcnlfZ3JvdXAwX3JlcGV0aXRpb25fcGx1czBfZ3JvdXAwXCI6Mjk0LFwiRGVzY3JpYmVRdWVyeV9ncm91cDBfcmVwZXRpdGlvbl9wbHVzMFwiOjI5NSxcIk5BTUVEXCI6Mjk2LFwiU0lMRU5UXCI6Mjk3LFwiQ0xFQVJcIjoyOTgsXCJEUk9QXCI6Mjk5LFwiQUREXCI6MzAwLFwiTU9WRVwiOjMwMSxcIkNPUFlcIjozMDIsXCJBTExcIjozMDMsXCIuXCI6MzA0LFwiVU5JT05cIjozMDUsXCJ8XCI6MzA2LFwiL1wiOjMwNyxcIlBhdGhFbHRfb3B0aW9uMF9ncm91cDBcIjozMDgsXCI/XCI6MzA5LFwiK1wiOjMxMCxcIiE9XCI6MzExLFwiPFwiOjMxMixcIj5cIjozMTMsXCI8PVwiOjMxNCxcIj49XCI6MzE1LFwiTk9UXCI6MzE2LFwiQ09OQ0FUXCI6MzE3LFwiQ09BTEVTQ0VcIjozMTgsXCJTVUJTVFJcIjozMTksXCJSRUdFWFwiOjMyMCxcIlJFUExBQ0VcIjozMjEsXCIkYWNjZXB0XCI6MCxcIiRlbmRcIjoxfSxcbnRlcm1pbmFsc186IHsyOlwiZXJyb3JcIiw2OlwiRU9GXCIsMTI6XCJCQVNFXCIsMTM6XCJJUklSRUZcIiwxNTpcIlBSRUZJWFwiLDE2OlwiUE5BTUVfTlNcIiwyNDpcIlNFTEVDVFwiLDI4OlwiVkFSXCIsMjk6XCIoXCIsMzE6XCJBU1wiLDMyOlwiKVwiLDM0OlwiQ09OU1RSVUNUXCIsMzg6XCJXSEVSRVwiLDM5Olwie1wiLDQxOlwifVwiLDQzOlwiREVTQ1JJQkVcIiw0ODpcIkFTS1wiLDUxOlwiRlJPTVwiLDYxOlwiR1JPVVBcIiw2MjpcIkJZXCIsNjg6XCJIQVZJTkdcIiw3MTpcIk9SREVSXCIsNzQ6XCJBU0NcIiw3NjpcIkRFU0NcIiw3OTpcIkxJTUlUXCIsODA6XCJJTlRFR0VSXCIsODE6XCJPRkZTRVRcIiw4MzpcIlZBTFVFU1wiLDg2OlwiTklMXCIsOTI6XCJVTkRFRlwiLDk5OlwiTE9BRFwiLDEwODpcIlRPXCIsMTA5OlwiQ1JFQVRFXCIsMTExOlwiR1JBUEhcIiwxMTI6XCJJTlNFUlREQVRBXCIsMTE0OlwiREVMRVRFREFUQVwiLDExNTpcIkRFTEVURVdIRVJFXCIsMTI0OlwiREVMRVRFXCIsMTI1OlwiSU5TRVJUXCIsMTI3OlwiVVNJTkdcIiwxMzA6XCJXSVRIXCIsMTMyOlwiSU5UT1wiLDEzMzpcIkRFRkFVTFRcIiwxNTk6XCJPUFRJT05BTFwiLDE2MDpcIk1JTlVTXCIsMTYyOlwiU0VSVklDRVwiLDE2NTpcIkZJTFRFUlwiLDE2NjpcIkJJTkRcIiwxODM6XCI7XCIsMTg3OlwiYVwiLDIwODpcIiFcIiwyMTM6XCJeXCIsMjE1OlwiW1wiLDIxNjpcIl1cIiwyMTg6XCJCTEFOS19OT0RFX0xBQkVMXCIsMjE5OlwiQU5PTlwiLDIyMzpcInx8XCIsMjI3OlwiJiZcIiwyMzE6XCJJTlwiLDI0NjpcIi1cIiwyNDg6XCJGVU5DX0FSSVRZMFwiLDI0OTpcIkZVTkNfQVJJVFkxXCIsMjUwOlwiRlVOQ19BUklUWTJcIiwyNTE6XCIsXCIsMjUyOlwiSUZcIiwyNTQ6XCJCT1VORFwiLDI1NTpcIkJOT0RFXCIsMjU3OlwiRVhJU1RTXCIsMjU4OlwiQ09VTlRcIiwyNjE6XCJGVU5DX0FHR1JFR0FURVwiLDI2MzpcIkdST1VQX0NPTkNBVFwiLDI2NzpcIlNFUEFSQVRPUlwiLDI2ODpcIj1cIiwyNzA6XCJMQU5HVEFHXCIsMjcxOlwiXl5cIiwyNzI6XCJERUNJTUFMXCIsMjczOlwiRE9VQkxFXCIsMjc0OlwidHJ1ZVwiLDI3NTpcImZhbHNlXCIsMjc2OlwiU1RSSU5HX0xJVEVSQUwxXCIsMjc3OlwiU1RSSU5HX0xJVEVSQUwyXCIsMjc4OlwiU1RSSU5HX0xJVEVSQUxfTE9ORzFcIiwyNzk6XCJTVFJJTkdfTElURVJBTF9MT05HMlwiLDI4MDpcIklOVEVHRVJfUE9TSVRJVkVcIiwyODE6XCJERUNJTUFMX1BPU0lUSVZFXCIsMjgyOlwiRE9VQkxFX1BPU0lUSVZFXCIsMjgzOlwiSU5URUdFUl9ORUdBVElWRVwiLDI4NDpcIkRFQ0lNQUxfTkVHQVRJVkVcIiwyODU6XCJET1VCTEVfTkVHQVRJVkVcIiwyODY6XCJQTkFNRV9MTlwiLDI5MDpcIkRJU1RJTkNUXCIsMjkxOlwiUkVEVUNFRFwiLDI5MzpcIipcIiwyOTY6XCJOQU1FRFwiLDI5NzpcIlNJTEVOVFwiLDI5ODpcIkNMRUFSXCIsMjk5OlwiRFJPUFwiLDMwMDpcIkFERFwiLDMwMTpcIk1PVkVcIiwzMDI6XCJDT1BZXCIsMzAzOlwiQUxMXCIsMzA0OlwiLlwiLDMwNTpcIlVOSU9OXCIsMzA2OlwifFwiLDMwNzpcIi9cIiwzMDk6XCI/XCIsMzEwOlwiK1wiLDMxMTpcIiE9XCIsMzEyOlwiPFwiLDMxMzpcIj5cIiwzMTQ6XCI8PVwiLDMxNTpcIj49XCIsMzE2OlwiTk9UXCIsMzE3OlwiQ09OQ0FUXCIsMzE4OlwiQ09BTEVTQ0VcIiwzMTk6XCJTVUJTVFJcIiwzMjA6XCJSRUdFWFwiLDMyMTpcIlJFUExBQ0VcIn0sXG5wcm9kdWN0aW9uc186IFswLFszLDNdLFs0LDFdLFs4LDJdLFsxMSwyXSxbMTQsM10sWzE3LDRdLFsyMiw0XSxbMTgsM10sWzI3LDFdLFsyNyw1XSxbMzMsNV0sWzMzLDddLFs0Miw1XSxbNDcsNF0sWzUwLDNdLFsyMCwyXSxbMjEsNF0sWzYwLDNdLFs2NCwxXSxbNjQsMV0sWzY0LDNdLFs2NCw1XSxbNjQsMV0sWzY3LDJdLFs3MCwzXSxbNzMsMl0sWzczLDJdLFs3MywxXSxbNzMsMV0sWzc4LDJdLFs3OCwyXSxbNzgsNF0sWzc4LDRdLFs4MiwyXSxbODQsNF0sWzg0LDRdLFs4NCw2XSxbOTAsMV0sWzkwLDFdLFs5MCwxXSxbOTMsM10sWzk1LDNdLFs5Nyw0XSxbOTcsM10sWzk3LDVdLFs5Nyw0XSxbOTcsMl0sWzk3LDJdLFs5NywyXSxbOTcsNl0sWzk3LDZdLFsxMjEsMl0sWzExNywyXSxbMTI2LDNdLFsxMjksMl0sWzEzMSwzXSxbMTA3LDFdLFsxMDcsMl0sWzEwNCwyXSxbMTA0LDFdLFsxMTMsNF0sWzEzOCw3XSxbMTQzLDNdLFs1NSwzXSxbNTUsM10sWzE0NywyXSxbMTUwLDNdLFsxNTQsM10sWzE1MSwyXSxbMTUxLDJdLFsxNTEsMl0sWzE1MSwzXSxbMTUxLDRdLFsxNTEsMl0sWzE1MSw2XSxbMTUxLDFdLFs3NywxXSxbNzcsMV0sWzc3LDFdLFs2NiwyXSxbNjYsNl0sWzE2OSwxXSxbMTY5LDRdLFszNSwzXSxbMTcyLDNdLFsxNDUsMl0sWzE0NSwyXSxbMTc4LDFdLFsxNzYsMl0sWzE4MiwyXSxbMTgwLDJdLFsxODUsMV0sWzE4NSwxXSxbMTg1LDFdLFsxODYsMl0sWzE1NiwyXSxbMTU2LDJdLFsxOTAsNF0sWzE5NywxXSxbMTk3LDNdLFsxOTksMl0sWzIwMSwyXSxbMjA0LDJdLFsyMDMsMl0sWzIwNSwxXSxbMjA1LDFdLFsyMDUsMl0sWzIwNSwzXSxbMjA5LDFdLFsyMDksMV0sWzIwOSw0XSxbMjEwLDFdLFsyMTAsMV0sWzIxMCwyXSxbMjEwLDJdLFsxNzcsM10sWzE3NywzXSxbMTkxLDNdLFsxOTEsM10sWzE4OSwxXSxbMTg5LDFdLFsxOTUsMV0sWzE5NSwxXSxbMTc1LDFdLFsxNzUsMV0sWzE3NSwxXSxbMTc1LDFdLFsxNzUsMV0sWzE3NSwxXSxbMzAsMl0sWzIyMiwyXSxbMjIwLDJdLFsyMjYsMl0sWzIyNCwxXSxbMjI0LDNdLFsyMjQsNF0sWzIyOCwyXSxbMjM0LDJdLFsyMzQsMl0sWzIzNCwyXSxbMjMyLDJdLFsyNDIsMl0sWzI0MCwyXSxbMjQwLDJdLFsyNDAsMl0sWzI0NSwxXSxbMjQ1LDFdLFsyNDUsMV0sWzI0NSwxXSxbMjQ1LDFdLFsyNDUsMV0sWzc1LDNdLFs2NSwxXSxbNjUsMl0sWzY1LDRdLFs2NSw2XSxbNjUsOF0sWzY1LDJdLFs2NSw0XSxbNjUsMl0sWzY1LDRdLFs2NSwzXSxbMjQ3LDVdLFsyNDcsNV0sWzI0Nyw2XSxbMjY2LDRdLFs5MSwxXSxbOTEsMl0sWzkxLDNdLFs5MSwxXSxbOTEsMV0sWzkxLDFdLFs5MSwxXSxbOTEsMV0sWzkxLDFdLFs5MSwxXSxbMjY5LDFdLFsyNjksMV0sWzI2OSwxXSxbMjY5LDFdLFsyMzYsMV0sWzIzNiwxXSxbMjM2LDFdLFsyMzgsMV0sWzIzOCwxXSxbMjM4LDFdLFs1MywxXSxbNTMsMV0sWzUzLDFdLFsyODcsMF0sWzI4NywxXSxbNSwxXSxbNSwxXSxbMjg4LDFdLFsyODgsMV0sWzcsMF0sWzcsMl0sWzksMV0sWzksMV0sWzksMV0sWzksMV0sWzEwLDBdLFsxMCwxXSxbMTksMF0sWzE5LDJdLFsyMywwXSxbMjMsMV0sWzI4OSwxXSxbMjg5LDFdLFsyNSwwXSxbMjUsMV0sWzI5MiwxXSxbMjkyLDJdLFsyNiwxXSxbMjYsMV0sWzM2LDBdLFszNiwyXSxbMzcsMF0sWzM3LDJdLFs0MCwwXSxbNDAsMV0sWzI5NCwxXSxbMjk0LDFdLFsyOTUsMV0sWzI5NSwyXSxbNDQsMV0sWzQ0LDFdLFs0NSwwXSxbNDUsMl0sWzQ2LDBdLFs0NiwxXSxbNDksMF0sWzQ5LDJdLFs1MiwwXSxbNTIsMV0sWzU0LDBdLFs1NCwxXSxbNTYsMF0sWzU2LDFdLFs1NywwXSxbNTcsMV0sWzU4LDBdLFs1OCwxXSxbNTksMF0sWzU5LDFdLFs2MywxXSxbNjMsMl0sWzY5LDFdLFs2OSwyXSxbNzIsMV0sWzcyLDJdLFs4NSwwXSxbODUsMl0sWzg3LDBdLFs4NywyXSxbODgsMV0sWzg4LDJdLFs4OSwwXSxbODksMl0sWzk0LDFdLFs5NCwyXSxbOTYsMF0sWzk2LDRdLFs5OCwwXSxbOTgsMl0sWzEwMCwwXSxbMTAwLDFdLFsxMDEsMF0sWzEwMSwxXSxbMTAyLDFdLFsxMDIsMV0sWzEwMywwXSxbMTAzLDFdLFsxMDUsMV0sWzEwNSwxXSxbMTA1LDFdLFsxMDYsMF0sWzEwNiwxXSxbMTEwLDBdLFsxMTAsMV0sWzExNiwwXSxbMTE2LDFdLFsxMTgsMF0sWzExOCwxXSxbMTE5LDBdLFsxMTksMl0sWzEyMCwwXSxbMTIwLDFdLFsxMjIsMF0sWzEyMiwxXSxbMTIzLDBdLFsxMjMsMl0sWzEyOCwwXSxbMTI4LDFdLFsxMzQsMF0sWzEzNCwxXSxbMTM1LDFdLFsxMzUsMV0sWzEzNSwxXSxbMTM2LDBdLFsxMzYsMV0sWzEzNywwXSxbMTM3LDJdLFsxMzksMV0sWzEzOSwxXSxbMTQwLDBdLFsxNDAsMV0sWzE0MSwwXSxbMTQxLDFdLFsxNDIsMF0sWzE0MiwxXSxbMTQ0LDBdLFsxNDQsM10sWzE0NiwwXSxbMTQ2LDFdLFsxNDgsMF0sWzE0OCwxXSxbMTQ5LDBdLFsxNDksMl0sWzE1MiwwXSxbMTUyLDFdLFsxNTMsMF0sWzE1MywxXSxbMTU1LDBdLFsxNTUsM10sWzE1NywwXSxbMTU3LDFdLFsxNTgsMF0sWzE1OCwzXSxbMTYxLDFdLFsxNjEsMV0sWzE2MywwXSxbMTYzLDFdLFsxNjQsMV0sWzE2NCwxXSxbMTY3LDBdLFsxNjcsMV0sWzE2OCwwXSxbMTY4LDNdLFsxNzAsMF0sWzE3MCwzXSxbMTcxLDBdLFsxNzEsMV0sWzE3MywwXSxbMTczLDNdLFsxNzQsMF0sWzE3NCwxXSxbMTc5LDBdLFsxNzksMV0sWzE4MSwwXSxbMTgxLDJdLFsxODQsMF0sWzE4NCwxXSxbMTg4LDBdLFsxODgsM10sWzE5MiwwXSxbMTkyLDFdLFsxOTMsMV0sWzE5MywxXSxbMTk0LDBdLFsxOTQsM10sWzE5NiwwXSxbMTk2LDJdLFsxOTgsMV0sWzE5OCwxXSxbMjAwLDBdLFsyMDAsM10sWzIwMiwwXSxbMjAyLDNdLFszMDgsMV0sWzMwOCwxXSxbMzA4LDFdLFsyMDYsMF0sWzIwNiwxXSxbMjA3LDBdLFsyMDcsMV0sWzIxMSwwXSxbMjExLDNdLFsyMTIsMF0sWzIxMiwxXSxbMjE0LDFdLFsyMTQsMl0sWzIxNywxXSxbMjE3LDJdLFsyMjEsMF0sWzIyMSwyXSxbMjI1LDBdLFsyMjUsMl0sWzIyOSwxXSxbMjI5LDFdLFsyMjksMV0sWzIyOSwxXSxbMjI5LDFdLFsyMjksMV0sWzIzMCwwXSxbMjMwLDFdLFsyMzMsMF0sWzIzMywyXSxbMjM1LDFdLFsyMzUsMV0sWzIzNywwXSxbMjM3LDJdLFsyMzksMF0sWzIzOSwyXSxbMjQxLDBdLFsyNDEsMl0sWzI0MywxXSxbMjQzLDFdLFsyNDQsMF0sWzI0NCwxXSxbMjUzLDFdLFsyNTMsMV0sWzI1MywxXSxbMjUzLDFdLFsyNTMsMV0sWzI1NiwwXSxbMjU2LDFdLFsyNTksMF0sWzI1OSwxXSxbMjYwLDFdLFsyNjAsMV0sWzI2MiwwXSxbMjYyLDFdLFsyNjQsMF0sWzI2NCwxXSxbMjY1LDBdLFsyNjUsMV1dLFxucGVyZm9ybUFjdGlvbjogZnVuY3Rpb24gYW5vbnltb3VzKHl5dGV4dCwgeXlsZW5nLCB5eWxpbmVubywgeXksIHl5c3RhdGUgLyogYWN0aW9uWzFdICovLCAkJCAvKiB2c3RhY2sgKi8sIF8kIC8qIGxzdGFjayAqLykge1xuLyogdGhpcyA9PSB5eXZhbCAqL1xuXG52YXIgJDAgPSAkJC5sZW5ndGggLSAxO1xuc3dpdGNoICh5eXN0YXRlKSB7XG5jYXNlIDE6XG5cbiAgICAgICQkWyQwLTFdID0gJCRbJDAtMV0gfHwge307XG4gICAgICBpZiAoUGFyc2VyLmJhc2UpXG4gICAgICAgICQkWyQwLTFdLmJhc2UgPSBQYXJzZXIuYmFzZTtcbiAgICAgIFBhcnNlci5iYXNlID0gYmFzZSA9IGJhc2VQYXRoID0gYmFzZVJvb3QgPSAnJztcbiAgICAgICQkWyQwLTFdLnByZWZpeGVzID0gUGFyc2VyLnByZWZpeGVzO1xuICAgICAgUGFyc2VyLnByZWZpeGVzID0gbnVsbDtcbiAgICAgIHJldHVybiAkJFskMC0xXTtcbiAgICBcbmJyZWFrO1xuY2FzZSAzOlxudGhpcy4kID0gZXh0ZW5kKCQkWyQwLTFdLCAkJFskMF0sIHsgdHlwZTogJ3F1ZXJ5JyB9KTtcbmJyZWFrO1xuY2FzZSA0OlxuXG4gICAgICBQYXJzZXIuYmFzZSA9IHJlc29sdmVJUkkoJCRbJDBdKVxuICAgICAgYmFzZSA9IGJhc2VQYXRoID0gYmFzZVJvb3QgPSAnJztcbiAgICBcbmJyZWFrO1xuY2FzZSA1OlxuXG4gICAgICBpZiAoIVBhcnNlci5wcmVmaXhlcykgUGFyc2VyLnByZWZpeGVzID0ge307XG4gICAgICAkJFskMC0xXSA9ICQkWyQwLTFdLnN1YnN0cigwLCAkJFskMC0xXS5sZW5ndGggLSAxKTtcbiAgICAgICQkWyQwXSA9IHJlc29sdmVJUkkoJCRbJDBdKTtcbiAgICAgIFBhcnNlci5wcmVmaXhlc1skJFskMC0xXV0gPSAkJFskMF07XG4gICAgXG5icmVhaztcbmNhc2UgNjpcbnRoaXMuJCA9IGV4dGVuZCgkJFskMC0zXSwgZ3JvdXBEYXRhc2V0cygkJFskMC0yXSksICQkWyQwLTFdLCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDc6XG50aGlzLiQgPSBleHRlbmQoJCRbJDAtM10sICQkWyQwLTJdLCAkJFskMC0xXSwgJCRbJDBdLCB7IHR5cGU6ICdxdWVyeScgfSk7XG5icmVhaztcbmNhc2UgODpcbnRoaXMuJCA9IGV4dGVuZCh7IHF1ZXJ5VHlwZTogJ1NFTEVDVCcsIHZhcmlhYmxlczogJCRbJDBdID09PSAnKicgPyBbJyonXSA6ICQkWyQwXSB9LCAkJFskMC0xXSAmJiAoJCRbJDAtMl0gPSBsb3dlcmNhc2UoJCRbJDAtMV0pLCAkJFskMC0xXSA9IHt9LCAkJFskMC0xXVskJFskMC0yXV0gPSB0cnVlLCAkJFskMC0xXSkpO1xuYnJlYWs7XG5jYXNlIDk6IGNhc2UgOTI6IGNhc2UgMTI0OiBjYXNlIDE1MTpcbnRoaXMuJCA9IHRvVmFyKCQkWyQwXSk7XG5icmVhaztcbmNhc2UgMTA6IGNhc2UgMjI6XG50aGlzLiQgPSBleHByZXNzaW9uKCQkWyQwLTNdLCB7IHZhcmlhYmxlOiB0b1ZhcigkJFskMC0xXSkgfSk7XG5icmVhaztcbmNhc2UgMTE6XG50aGlzLiQgPSBleHRlbmQoeyBxdWVyeVR5cGU6ICdDT05TVFJVQ1QnLCB0ZW1wbGF0ZTogJCRbJDAtM10gfSwgZ3JvdXBEYXRhc2V0cygkJFskMC0yXSksICQkWyQwLTFdLCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDEyOlxudGhpcy4kID0gZXh0ZW5kKHsgcXVlcnlUeXBlOiAnQ09OU1RSVUNUJywgdGVtcGxhdGU6ICQkWyQwLTJdID0gKCQkWyQwLTJdID8gJCRbJDAtMl0udHJpcGxlcyA6IFtdKSB9LCBncm91cERhdGFzZXRzKCQkWyQwLTVdKSwgeyB3aGVyZTogWyB7IHR5cGU6ICdiZ3AnLCB0cmlwbGVzOiBhcHBlbmRBbGxUbyhbXSwgJCRbJDAtMl0pIH0gXSB9LCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDEzOlxudGhpcy4kID0gZXh0ZW5kKHsgcXVlcnlUeXBlOiAnREVTQ1JJQkUnLCB2YXJpYWJsZXM6ICQkWyQwLTNdID09PSAnKicgPyBbJyonXSA6ICQkWyQwLTNdLm1hcCh0b1ZhcikgfSwgZ3JvdXBEYXRhc2V0cygkJFskMC0yXSksICQkWyQwLTFdLCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDE0OlxudGhpcy4kID0gZXh0ZW5kKHsgcXVlcnlUeXBlOiAnQVNLJyB9LCBncm91cERhdGFzZXRzKCQkWyQwLTJdKSwgJCRbJDAtMV0sICQkWyQwXSk7XG5icmVhaztcbmNhc2UgMTU6IGNhc2UgNTQ6XG50aGlzLiQgPSB7IGlyaTogJCRbJDBdLCBuYW1lZDogISEkJFskMC0xXSB9O1xuYnJlYWs7XG5jYXNlIDE2OlxudGhpcy4kID0geyB3aGVyZTogJCRbJDBdLnBhdHRlcm5zIH07XG5icmVhaztcbmNhc2UgMTc6XG50aGlzLiQgPSBleHRlbmQoJCRbJDAtM10sICQkWyQwLTJdLCAkJFskMC0xXSwgJCRbJDBdKTtcbmJyZWFrO1xuY2FzZSAxODpcbnRoaXMuJCA9IHsgZ3JvdXA6ICQkWyQwXSB9O1xuYnJlYWs7XG5jYXNlIDE5OiBjYXNlIDIwOiBjYXNlIDI2OiBjYXNlIDI4OlxudGhpcy4kID0gZXhwcmVzc2lvbigkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDIxOlxudGhpcy4kID0gZXhwcmVzc2lvbigkJFskMC0xXSk7XG5icmVhaztcbmNhc2UgMjM6IGNhc2UgMjk6XG50aGlzLiQgPSBleHByZXNzaW9uKHRvVmFyKCQkWyQwXSkpO1xuYnJlYWs7XG5jYXNlIDI0OlxudGhpcy4kID0geyBoYXZpbmc6ICQkWyQwXSB9O1xuYnJlYWs7XG5jYXNlIDI1OlxudGhpcy4kID0geyBvcmRlcjogJCRbJDBdIH07XG5icmVhaztcbmNhc2UgMjc6XG50aGlzLiQgPSBleHByZXNzaW9uKCQkWyQwXSwgeyBkZXNjZW5kaW5nOiB0cnVlIH0pO1xuYnJlYWs7XG5jYXNlIDMwOlxudGhpcy4kID0geyBsaW1pdDogIHRvSW50KCQkWyQwXSkgfTtcbmJyZWFrO1xuY2FzZSAzMTpcbnRoaXMuJCA9IHsgb2Zmc2V0OiB0b0ludCgkJFskMF0pIH07XG5icmVhaztcbmNhc2UgMzI6XG50aGlzLiQgPSB7IGxpbWl0OiB0b0ludCgkJFskMC0yXSksIG9mZnNldDogdG9JbnQoJCRbJDBdKSB9O1xuYnJlYWs7XG5jYXNlIDMzOlxudGhpcy4kID0geyBsaW1pdDogdG9JbnQoJCRbJDBdKSwgb2Zmc2V0OiB0b0ludCgkJFskMC0yXSkgfTtcbmJyZWFrO1xuY2FzZSAzNDpcbnRoaXMuJCA9IHsgdHlwZTogJ3ZhbHVlcycsIHZhbHVlczogJCRbJDBdIH07XG5icmVhaztcbmNhc2UgMzU6XG5cbiAgICAgICQkWyQwLTNdID0gdG9WYXIoJCRbJDAtM10pO1xuICAgICAgdGhpcy4kID0gJCRbJDAtMV0ubWFwKGZ1bmN0aW9uKHYpIHsgdmFyIG8gPSB7fTsgb1skJFskMC0zXV0gPSB2OyByZXR1cm4gbzsgfSlcbiAgICBcbmJyZWFrO1xuY2FzZSAzNjpcblxuICAgICAgdGhpcy4kID0gJCRbJDAtMV0ubWFwKGZ1bmN0aW9uKCkgeyByZXR1cm4ge307IH0pXG4gICAgXG5icmVhaztcbmNhc2UgMzc6XG5cbiAgICAgIHZhciBsZW5ndGggPSAkJFskMC00XS5sZW5ndGg7XG4gICAgICAkJFskMC00XSA9ICQkWyQwLTRdLm1hcCh0b1Zhcik7XG4gICAgICB0aGlzLiQgPSAkJFskMC0xXS5tYXAoZnVuY3Rpb24gKHZhbHVlcykge1xuICAgICAgICBpZiAodmFsdWVzLmxlbmd0aCAhPT0gbGVuZ3RoKVxuICAgICAgICAgIHRocm93IEVycm9yKCdJbmNvbnNpc3RlbnQgVkFMVUVTIGxlbmd0aCcpO1xuICAgICAgICB2YXIgdmFsdWVzT2JqZWN0ID0ge307XG4gICAgICAgIGZvcih2YXIgaSA9IDA7IGk8bGVuZ3RoOyBpKyspXG4gICAgICAgICAgdmFsdWVzT2JqZWN0WyQkWyQwLTRdW2ldXSA9IHZhbHVlc1tpXTtcbiAgICAgICAgcmV0dXJuIHZhbHVlc09iamVjdDtcbiAgICAgIH0pO1xuICAgIFxuYnJlYWs7XG5jYXNlIDQwOlxudGhpcy4kID0gdW5kZWZpbmVkO1xuYnJlYWs7XG5jYXNlIDQxOiBjYXNlIDg0OiBjYXNlIDEwODogY2FzZSAxNTI6XG50aGlzLiQgPSAkJFskMC0xXTtcbmJyZWFrO1xuY2FzZSA0MjpcbnRoaXMuJCA9IHsgdHlwZTogJ3VwZGF0ZScsIHVwZGF0ZXM6IGFwcGVuZFRvKCQkWyQwLTJdLCAkJFskMC0xXSkgfTtcbmJyZWFrO1xuY2FzZSA0MzpcbnRoaXMuJCA9IGV4dGVuZCh7IHR5cGU6ICdsb2FkJywgc2lsZW50OiAhISQkWyQwLTJdLCBzb3VyY2U6ICQkWyQwLTFdIH0sICQkWyQwXSAmJiB7IGRlc3RpbmF0aW9uOiAkJFskMF0gfSk7XG5icmVhaztcbmNhc2UgNDQ6XG50aGlzLiQgPSB7IHR5cGU6IGxvd2VyY2FzZSgkJFskMC0yXSksIHNpbGVudDogISEkJFskMC0xXSwgZ3JhcGg6ICQkWyQwXSB9O1xuYnJlYWs7XG5jYXNlIDQ1OlxudGhpcy4kID0geyB0eXBlOiBsb3dlcmNhc2UoJCRbJDAtNF0pLCBzaWxlbnQ6ICEhJCRbJDAtM10sIHNvdXJjZTogJCRbJDAtMl0sIGRlc3RpbmF0aW9uOiAkJFskMF0gfTtcbmJyZWFrO1xuY2FzZSA0NjpcbnRoaXMuJCA9IHsgdHlwZTogJ2NyZWF0ZScsIHNpbGVudDogISEkJFskMC0yXSwgZ3JhcGg6IHsgdHlwZTogJ2dyYXBoJywgbmFtZTogJCRbJDBdIH0gfTtcbmJyZWFrO1xuY2FzZSA0NzpcbnRoaXMuJCA9IHsgdXBkYXRlVHlwZTogJ2luc2VydCcsICAgICAgaW5zZXJ0OiAkJFskMF0gfTtcbmJyZWFrO1xuY2FzZSA0ODpcbnRoaXMuJCA9IHsgdXBkYXRlVHlwZTogJ2RlbGV0ZScsICAgICAgZGVsZXRlOiAkJFskMF0gfTtcbmJyZWFrO1xuY2FzZSA0OTpcbnRoaXMuJCA9IHsgdXBkYXRlVHlwZTogJ2RlbGV0ZXdoZXJlJywgZGVsZXRlOiAkJFskMF0gfTtcbmJyZWFrO1xuY2FzZSA1MDpcbnRoaXMuJCA9IGV4dGVuZCh7IHVwZGF0ZVR5cGU6ICdpbnNlcnRkZWxldGUnIH0sICQkWyQwLTVdLCB7IGluc2VydDogJCRbJDAtNF0gfHwgW10gfSwgeyBkZWxldGU6ICQkWyQwLTNdIHx8IFtdIH0sIGdyb3VwRGF0YXNldHMoJCRbJDAtMl0pLCB7IHdoZXJlOiAkJFskMF0ucGF0dGVybnMgfSk7XG5icmVhaztcbmNhc2UgNTE6XG50aGlzLiQgPSBleHRlbmQoeyB1cGRhdGVUeXBlOiAnaW5zZXJ0ZGVsZXRlJyB9LCAkJFskMC01XSwgeyBkZWxldGU6ICQkWyQwLTRdIHx8IFtdIH0sIHsgaW5zZXJ0OiAkJFskMC0zXSB8fCBbXSB9LCBncm91cERhdGFzZXRzKCQkWyQwLTJdKSwgeyB3aGVyZTogJCRbJDBdLnBhdHRlcm5zIH0pO1xuYnJlYWs7XG5jYXNlIDUyOiBjYXNlIDUzOiBjYXNlIDU2OiBjYXNlIDE0MzpcbnRoaXMuJCA9ICQkWyQwXTtcbmJyZWFrO1xuY2FzZSA1NTpcbnRoaXMuJCA9IHsgZ3JhcGg6ICQkWyQwXSB9O1xuYnJlYWs7XG5jYXNlIDU3OlxudGhpcy4kID0geyB0eXBlOiAnZ3JhcGgnLCBkZWZhdWx0OiB0cnVlIH07XG5icmVhaztcbmNhc2UgNTg6IGNhc2UgNTk6XG50aGlzLiQgPSB7IHR5cGU6ICdncmFwaCcsIG5hbWU6ICQkWyQwXSB9O1xuYnJlYWs7XG5jYXNlIDYwOlxuIHRoaXMuJCA9IHt9OyB0aGlzLiRbbG93ZXJjYXNlKCQkWyQwXSldID0gdHJ1ZTsgXG5icmVhaztcbmNhc2UgNjE6XG50aGlzLiQgPSAkJFskMC0yXSA/IHVuaW9uQWxsKCQkWyQwLTFdLCBbJCRbJDAtMl1dKSA6IHVuaW9uQWxsKCQkWyQwLTFdKTtcbmJyZWFrO1xuY2FzZSA2MjpcblxuICAgICAgdmFyIGdyYXBoID0gZXh0ZW5kKCQkWyQwLTNdIHx8IHsgdHJpcGxlczogW10gfSwgeyB0eXBlOiAnZ3JhcGgnLCBuYW1lOiB0b1ZhcigkJFskMC01XSkgfSk7XG4gICAgICB0aGlzLiQgPSAkJFskMF0gPyBbZ3JhcGgsICQkWyQwXV0gOiBbZ3JhcGhdO1xuICAgIFxuYnJlYWs7XG5jYXNlIDYzOiBjYXNlIDY4OlxudGhpcy4kID0geyB0eXBlOiAnYmdwJywgdHJpcGxlczogdW5pb25BbGwoJCRbJDAtMl0sIFskJFskMC0xXV0pIH07XG5icmVhaztcbmNhc2UgNjQ6XG50aGlzLiQgPSB7IHR5cGU6ICdncm91cCcsIHBhdHRlcm5zOiBbICQkWyQwLTFdIF0gfTtcbmJyZWFrO1xuY2FzZSA2NTpcbnRoaXMuJCA9IHsgdHlwZTogJ2dyb3VwJywgcGF0dGVybnM6ICQkWyQwLTFdIH07XG5icmVhaztcbmNhc2UgNjY6XG50aGlzLiQgPSAkJFskMC0xXSA/IHVuaW9uQWxsKFskJFskMC0xXV0sICQkWyQwXSkgOiB1bmlvbkFsbCgkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDY3OlxudGhpcy4kID0gJCRbJDBdID8gWyQkWyQwLTJdLCAkJFskMF1dIDogJCRbJDAtMl07XG5icmVhaztcbmNhc2UgNjk6XG5cbiAgICAgIGlmICgkJFskMC0xXS5sZW5ndGgpXG4gICAgICAgIHRoaXMuJCA9IHsgdHlwZTogJ3VuaW9uJywgcGF0dGVybnM6IHVuaW9uQWxsKCQkWyQwLTFdLm1hcChkZWdyb3VwU2luZ2xlKSwgW2RlZ3JvdXBTaW5nbGUoJCRbJDBdKV0pIH07XG4gICAgICBlbHNlXG4gICAgICAgIHRoaXMuJCA9ICQkWyQwXTtcbiAgICBcbmJyZWFrO1xuY2FzZSA3MDpcbnRoaXMuJCA9IGV4dGVuZCgkJFskMF0sIHsgdHlwZTogJ29wdGlvbmFsJyB9KTtcbmJyZWFrO1xuY2FzZSA3MTpcbnRoaXMuJCA9IGV4dGVuZCgkJFskMF0sIHsgdHlwZTogJ21pbnVzJyB9KTtcbmJyZWFrO1xuY2FzZSA3MjpcbnRoaXMuJCA9IGV4dGVuZCgkJFskMF0sIHsgdHlwZTogJ2dyYXBoJywgbmFtZTogdG9WYXIoJCRbJDAtMV0pIH0pO1xuYnJlYWs7XG5jYXNlIDczOlxudGhpcy4kID0gZXh0ZW5kKCQkWyQwXSwgeyB0eXBlOiAnc2VydmljZScsIG5hbWU6IHRvVmFyKCQkWyQwLTFdKSwgc2lsZW50OiAhISQkWyQwLTJdIH0pO1xuYnJlYWs7XG5jYXNlIDc0OlxudGhpcy4kID0geyB0eXBlOiAnZmlsdGVyJywgZXhwcmVzc2lvbjogJCRbJDBdIH07XG5icmVhaztcbmNhc2UgNzU6XG50aGlzLiQgPSB7IHR5cGU6ICdiaW5kJywgdmFyaWFibGU6IHRvVmFyKCQkWyQwLTFdKSwgZXhwcmVzc2lvbjogJCRbJDAtM10gfTtcbmJyZWFrO1xuY2FzZSA4MDpcbnRoaXMuJCA9IHsgdHlwZTogJ2Z1bmN0aW9uQ2FsbCcsIGZ1bmN0aW9uOiAkJFskMC0xXSwgYXJnczogW10gfTtcbmJyZWFrO1xuY2FzZSA4MTpcbnRoaXMuJCA9IHsgdHlwZTogJ2Z1bmN0aW9uQ2FsbCcsIGZ1bmN0aW9uOiAkJFskMC01XSwgYXJnczogYXBwZW5kVG8oJCRbJDAtMl0sICQkWyQwLTFdKSwgZGlzdGluY3Q6ICEhJCRbJDAtM10gfTtcbmJyZWFrO1xuY2FzZSA4MjogY2FzZSA5OTogY2FzZSAxMTA6IGNhc2UgMTk2OiBjYXNlIDIwNDogY2FzZSAyMTY6IGNhc2UgMjE4OiBjYXNlIDIyODogY2FzZSAyMzI6IGNhc2UgMjUyOiBjYXNlIDI1NDogY2FzZSAyNTg6IGNhc2UgMjYyOiBjYXNlIDI4NTogY2FzZSAyOTE6IGNhc2UgMzAyOiBjYXNlIDMxMjogY2FzZSAzMTg6IGNhc2UgMzI0OiBjYXNlIDMyODogY2FzZSAzMzg6IGNhc2UgMzQwOiBjYXNlIDM0NDogY2FzZSAzNTA6IGNhc2UgMzU0OiBjYXNlIDM2MDogY2FzZSAzNjI6IGNhc2UgMzY2OiBjYXNlIDM2ODogY2FzZSAzNzc6IGNhc2UgMzg1OiBjYXNlIDM4NzogY2FzZSAzOTc6IGNhc2UgNDAxOiBjYXNlIDQwMzogY2FzZSA0MDU6XG50aGlzLiQgPSBbXTtcbmJyZWFrO1xuY2FzZSA4MzpcbnRoaXMuJCA9IGFwcGVuZFRvKCQkWyQwLTJdLCAkJFskMC0xXSk7XG5icmVhaztcbmNhc2UgODU6XG50aGlzLiQgPSB1bmlvbkFsbCgkJFskMC0yXSwgWyQkWyQwLTFdXSk7XG5icmVhaztcbmNhc2UgODY6IGNhc2UgOTY6XG50aGlzLiQgPSAkJFskMF0ubWFwKGZ1bmN0aW9uICh0KSB7IHJldHVybiBleHRlbmQodHJpcGxlKCQkWyQwLTFdKSwgdCk7IH0pO1xuYnJlYWs7XG5jYXNlIDg3OlxudGhpcy4kID0gYXBwZW5kQWxsVG8oJCRbJDBdLm1hcChmdW5jdGlvbiAodCkgeyByZXR1cm4gZXh0ZW5kKHRyaXBsZSgkJFskMC0xXS5lbnRpdHkpLCB0KTsgfSksICQkWyQwLTFdLnRyaXBsZXMpIC8qIHRoZSBzdWJqZWN0IGlzIGEgYmxhbmsgbm9kZSwgcG9zc2libHkgd2l0aCBtb3JlIHRyaXBsZXMgKi87XG5icmVhaztcbmNhc2UgODk6XG50aGlzLiQgPSB1bmlvbkFsbChbJCRbJDAtMV1dLCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDkwOlxudGhpcy4kID0gdW5pb25BbGwoJCRbJDBdKTtcbmJyZWFrO1xuY2FzZSA5MTpcbnRoaXMuJCA9IG9iamVjdExpc3RUb1RyaXBsZXMoJCRbJDAtMV0sICQkWyQwXSk7XG5icmVhaztcbmNhc2UgOTQ6IGNhc2UgMTA2OiBjYXNlIDExMzpcbnRoaXMuJCA9IFJERl9UWVBFO1xuYnJlYWs7XG5jYXNlIDk1OlxudGhpcy4kID0gYXBwZW5kVG8oJCRbJDAtMV0sICQkWyQwXSk7XG5icmVhaztcbmNhc2UgOTc6XG50aGlzLiQgPSAhJCRbJDBdID8gJCRbJDAtMV0udHJpcGxlcyA6IGFwcGVuZEFsbFRvKCQkWyQwXS5tYXAoZnVuY3Rpb24gKHQpIHsgcmV0dXJuIGV4dGVuZCh0cmlwbGUoJCRbJDAtMV0uZW50aXR5KSwgdCk7IH0pLCAkJFskMC0xXS50cmlwbGVzKSAvKiB0aGUgc3ViamVjdCBpcyBhIGJsYW5rIG5vZGUsIHBvc3NpYmx5IHdpdGggbW9yZSB0cmlwbGVzICovO1xuYnJlYWs7XG5jYXNlIDk4OlxudGhpcy4kID0gb2JqZWN0TGlzdFRvVHJpcGxlcyh0b1ZhcigkJFskMC0zXSksIGFwcGVuZFRvKCQkWyQwLTJdLCAkJFskMC0xXSksICQkWyQwXSk7XG5icmVhaztcbmNhc2UgMTAwOlxudGhpcy4kID0gb2JqZWN0TGlzdFRvVHJpcGxlcyh0b1ZhcigkJFskMC0xXSksICQkWyQwXSk7XG5icmVhaztcbmNhc2UgMTAxOlxudGhpcy4kID0gJCRbJDAtMV0ubGVuZ3RoID8gcGF0aCgnfCcsYXBwZW5kVG8oJCRbJDAtMV0sICQkWyQwXSkpIDogJCRbJDBdO1xuYnJlYWs7XG5jYXNlIDEwMjpcbnRoaXMuJCA9ICQkWyQwLTFdLmxlbmd0aCA/IHBhdGgoJy8nLCBhcHBlbmRUbygkJFskMC0xXSwgJCRbJDBdKSkgOiAkJFskMF07XG5icmVhaztcbmNhc2UgMTAzOlxudGhpcy4kID0gJCRbJDBdID8gcGF0aCgkJFskMF0sIFskJFskMC0xXV0pIDogJCRbJDAtMV07XG5icmVhaztcbmNhc2UgMTA0OlxudGhpcy4kID0gJCRbJDAtMV0gPyBwYXRoKCQkWyQwLTFdLCBbJCRbJDBdXSkgOiAkJFskMF07O1xuYnJlYWs7XG5jYXNlIDEwNzogY2FzZSAxMTQ6XG50aGlzLiQgPSBwYXRoKCQkWyQwLTFdLCBbJCRbJDBdXSk7XG5icmVhaztcbmNhc2UgMTExOlxudGhpcy4kID0gcGF0aCgnfCcsIGFwcGVuZFRvKCQkWyQwLTJdLCAkJFskMC0xXSkpO1xuYnJlYWs7XG5jYXNlIDExNTpcbnRoaXMuJCA9IHBhdGgoJCRbJDAtMV0sIFtSREZfVFlQRV0pO1xuYnJlYWs7XG5jYXNlIDExNjogY2FzZSAxMTg6XG50aGlzLiQgPSBjcmVhdGVMaXN0KCQkWyQwLTFdKTtcbmJyZWFrO1xuY2FzZSAxMTc6IGNhc2UgMTE5OlxudGhpcy4kID0gY3JlYXRlQW5vbnltb3VzT2JqZWN0KCQkWyQwLTFdKTtcbmJyZWFrO1xuY2FzZSAxMjA6XG50aGlzLiQgPSB7IGVudGl0eTogJCRbJDBdLCB0cmlwbGVzOiBbXSB9IC8qIGZvciBjb25zaXN0ZW5jeSB3aXRoIFRyaXBsZXNOb2RlICovO1xuYnJlYWs7XG5jYXNlIDEyMjpcbnRoaXMuJCA9IHsgZW50aXR5OiAkJFskMF0sIHRyaXBsZXM6IFtdIH0gLyogZm9yIGNvbnNpc3RlbmN5IHdpdGggVHJpcGxlc05vZGVQYXRoICovO1xuYnJlYWs7XG5jYXNlIDEyODpcbnRoaXMuJCA9IGJsYW5rKCk7XG5icmVhaztcbmNhc2UgMTI5OlxudGhpcy4kID0gUkRGX05JTDtcbmJyZWFrO1xuY2FzZSAxMzA6IGNhc2UgMTMyOiBjYXNlIDEzNzogY2FzZSAxNDE6XG50aGlzLiQgPSBjcmVhdGVPcGVyYXRpb25UcmVlKCQkWyQwLTFdLCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDEzMTpcbnRoaXMuJCA9IFsnfHwnLCAkJFskMF1dO1xuYnJlYWs7XG5jYXNlIDEzMzpcbnRoaXMuJCA9IFsnJiYnLCAkJFskMF1dO1xuYnJlYWs7XG5jYXNlIDEzNTpcbnRoaXMuJCA9IG9wZXJhdGlvbigkJFskMC0xXSwgWyQkWyQwLTJdLCAkJFskMF1dKTtcbmJyZWFrO1xuY2FzZSAxMzY6XG50aGlzLiQgPSBvcGVyYXRpb24oJCRbJDAtMl0gPyAnbm90aW4nIDogJ2luJywgWyQkWyQwLTNdLCAkJFskMF1dKTtcbmJyZWFrO1xuY2FzZSAxMzg6IGNhc2UgMTQyOlxudGhpcy4kID0gWyQkWyQwLTFdLCAkJFskMF1dO1xuYnJlYWs7XG5jYXNlIDEzOTpcbnRoaXMuJCA9IFsnKycsIGNyZWF0ZU9wZXJhdGlvblRyZWUoJCRbJDAtMV0sICQkWyQwXSldO1xuYnJlYWs7XG5jYXNlIDE0MDpcbnRoaXMuJCA9IFsnLScsIGNyZWF0ZU9wZXJhdGlvblRyZWUoJCRbJDAtMV0ucmVwbGFjZSgnLScsICcnKSwgJCRbJDBdKV07XG5icmVhaztcbmNhc2UgMTQ0OlxudGhpcy4kID0gb3BlcmF0aW9uKCQkWyQwLTFdLCBbJCRbJDBdXSk7XG5icmVhaztcbmNhc2UgMTQ1OlxudGhpcy4kID0gb3BlcmF0aW9uKCdVTUlOVVMnLCBbJCRbJDBdXSk7XG5icmVhaztcbmNhc2UgMTU0OlxudGhpcy4kID0gb3BlcmF0aW9uKGxvd2VyY2FzZSgkJFskMC0xXSkpO1xuYnJlYWs7XG5jYXNlIDE1NTpcbnRoaXMuJCA9IG9wZXJhdGlvbihsb3dlcmNhc2UoJCRbJDAtM10pLCBbJCRbJDAtMV1dKTtcbmJyZWFrO1xuY2FzZSAxNTY6XG50aGlzLiQgPSBvcGVyYXRpb24obG93ZXJjYXNlKCQkWyQwLTVdKSwgWyQkWyQwLTNdLCAkJFskMC0xXV0pO1xuYnJlYWs7XG5jYXNlIDE1NzpcbnRoaXMuJCA9IG9wZXJhdGlvbihsb3dlcmNhc2UoJCRbJDAtN10pLCBbJCRbJDAtNV0sICQkWyQwLTNdLCAkJFskMC0xXV0pO1xuYnJlYWs7XG5jYXNlIDE1ODpcbnRoaXMuJCA9IG9wZXJhdGlvbihsb3dlcmNhc2UoJCRbJDAtMV0pLCAkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDE1OTpcbnRoaXMuJCA9IG9wZXJhdGlvbignYm91bmQnLCBbdG9WYXIoJCRbJDAtMV0pXSk7XG5icmVhaztcbmNhc2UgMTYwOlxudGhpcy4kID0gb3BlcmF0aW9uKCQkWyQwLTFdLCBbXSk7XG5icmVhaztcbmNhc2UgMTYxOlxudGhpcy4kID0gb3BlcmF0aW9uKCQkWyQwLTNdLCBbJCRbJDAtMV1dKTtcbmJyZWFrO1xuY2FzZSAxNjI6XG50aGlzLiQgPSBvcGVyYXRpb24oJCRbJDAtMl0gPyAnbm90ZXhpc3RzJyA6J2V4aXN0cycsIFtkZWdyb3VwU2luZ2xlKCQkWyQwXSldKTtcbmJyZWFrO1xuY2FzZSAxNjM6IGNhc2UgMTY0OlxudGhpcy4kID0gZXhwcmVzc2lvbigkJFskMC0xXSwgeyB0eXBlOiAnYWdncmVnYXRlJywgYWdncmVnYXRpb246IGxvd2VyY2FzZSgkJFskMC00XSksIGRpc3RpbmN0OiAhISQkWyQwLTJdIH0pO1xuYnJlYWs7XG5jYXNlIDE2NTpcbnRoaXMuJCA9IGV4cHJlc3Npb24oJCRbJDAtMl0sIHsgdHlwZTogJ2FnZ3JlZ2F0ZScsIGFnZ3JlZ2F0aW9uOiBsb3dlcmNhc2UoJCRbJDAtNV0pLCBkaXN0aW5jdDogISEkJFskMC0zXSwgc2VwYXJhdG9yOiAkJFskMC0xXSB8fCAnICcgfSk7XG5icmVhaztcbmNhc2UgMTY2OlxudGhpcy4kID0gJCRbJDBdLnN1YnN0cigxLCAkJFskMF0ubGVuZ3RoIC0gMik7XG5icmVhaztcbmNhc2UgMTY4OlxudGhpcy4kID0gJCRbJDAtMV0gKyBsb3dlcmNhc2UoJCRbJDBdKTtcbmJyZWFrO1xuY2FzZSAxNjk6XG50aGlzLiQgPSAkJFskMC0yXSArICdeXicgKyAkJFskMF07XG5icmVhaztcbmNhc2UgMTcwOiBjYXNlIDE4NDpcbnRoaXMuJCA9IGNyZWF0ZUxpdGVyYWwoJCRbJDBdLCBYU0RfSU5URUdFUik7XG5icmVhaztcbmNhc2UgMTcxOiBjYXNlIDE4NTpcbnRoaXMuJCA9IGNyZWF0ZUxpdGVyYWwoJCRbJDBdLCBYU0RfREVDSU1BTCk7XG5icmVhaztcbmNhc2UgMTcyOiBjYXNlIDE4NjpcbnRoaXMuJCA9IGNyZWF0ZUxpdGVyYWwobG93ZXJjYXNlKCQkWyQwXSksIFhTRF9ET1VCTEUpO1xuYnJlYWs7XG5jYXNlIDE3NTpcbnRoaXMuJCA9IFhTRF9UUlVFO1xuYnJlYWs7XG5jYXNlIDE3NjpcbnRoaXMuJCA9IFhTRF9GQUxTRTtcbmJyZWFrO1xuY2FzZSAxNzc6IGNhc2UgMTc4OlxudGhpcy4kID0gdW5lc2NhcGVTdHJpbmcoJCRbJDBdLCAxKTtcbmJyZWFrO1xuY2FzZSAxNzk6IGNhc2UgMTgwOlxudGhpcy4kID0gdW5lc2NhcGVTdHJpbmcoJCRbJDBdLCAzKTtcbmJyZWFrO1xuY2FzZSAxODE6XG50aGlzLiQgPSBjcmVhdGVMaXRlcmFsKCQkWyQwXS5zdWJzdHIoMSksIFhTRF9JTlRFR0VSKTtcbmJyZWFrO1xuY2FzZSAxODI6XG50aGlzLiQgPSBjcmVhdGVMaXRlcmFsKCQkWyQwXS5zdWJzdHIoMSksIFhTRF9ERUNJTUFMKTtcbmJyZWFrO1xuY2FzZSAxODM6XG50aGlzLiQgPSBjcmVhdGVMaXRlcmFsKCQkWyQwXS5zdWJzdHIoMSkudG9Mb3dlckNhc2UoKSwgWFNEX0RPVUJMRSk7XG5icmVhaztcbmNhc2UgMTg3OlxudGhpcy4kID0gcmVzb2x2ZUlSSSgkJFskMF0pO1xuYnJlYWs7XG5jYXNlIDE4ODpcblxuICAgICAgdmFyIG5hbWVQb3MgPSAkJFskMF0uaW5kZXhPZignOicpLFxuICAgICAgICAgIHByZWZpeCA9ICQkWyQwXS5zdWJzdHIoMCwgbmFtZVBvcyksXG4gICAgICAgICAgZXhwYW5zaW9uID0gUGFyc2VyLnByZWZpeGVzW3ByZWZpeF07XG4gICAgICBpZiAoIWV4cGFuc2lvbikgdGhyb3cgbmV3IEVycm9yKCdVbmtub3duIHByZWZpeDogJyArIHByZWZpeCk7XG4gICAgICB0aGlzLiQgPSByZXNvbHZlSVJJKGV4cGFuc2lvbiArICQkWyQwXS5zdWJzdHIobmFtZVBvcyArIDEpKTtcbiAgICBcbmJyZWFrO1xuY2FzZSAxODk6XG5cbiAgICAgICQkWyQwXSA9ICQkWyQwXS5zdWJzdHIoMCwgJCRbJDBdLmxlbmd0aCAtIDEpO1xuICAgICAgaWYgKCEoJCRbJDBdIGluIFBhcnNlci5wcmVmaXhlcykpIHRocm93IG5ldyBFcnJvcignVW5rbm93biBwcmVmaXg6ICcgKyAkJFskMF0pO1xuICAgICAgdGhpcy4kID0gcmVzb2x2ZUlSSShQYXJzZXIucHJlZml4ZXNbJCRbJDBdXSk7XG4gICAgXG5icmVhaztcbmNhc2UgMTk3OiBjYXNlIDIwNTogY2FzZSAyMTM6IGNhc2UgMjE3OiBjYXNlIDIxOTogY2FzZSAyMjU6IGNhc2UgMjI5OiBjYXNlIDIzMzogY2FzZSAyNDc6IGNhc2UgMjQ5OiBjYXNlIDI1MTogY2FzZSAyNTM6IGNhc2UgMjU1OiBjYXNlIDI1NzogY2FzZSAyNTk6IGNhc2UgMjYxOiBjYXNlIDI4NjogY2FzZSAyOTI6IGNhc2UgMzAzOiBjYXNlIDMxOTogY2FzZSAzNTE6IGNhc2UgMzYzOiBjYXNlIDM4MjogY2FzZSAzODQ6IGNhc2UgMzg2OiBjYXNlIDM4ODogY2FzZSAzOTg6IGNhc2UgNDAyOiBjYXNlIDQwNDogY2FzZSA0MDY6XG4kJFskMC0xXS5wdXNoKCQkWyQwXSk7XG5icmVhaztcbmNhc2UgMjEyOiBjYXNlIDIyNDogY2FzZSAyNDY6IGNhc2UgMjQ4OiBjYXNlIDI1MDogY2FzZSAyNTY6IGNhc2UgMjYwOiBjYXNlIDM4MTogY2FzZSAzODM6XG50aGlzLiQgPSBbJCRbJDBdXTtcbmJyZWFrO1xuY2FzZSAyNjM6XG4kJFskMC0zXS5wdXNoKCQkWyQwLTJdKTtcbmJyZWFrO1xuY2FzZSAzMTM6IGNhc2UgMzI1OiBjYXNlIDMyOTogY2FzZSAzMzk6IGNhc2UgMzQxOiBjYXNlIDM0NTogY2FzZSAzNTU6IGNhc2UgMzYxOiBjYXNlIDM2NzogY2FzZSAzNjk6IGNhc2UgMzc4OlxuJCRbJDAtMl0ucHVzaCgkJFskMC0xXSk7XG5icmVhaztcbn1cbn0sXG50YWJsZTogW28oJFYwLCRWMSx7MzoxLDQ6Miw3OjN9KSx7MTpbM119LG8oJFYyLFsyLDI2Ml0sezU6NCw4OjUsMjg3OjYsOTo3LDk1OjgsMTc6OSwzMzoxMCw0MjoxMSw0NzoxMiw5NjoxMywxODoxNCw2OlsyLDE5MF0sMjQ6JFYzLDM0OlsxLDE1XSw0MzpbMSwxNl0sNDg6WzEsMTddfSksbyhbNiwyNCwzNCw0Myw0OCw5OSwxMDksMTEyLDExNCwxMTUsMTI0LDEyNSwxMzAsMjk4LDI5OSwzMDAsMzAxLDMwMl0sWzIsMl0sezI4ODoxOSwxMToyMCwxNDoyMSwxMjpbMSwyMl0sMTU6WzEsMjNdfSksezY6WzEsMjRdfSx7NjpbMiwxOTJdfSx7NjpbMiwxOTNdfSx7NjpbMiwyMDJdLDEwOjI1LDgyOjI2LDgzOiRWNH0sezY6WzIsMTkxXX0sbygkVjUsWzIsMTk4XSksbygkVjUsWzIsMTk5XSksbygkVjUsWzIsMjAwXSksbygkVjUsWzIsMjAxXSksezk3OjI4LDk5OlsxLDI5XSwxMDI6MzAsMTA1OjMxLDEwOTpbMSwzMl0sMTEyOlsxLDMzXSwxMTQ6WzEsMzRdLDExNTpbMSwzNV0sMTE2OjM2LDEyMDozNywxMjQ6WzIsMjg3XSwxMjU6WzIsMjgxXSwxMjk6NDMsMTMwOlsxLDQ0XSwyOTg6WzEsMzhdLDI5OTpbMSwzOV0sMzAwOlsxLDQwXSwzMDE6WzEsNDFdLDMwMjpbMSw0Ml19LG8oJFY2LFsyLDIwNF0sezE5OjQ1fSksbygkVjcsWzIsMjE4XSx7MzU6NDYsMzc6NDcsMzk6WzEsNDhdfSksezEzOiRWOCwxNjokVjksMjg6JFZhLDQ0OjQ5LDUzOjU0LDI4NjokVmIsMjkzOlsxLDUxXSwyOTQ6NTIsMjk1OjUwfSxvKCRWNixbMiwyMzJdLHs0OTo1OH0pLG8oJFZjLFsyLDIxMF0sezI1OjU5LDI4OTo2MCwyOTA6WzEsNjFdLDI5MTpbMSw2Ml19KSxvKCRWMCxbMiwxOTddKSxvKCRWMCxbMiwxOTRdKSxvKCRWMCxbMiwxOTVdKSx7MTM6WzEsNjNdfSx7MTY6WzEsNjRdfSx7MTpbMiwxXX0sezY6WzIsM119LHs2OlsyLDIwM119LHsyODpbMSw2Nl0sMjk6WzEsNjhdLDg0OjY1LDg2OlsxLDY3XX0sezY6WzIsMjY0XSw5ODo2OSwxODM6WzEsNzBdfSxvKCRWZCxbMiwyNjZdLHsxMDA6NzEsMjk3OlsxLDcyXX0pLG8oJFZlLFsyLDI3Ml0sezEwMzo3MywyOTc6WzEsNzRdfSksbygkVmYsWzIsMjc3XSx7MTA2Ojc1LDI5NzpbMSw3Nl19KSx7MTEwOjc3LDExMTpbMiwyNzldLDI5NzpbMSw3OF19LHszOTokVmcsMTEzOjc5fSx7Mzk6JFZnLDExMzo4MX0sezM5OiRWZywxMTM6ODJ9LHsxMTc6ODMsMTI1OiRWaH0sezEyMTo4NSwxMjQ6JFZpfSxvKCRWaixbMiwyNzBdKSxvKCRWaixbMiwyNzFdKSxvKCRWayxbMiwyNzRdKSxvKCRWayxbMiwyNzVdKSxvKCRWayxbMiwyNzZdKSx7MTI0OlsyLDI4OF0sMTI1OlsyLDI4Ml19LHsxMzokVjgsMTY6JFY5LDUzOjg3LDI4NjokVmJ9LHsyMDo4OCwzODokVmwsMzk6JFZtLDUwOjg5LDUxOiRWbiw1NDo5MH0sbygkVjYsWzIsMjE2XSx7MzY6OTN9KSx7Mzg6WzEsOTRdLDUwOjk1LDUxOiRWbn0sbygkVm8sWzIsMzQ0XSx7MTcxOjk2LDE3Mjo5NywxNzM6OTgsNDE6WzIsMzQyXX0pLG8oJFZwLFsyLDIyOF0sezQ1Ojk5fSksbygkVnAsWzIsMjI2XSx7NTM6NTQsMjk0OjEwMCwxMzokVjgsMTY6JFY5LDI4OiRWYSwyODY6JFZifSksbygkVnAsWzIsMjI3XSksbygkVnEsWzIsMjI0XSksbygkVnEsWzIsMjIyXSksbygkVnEsWzIsMjIzXSksbygkVnIsWzIsMTg3XSksbygkVnIsWzIsMTg4XSksbygkVnIsWzIsMTg5XSksezIwOjEwMSwzODokVmwsMzk6JFZtLDUwOjEwMiw1MTokVm4sNTQ6OTB9LHsyNjoxMDMsMjc6MTA2LDI4OiRWcywyOTokVnQsMjkyOjEwNCwyOTM6WzEsMTA1XX0sbygkVmMsWzIsMjExXSksbygkVmMsWzIsMjA4XSksbygkVmMsWzIsMjA5XSksbygkVjAsWzIsNF0pLHsxMzpbMSwxMDldfSxvKCRWdSxbMiwzNF0pLHszOTpbMSwxMTBdfSx7Mzk6WzEsMTExXX0sezI4OlsxLDExM10sODg6MTEyfSx7NjpbMiw0Ml19LG8oJFYwLCRWMSx7NzozLDQ6MTE0fSksezEzOiRWOCwxNjokVjksNTM6MTE1LDI4NjokVmJ9LG8oJFZkLFsyLDI2N10pLHsxMDQ6MTE2LDExMTpbMSwxMTddLDEzMzpbMSwxMTldLDEzNToxMTgsMjk2OlsxLDEyMF0sMzAzOlsxLDEyMV19LG8oJFZlLFsyLDI3M10pLG8oJFZkLCRWdix7MTA3OjEyMiwxMzQ6MTI0LDExMTokVncsMTMzOiRWeH0pLG8oJFZmLFsyLDI3OF0pLHsxMTE6WzEsMTI2XX0sezExMTpbMiwyODBdfSxvKCRWeSxbMiw0N10pLG8oJFZvLCRWeix7MTM2OjEyNywxNDM6MTI4LDE0NDoxMjksNDE6JFZBLDExMTokVkF9KSxvKCRWeSxbMiw0OF0pLG8oJFZ5LFsyLDQ5XSksbygkVkIsWzIsMjgzXSx7MTE4OjEzMCwxMjE6MTMxLDEyNDokVml9KSx7Mzk6JFZnLDExMzoxMzJ9LG8oJFZCLFsyLDI4OV0sezEyMjoxMzMsMTE3OjEzNCwxMjU6JFZofSksezM5OiRWZywxMTM6MTM1fSxvKFsxMjQsMTI1XSxbMiw1NV0pLG8oJFZDLCRWRCx7MjE6MTM2LDU2OjEzNyw2MDoxMzgsNjE6JFZFfSksbygkVjYsWzIsMjA1XSksezM5OiRWRiw1NToxNDB9LG8oJFZkLFsyLDIzNF0sezUyOjE0MiwyOTY6WzEsMTQzXX0pLHszOTpbMiwyMzddfSx7MjA6MTQ0LDM4OiRWbCwzOTokVm0sNTA6MTQ1LDUxOiRWbiw1NDo5MH0sezM5OlsxLDE0Nl19LG8oJFY3LFsyLDIxOV0pLHs0MTpbMSwxNDddfSx7NDE6WzIsMzQzXX0sezEzOiRWOCwxNjokVjksMjg6JFZHLDI5OiRWSCw1MzoxNTIsODA6JFZJLDg2OiRWSiw5MToxNTMsMTQ1OjE0OCwxNzU6MTQ5LDE3NzoxNTAsMjE1OiRWSywyMTg6JFZMLDIxOTokVk0sMjM2OjE2MywyMzg6MTY0LDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmJ9LG8oJFYkLFsyLDIzMF0sezU0OjkwLDQ2OjE3Nyw1MDoxNzgsMjA6MTc5LDM4OiRWbCwzOTokVm0sNTE6JFZufSksbygkVnEsWzIsMjI1XSksbygkVkMsJFZELHs1NjoxMzcsNjA6MTM4LDIxOjE4MCw2MTokVkV9KSxvKCRWNixbMiwyMzNdKSxvKCRWNixbMiw4XSksbygkVjYsWzIsMjE0XSx7Mjc6MTgxLDI4OiRWcywyOTokVnR9KSxvKCRWNixbMiwyMTVdKSxvKCRWMDEsWzIsMjEyXSksbygkVjAxLFsyLDldKSxvKCRWMTEsJFYyMSx7MzA6MTgyLDIyMDoxODMsMjI0OjE4NCwyMjg6MTg1LDIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksbygkVjAsWzIsNV0pLG8oJFY2MSxbMiwyNTJdLHs4NToxOTJ9KSxvKCRWNzEsWzIsMjU0XSx7ODc6MTkzfSksezI4OlsxLDE5NV0sMzI6WzEsMTk0XX0sbygkVjgxLFsyLDI1Nl0pLG8oJFYyLFsyLDI2M10sezY6WzIsMjY1XX0pLG8oJFZ5LFsyLDI2OF0sezEwMToxOTYsMTMxOjE5NywxMzI6WzEsMTk4XX0pLG8oJFZ5LFsyLDQ0XSksezEzOiRWOCwxNjokVjksNTM6MTk5LDI4NjokVmJ9LG8oJFZ5LFsyLDYwXSksbygkVnksWzIsMjk3XSksbygkVnksWzIsMjk4XSksbygkVnksWzIsMjk5XSksezEwODpbMSwyMDBdfSxvKCRWOTEsWzIsNTddKSx7MTM6JFY4LDE2OiRWOSw1MzoyMDEsMjg2OiRWYn0sbygkVmQsWzIsMjk2XSksezEzOiRWOCwxNjokVjksNTM6MjAyLDI4NjokVmJ9LG8oJFZhMSxbMiwzMDJdLHsxMzc6MjAzfSksbygkVmExLFsyLDMwMV0pLHsxMzokVjgsMTY6JFY5LDI4OiRWRywyOTokVkgsNTM6MTUyLDgwOiRWSSw4NjokVkosOTE6MTUzLDE0NToyMDQsMTc1OjE0OSwxNzc6MTUwLDIxNTokVkssMjE4OiRWTCwyMTk6JFZNLDIzNjoxNjMsMjM4OjE2NCwyNjk6MTU5LDI3MjokVk4sMjczOiRWTywyNzQ6JFZQLDI3NTokVlEsMjc2OiRWUiwyNzc6JFZTLDI3ODokVlQsMjc5OiRWVSwyODA6JFZWLDI4MTokVlcsMjgyOiRWWCwyODM6JFZZLDI4NDokVlosMjg1OiRWXywyODY6JFZifSxvKCRWQixbMiwyODVdLHsxMTk6MjA1fSksbygkVkIsWzIsMjg0XSksbyhbMzgsMTI0LDEyN10sWzIsNTNdKSxvKCRWQixbMiwyOTFdLHsxMjM6MjA2fSksbygkVkIsWzIsMjkwXSksbyhbMzgsMTI1LDEyN10sWzIsNTJdKSxvKCRWNSxbMiw2XSksbygkVmIxLFsyLDI0MF0sezU3OjIwNyw2NzoyMDgsNjg6WzEsMjA5XX0pLG8oJFZDLFsyLDIzOV0pLHs2MjpbMSwyMTBdfSxvKFs2LDQxLDYxLDY4LDcxLDc5LDgxLDgzXSxbMiwxNl0pLG8oJFZvLCRWYzEsezIyOjIxMSwxNDc6MjEyLDE4OjIxMywxNDg6MjE0LDE1NDoyMTUsMTU1OjIxNiwyNDokVjMsMzk6JFZkMSw0MTokVmQxLDgzOiRWZDEsMTExOiRWZDEsMTU5OiRWZDEsMTYwOiRWZDEsMTYyOiRWZDEsMTY1OiRWZDEsMTY2OiRWZDF9KSx7MTM6JFY4LDE2OiRWOSw1MzoyMTcsMjg2OiRWYn0sbygkVmQsWzIsMjM1XSksbygkVkMsJFZELHs1NjoxMzcsNjA6MTM4LDIxOjIxOCw2MTokVkV9KSxvKCRWNixbMiwyMTddKSxvKCRWbywkVnosezE0NDoxMjksNDA6MjE5LDE0MzoyMjAsNDE6WzIsMjIwXX0pLG8oJFY2LFsyLDg0XSksezQxOlsyLDM0Nl0sMTc0OjIyMSwzMDQ6WzEsMjIyXX0sezEzOiRWOCwxNjokVjksMjg6JFZlMSw1MzoyMjcsMTc2OjIyMywxODA6MjI0LDE4NToyMjUsMTg3OiRWZjEsMjg2OiRWYn0sbygkVmcxLFsyLDM0OF0sezE4MDoyMjQsMTg1OjIyNSw1MzoyMjcsMTc4OjIyOSwxNzk6MjMwLDE3NjoyMzEsMTM6JFY4LDE2OiRWOSwyODokVmUxLDE4NzokVmYxLDI4NjokVmJ9KSxvKCRWaDEsWzIsMTI0XSksbygkVmgxLFsyLDEyNV0pLG8oJFZoMSxbMiwxMjZdKSxvKCRWaDEsWzIsMTI3XSksbygkVmgxLFsyLDEyOF0pLG8oJFZoMSxbMiwxMjldKSx7MTM6JFY4LDE2OiRWOSwyODokVkcsMjk6JFZILDUzOjE1Miw4MDokVkksODY6JFZKLDkxOjE1MywxNzU6MjM0LDE3NzoyMzUsMTg5OjIzMywyMTQ6MjMyLDIxNTokVkssMjE4OiRWTCwyMTk6JFZNLDIzNjoxNjMsMjM4OjE2NCwyNjk6MTU5LDI3MjokVk4sMjczOiRWTywyNzQ6JFZQLDI3NTokVlEsMjc2OiRWUiwyNzc6JFZTLDI3ODokVlQsMjc5OiRWVSwyODA6JFZWLDI4MTokVlcsMjgyOiRWWCwyODM6JFZZLDI4NDokVlosMjg1OiRWXywyODY6JFZifSx7MTM6JFY4LDE2OiRWOSwyODokVmUxLDUzOjIyNywxNzY6MjM2LDE4MDoyMjQsMTg1OjIyNSwxODc6JFZmMSwyODY6JFZifSxvKCRWaTEsWzIsMTY3XSx7MjcwOlsxLDIzN10sMjcxOlsxLDIzOF19KSxvKCRWaTEsWzIsMTcwXSksbygkVmkxLFsyLDE3MV0pLG8oJFZpMSxbMiwxNzJdKSxvKCRWaTEsWzIsMTczXSksbygkVmkxLFsyLDE3NF0pLG8oJFZpMSxbMiwxNzVdKSxvKCRWaTEsWzIsMTc2XSksbygkVmoxLFsyLDE3N10pLG8oJFZqMSxbMiwxNzhdKSxvKCRWajEsWzIsMTc5XSksbygkVmoxLFsyLDE4MF0pLG8oJFZpMSxbMiwxODFdKSxvKCRWaTEsWzIsMTgyXSksbygkVmkxLFsyLDE4M10pLG8oJFZpMSxbMiwxODRdKSxvKCRWaTEsWzIsMTg1XSksbygkVmkxLFsyLDE4Nl0pLG8oJFZDLCRWRCx7NTY6MTM3LDYwOjEzOCwyMToyMzksNjE6JFZFfSksbygkVnAsWzIsMjI5XSksbygkViQsWzIsMjMxXSksbygkVjUsWzIsMTRdKSxvKCRWMDEsWzIsMjEzXSksezMxOlsxLDI0MF19LG8oJFZrMSxbMiwzODVdLHsyMjE6MjQxfSksbygkVmwxLFsyLDM4N10sezIyNToyNDJ9KSxvKCRWbDEsWzIsMTM0XSx7MjI5OjI0MywyMzA6MjQ0LDIzMTpbMiwzOTVdLDI2ODpbMSwyNDVdLDMxMTpbMSwyNDZdLDMxMjpbMSwyNDddLDMxMzpbMSwyNDhdLDMxNDpbMSwyNDldLDMxNTpbMSwyNTBdLDMxNjpbMSwyNTFdfSksbygkVm0xLFsyLDM5N10sezIzMzoyNTJ9KSxvKCRWbjEsWzIsNDA1XSx7MjQxOjI1M30pLHsxMzokVjgsMTY6JFY5LDI4OiRWbzEsMjk6JFZwMSw1MzoyNTcsNjU6MjU2LDY2OjI1OCw3NToyNTUsODA6JFZJLDkxOjI1OSwyMzY6MTYzLDIzODoxNjQsMjQ1OjI1NCwyNDc6MjYyLDI0ODokVnExLDI0OTokVnIxLDI1MDokVnMxLDI1MjokVnQxLDI1MzoyNjcsMjU0OiRWdTEsMjU1OiRWdjEsMjU2OjI3MCwyNTc6JFZ3MSwyNTg6JFZ4MSwyNjE6JFZ5MSwyNjM6JFZ6MSwyNjk6MTU5LDI3MjokVk4sMjczOiRWTywyNzQ6JFZQLDI3NTokVlEsMjc2OiRWUiwyNzc6JFZTLDI3ODokVlQsMjc5OiRWVSwyODA6JFZWLDI4MTokVlcsMjgyOiRWWCwyODM6JFZZLDI4NDokVlosMjg1OiRWXywyODY6JFZiLDMxNjokVkExLDMxNzokVkIxLDMxODokVkMxLDMxOTokVkQxLDMyMDokVkUxLDMyMTokVkYxfSx7MTM6JFY4LDE2OiRWOSwyODokVm8xLDI5OiRWcDEsNTM6MjU3LDY1OjI1Niw2NjoyNTgsNzU6MjU1LDgwOiRWSSw5MToyNTksMjM2OjE2MywyMzg6MTY0LDI0NToyODAsMjQ3OjI2MiwyNDg6JFZxMSwyNDk6JFZyMSwyNTA6JFZzMSwyNTI6JFZ0MSwyNTM6MjY3LDI1NDokVnUxLDI1NTokVnYxLDI1NjoyNzAsMjU3OiRWdzEsMjU4OiRWeDEsMjYxOiRWeTEsMjYzOiRWejEsMjY5OjE1OSwyNzI6JFZOLDI3MzokVk8sMjc0OiRWUCwyNzU6JFZRLDI3NjokVlIsMjc3OiRWUywyNzg6JFZULDI3OTokVlUsMjgwOiRWViwyODE6JFZXLDI4MjokVlgsMjgzOiRWWSwyODQ6JFZaLDI4NTokVl8sMjg2OiRWYiwzMTY6JFZBMSwzMTc6JFZCMSwzMTg6JFZDMSwzMTk6JFZEMSwzMjA6JFZFMSwzMjE6JFZGMX0sezEzOiRWOCwxNjokVjksMjg6JFZvMSwyOTokVnAxLDUzOjI1Nyw2NToyNTYsNjY6MjU4LDc1OjI1NSw4MDokVkksOTE6MjU5LDIzNjoxNjMsMjM4OjE2NCwyNDU6MjgxLDI0NzoyNjIsMjQ4OiRWcTEsMjQ5OiRWcjEsMjUwOiRWczEsMjUyOiRWdDEsMjUzOjI2NywyNTQ6JFZ1MSwyNTU6JFZ2MSwyNTY6MjcwLDI1NzokVncxLDI1ODokVngxLDI2MTokVnkxLDI2MzokVnoxLDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmIsMzE2OiRWQTEsMzE3OiRWQjEsMzE4OiRWQzEsMzE5OiRWRDEsMzIwOiRWRTEsMzIxOiRWRjF9LG8oJFYxMSxbMiw0MTBdKSx7MTM6JFY4LDE2OiRWOSw0MTpbMSwyODJdLDUzOjI4NCw4MDokVkksOTA6MjgzLDkxOjI4NSw5MjokVkcxLDIzNjoxNjMsMjM4OjE2NCwyNjk6MTU5LDI3MjokVk4sMjczOiRWTywyNzQ6JFZQLDI3NTokVlEsMjc2OiRWUiwyNzc6JFZTLDI3ODokVlQsMjc5OiRWVSwyODA6JFZWLDI4MTokVlcsMjgyOiRWWCwyODM6JFZZLDI4NDokVlosMjg1OiRWXywyODY6JFZifSx7NDE6WzEsMjg3XSw4NjpbMSwyODhdfSx7Mzk6WzEsMjg5XX0sbygkVjgxLFsyLDI1N10pLG8oJFZ5LFsyLDQzXSksbygkVnksWzIsMjY5XSksezExMTpbMSwyOTBdfSxvKCRWeSxbMiw1OV0pLG8oJFZkLCRWdix7MTM0OjEyNCwxMDc6MjkxLDExMTokVncsMTMzOiRWeH0pLG8oJFY5MSxbMiw1OF0pLG8oJFZ5LFsyLDQ2XSksezQxOlsxLDI5Ml0sMTExOlsxLDI5NF0sMTM4OjI5M30sbygkVmExLFsyLDMxNF0sezE0NjoyOTUsMzA0OlsxLDI5Nl19KSx7Mzg6WzEsMjk3XSwxMjY6Mjk4LDEyNzokVkgxfSx7Mzg6WzEsMzAwXSwxMjY6MzAxLDEyNzokVkgxfSxvKCRWSTEsWzIsMjQyXSx7NTg6MzAyLDcwOjMwMyw3MTpbMSwzMDRdfSksbygkVmIxLFsyLDI0MV0pLHsxMzokVjgsMTY6JFY5LDI5OiRWcDEsNTM6MzEwLDY1OjMwOCw2NjozMDksNjk6MzA1LDc1OjMwNyw3NzozMDYsMjQ3OjI2MiwyNDg6JFZxMSwyNDk6JFZyMSwyNTA6JFZzMSwyNTI6JFZ0MSwyNTM6MjY3LDI1NDokVnUxLDI1NTokVnYxLDI1NjoyNzAsMjU3OiRWdzEsMjU4OiRWeDEsMjYxOiRWeTEsMjYzOiRWejEsMjg2OiRWYiwzMTY6JFZBMSwzMTc6JFZCMSwzMTg6JFZDMSwzMTk6JFZEMSwzMjA6JFZFMSwzMjE6JFZGMX0sezEzOiRWOCwxNjokVjksMjg6JFZKMSwyOTokVksxLDUzOjMxMCw2MzozMTEsNjQ6MzEyLDY1OjMxMyw2NjozMTQsMjQ3OjI2MiwyNDg6JFZxMSwyNDk6JFZyMSwyNTA6JFZzMSwyNTI6JFZ0MSwyNTM6MjY3LDI1NDokVnUxLDI1NTokVnYxLDI1NjoyNzAsMjU3OiRWdzEsMjU4OiRWeDEsMjYxOiRWeTEsMjYzOiRWejEsMjg2OiRWYiwzMTY6JFZBMSwzMTc6JFZCMSwzMTg6JFZDMSwzMTk6JFZEMSwzMjA6JFZFMSwzMjE6JFZGMX0sezQxOlsxLDMxN119LHs0MTpbMSwzMThdfSx7MjA6MzE5LDM4OiRWbCwzOTokVm0sNTQ6OTB9LG8oJFZMMSxbMiwzMThdLHsxNDk6MzIwfSksbygkVkwxLFsyLDMxN10pLHsxMzokVjgsMTY6JFY5LDI4OiRWRywyOTokVk0xLDUzOjE1Miw4MDokVkksODY6JFZKLDkxOjE1MywxNTY6MzIxLDE3NTozMjIsMTkxOjMyMywyMTU6JFZOMSwyMTg6JFZMLDIxOTokVk0sMjM2OjE2MywyMzg6MTY0LDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmJ9LG8oJFZwLFsyLDE1XSksbygkVjUsWzIsMTFdKSx7NDE6WzEsMzI2XX0sezQxOlsyLDIyMV19LHs0MTpbMiw4NV19LG8oJFZvLFsyLDM0NV0sezQxOlsyLDM0N119KSxvKCRWZzEsWzIsODZdKSxvKCRWTzEsWzIsMzUwXSx7MTgxOjMyN30pLG8oJFZvLCRWUDEsezE4NjozMjgsMTg4OjMyOX0pLG8oJFZvLFsyLDkyXSksbygkVm8sWzIsOTNdKSxvKCRWbyxbMiw5NF0pLG8oJFZnMSxbMiw4N10pLG8oJFZnMSxbMiw4OF0pLG8oJFZnMSxbMiwzNDldKSx7MTM6JFY4LDE2OiRWOSwyODokVkcsMjk6JFZILDMyOlsxLDMzMF0sNTM6MTUyLDgwOiRWSSw4NjokVkosOTE6MTUzLDE3NToyMzQsMTc3OjIzNSwxODk6MzMxLDIxNTokVkssMjE4OiRWTCwyMTk6JFZNLDIzNjoxNjMsMjM4OjE2NCwyNjk6MTU5LDI3MjokVk4sMjczOiRWTywyNzQ6JFZQLDI3NTokVlEsMjc2OiRWUiwyNzc6JFZTLDI3ODokVlQsMjc5OiRWVSwyODA6JFZWLDI4MTokVlcsMjgyOiRWWCwyODM6JFZZLDI4NDokVlosMjg1OiRWXywyODY6JFZifSxvKCRWUTEsWzIsMzgxXSksbygkVlIxLFsyLDEyMF0pLG8oJFZSMSxbMiwxMjFdKSx7MjE2OlsxLDMzMl19LG8oJFZpMSxbMiwxNjhdKSx7MTM6JFY4LDE2OiRWOSw1MzozMzMsMjg2OiRWYn0sbygkVjUsWzIsMTNdKSx7Mjg6WzEsMzM0XX0sbyhbMzEsMzIsMTgzLDI1MV0sWzIsMTMwXSx7MjIyOjMzNSwyMjM6WzEsMzM2XX0pLG8oJFZrMSxbMiwxMzJdLHsyMjY6MzM3LDIyNzpbMSwzMzhdfSksbygkVjExLCRWMjEsezIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDIyODozMzksMjA4OiRWMzEsMjQ2OiRWNDEsMzEwOiRWNTF9KSx7MjMxOlsxLDM0MF19LG8oJFZTMSxbMiwzODldKSxvKCRWUzEsWzIsMzkwXSksbygkVlMxLFsyLDM5MV0pLG8oJFZTMSxbMiwzOTJdKSxvKCRWUzEsWzIsMzkzXSksbygkVlMxLFsyLDM5NF0pLHsyMzE6WzIsMzk2XX0sbyhbMzEsMzIsMTgzLDIyMywyMjcsMjMxLDI1MSwyNjgsMzExLDMxMiwzMTMsMzE0LDMxNSwzMTZdLFsyLDEzN10sezIzNDozNDEsMjM1OjM0MiwyMzY6MzQzLDIzODozNDQsMjQ2OlsxLDM0Nl0sMjgwOiRWViwyODE6JFZXLDI4MjokVlgsMjgzOiRWWSwyODQ6JFZaLDI4NTokVl8sMzEwOlsxLDM0NV19KSxvKCRWbTEsWzIsMTQxXSx7MjQyOjM0NywyNDM6MzQ4LDI5MzokVlQxLDMwNzokVlUxfSksbygkVm4xLFsyLDE0M10pLG8oJFZuMSxbMiwxNDZdKSxvKCRWbjEsWzIsMTQ3XSksbygkVm4xLFsyLDE0OF0sezI5OiRWVjEsODY6JFZXMX0pLG8oJFZuMSxbMiwxNDldKSxvKCRWbjEsWzIsMTUwXSksbygkVm4xLFsyLDE1MV0pLG8oJFYxMSwkVjIxLHsyMjA6MTgzLDIyNDoxODQsMjI4OjE4NSwyMzI6MTg2LDI0MDoxODcsMjQ0OjE4OCwzMDozNTMsMjA4OiRWMzEsMjQ2OiRWNDEsMzEwOiRWNTF9KSxvKCRWWDEsWzIsMTUzXSksezg2OlsxLDM1NF19LHsyOTpbMSwzNTVdfSx7Mjk6WzEsMzU2XX0sezI5OlsxLDM1N119LHsyOTokVlkxLDg2OiRWWjEsMTY5OjM1OH0sezI5OlsxLDM2MV19LHsyOTpbMSwzNjNdLDg2OlsxLDM2Ml19LHsyNTc6WzEsMzY0XX0sezI5OlsxLDM2NV19LHsyOTpbMSwzNjZdfSx7Mjk6WzEsMzY3XX0sbygkVl8xLFsyLDQxMV0pLG8oJFZfMSxbMiw0MTJdKSxvKCRWXzEsWzIsNDEzXSksbygkVl8xLFsyLDQxNF0pLG8oJFZfMSxbMiw0MTVdKSx7MjU3OlsyLDQxN119LG8oJFZuMSxbMiwxNDRdKSxvKCRWbjEsWzIsMTQ1XSksbygkVnUsWzIsMzVdKSxvKCRWNjEsWzIsMjUzXSksbygkViQxLFsyLDM4XSksbygkViQxLFsyLDM5XSksbygkViQxLFsyLDQwXSksbygkVnUsWzIsMzZdKSxvKCRWNzEsWzIsMjU1XSksbygkVjAyLFsyLDI1OF0sezg5OjM2OH0pLHsxMzokVjgsMTY6JFY5LDUzOjM2OSwyODY6JFZifSxvKCRWeSxbMiw0NV0pLG8oWzYsMzgsMTI0LDEyNSwxMjcsMTgzXSxbMiw2MV0pLG8oJFZhMSxbMiwzMDNdKSx7MTM6JFY4LDE2OiRWOSwyODpbMSwzNzFdLDUzOjM3MiwxMzk6MzcwLDI4NjokVmJ9LG8oJFZhMSxbMiw2M10pLG8oJFZvLFsyLDMxM10sezQxOiRWMTIsMTExOiRWMTJ9KSx7Mzk6JFZGLDU1OjM3M30sbygkVkIsWzIsMjg2XSksbygkVmQsWzIsMjkzXSx7MTI4OjM3NCwyOTY6WzEsMzc1XX0pLHszOTokVkYsNTU6Mzc2fSxvKCRWQixbMiwyOTJdKSxvKCRWMjIsWzIsMjQ0XSx7NTk6Mzc3LDc4OjM3OCw3OTpbMSwzNzldLDgxOlsxLDM4MF19KSxvKCRWSTEsWzIsMjQzXSksezYyOlsxLDM4MV19LG8oJFZiMSxbMiwyNF0sezI0NzoyNjIsMjUzOjI2NywyNTY6MjcwLDc1OjMwNyw2NTozMDgsNjY6MzA5LDUzOjMxMCw3NzozODIsMTM6JFY4LDE2OiRWOSwyOTokVnAxLDI0ODokVnExLDI0OTokVnIxLDI1MDokVnMxLDI1MjokVnQxLDI1NDokVnUxLDI1NTokVnYxLDI1NzokVncxLDI1ODokVngxLDI2MTokVnkxLDI2MzokVnoxLDI4NjokVmIsMzE2OiRWQTEsMzE3OiRWQjEsMzE4OiRWQzEsMzE5OiRWRDEsMzIwOiRWRTEsMzIxOiRWRjF9KSxvKCRWMzIsWzIsMjQ4XSksbygkVjQyLFsyLDc3XSksbygkVjQyLFsyLDc4XSksbygkVjQyLFsyLDc5XSksezI5OiRWVjEsODY6JFZXMX0sbygkVkMsWzIsMThdLHsyNDc6MjYyLDI1MzoyNjcsMjU2OjI3MCw1MzozMTAsNjU6MzEzLDY2OjMxNCw2NDozODMsMTM6JFY4LDE2OiRWOSwyODokVkoxLDI5OiRWSzEsMjQ4OiRWcTEsMjQ5OiRWcjEsMjUwOiRWczEsMjUyOiRWdDEsMjU0OiRWdTEsMjU1OiRWdjEsMjU3OiRWdzEsMjU4OiRWeDEsMjYxOiRWeTEsMjYzOiRWejEsMjg2OiRWYiwzMTY6JFZBMSwzMTc6JFZCMSwzMTg6JFZDMSwzMTk6JFZEMSwzMjA6JFZFMSwzMjE6JFZGMX0pLG8oJFY1MixbMiwyNDZdKSxvKCRWNTIsWzIsMTldKSxvKCRWNTIsWzIsMjBdKSxvKCRWMTEsJFYyMSx7MjIwOjE4MywyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMzA6Mzg0LDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksbygkVjUyLFsyLDIzXSksbygkVjYyLFsyLDY0XSksbygkVjYyLFsyLDY1XSksbygkVkMsJFZELHs1NjoxMzcsNjA6MTM4LDIxOjM4NSw2MTokVkV9KSx7Mzk6WzIsMzI4XSw0MTpbMiw2Nl0sODI6Mzk1LDgzOiRWNCwxMTE6WzEsMzkxXSwxNTA6Mzg2LDE1MTozODcsMTU4OjM4OCwxNTk6WzEsMzg5XSwxNjA6WzEsMzkwXSwxNjI6WzEsMzkyXSwxNjU6WzEsMzkzXSwxNjY6WzEsMzk0XX0sbygkVkwxLFsyLDMyNl0sezE1NzozOTYsMzA0OlsxLDM5N119KSxvKCRWNzIsJFY4Mix7MTkwOjM5OCwxOTM6Mzk5LDE5OTo0MDAsMjAwOjQwMiwyODokVjkyfSksbygkVmEyLFsyLDM1Nl0sezE5MzozOTksMTk5OjQwMCwyMDA6NDAyLDE5Mjo0MDMsMTkwOjQwNCwxMzokVjgyLDE2OiRWODIsMjk6JFY4MiwxODc6JFY4MiwyMDg6JFY4MiwyMTM6JFY4MiwyODY6JFY4MiwyODokVjkyfSksezEzOiRWOCwxNjokVjksMjg6JFZHLDI5OiRWTTEsNTM6MTUyLDgwOiRWSSw4NjokVkosOTE6MTUzLDE3NTo0MDcsMTkxOjQwOCwxOTU6NDA2LDIxNTokVk4xLDIxNzo0MDUsMjE4OiRWTCwyMTk6JFZNLDIzNjoxNjMsMjM4OjE2NCwyNjk6MTU5LDI3MjokVk4sMjczOiRWTywyNzQ6JFZQLDI3NTokVlEsMjc2OiRWUiwyNzc6JFZTLDI3ODokVlQsMjc5OiRWVSwyODA6JFZWLDI4MTokVlcsMjgyOiRWWCwyODM6JFZZLDI4NDokVlosMjg1OiRWXywyODY6JFZifSxvKCRWNzIsJFY4Mix7MTkzOjM5OSwxOTk6NDAwLDIwMDo0MDIsMTkwOjQwOSwyODokVjkyfSksbygkVkMsJFZELHs1NjoxMzcsNjA6MTM4LDIxOjQxMCw2MTokVkV9KSxvKFs0MSwxMTEsMjE2LDMwNF0sWzIsODldLHsxODI6NDExLDE4MzpbMSw0MTJdfSksbygkVk8xLFsyLDkxXSksezEzOiRWOCwxNjokVjksMjg6JFZHLDI5OiRWSCw1MzoxNTIsODA6JFZJLDg2OiRWSiw5MToxNTMsMTc1OjIzNCwxNzc6MjM1LDE4OTo0MTMsMjE1OiRWSywyMTg6JFZMLDIxOTokVk0sMjM2OjE2MywyMzg6MTY0LDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmJ9LG8oJFZiMixbMiwxMTZdKSxvKCRWUTEsWzIsMzgyXSksbygkVmIyLFsyLDExN10pLG8oJFZpMSxbMiwxNjldKSx7MzI6WzEsNDE0XX0sbygkVmsxLFsyLDM4Nl0pLG8oJFYxMSwkVjIxLHsyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMjIwOjQxNSwyMDg6JFYzMSwyNDY6JFY0MSwzMTA6JFY1MX0pLG8oJFZsMSxbMiwzODhdKSxvKCRWMTEsJFYyMSx7MjI4OjE4NSwyMzI6MTg2LDI0MDoxODcsMjQ0OjE4OCwyMjQ6NDE2LDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksbygkVmwxLFsyLDEzNV0pLHsyOTokVlkxLDg2OiRWWjEsMTY5OjQxN30sbygkVm0xLFsyLDM5OF0pLG8oJFYxMSwkVjIxLHsyNDA6MTg3LDI0NDoxODgsMjMyOjQxOCwyMDg6JFYzMSwyNDY6JFY0MSwzMTA6JFY1MX0pLG8oJFZuMSxbMiw0MDFdLHsyMzc6NDE5fSksbygkVm4xLFsyLDQwM10sezIzOTo0MjB9KSxvKCRWUzEsWzIsMzk5XSksbygkVlMxLFsyLDQwMF0pLG8oJFZuMSxbMiw0MDZdKSxvKCRWMTEsJFYyMSx7MjQ0OjE4OCwyNDA6NDIxLDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksbygkVlMxLFsyLDQwN10pLG8oJFZTMSxbMiw0MDhdKSxvKCRWWDEsWzIsODBdKSxvKCRWUzEsWzIsMzM2XSx7MTY3OjQyMiwyOTA6WzEsNDIzXX0pLHszMjpbMSw0MjRdfSxvKCRWWDEsWzIsMTU0XSksbygkVjExLCRWMjEsezIyMDoxODMsMjI0OjE4NCwyMjg6MTg1LDIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDMwOjQyNSwyMDg6JFYzMSwyNDY6JFY0MSwzMTA6JFY1MX0pLG8oJFYxMSwkVjIxLHsyMjA6MTgzLDIyNDoxODQsMjI4OjE4NSwyMzI6MTg2LDI0MDoxODcsMjQ0OjE4OCwzMDo0MjYsMjA4OiRWMzEsMjQ2OiRWNDEsMzEwOiRWNTF9KSxvKCRWMTEsJFYyMSx7MjIwOjE4MywyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMzA6NDI3LDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksbygkVlgxLFsyLDE1OF0pLG8oJFZYMSxbMiw4Ml0pLG8oJFZTMSxbMiwzNDBdLHsxNzA6NDI4fSksezI4OlsxLDQyOV19LG8oJFZYMSxbMiwxNjBdKSxvKCRWMTEsJFYyMSx7MjIwOjE4MywyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMzA6NDMwLDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksezM5OiRWRiw1NTo0MzF9LG8oJFZjMixbMiw0MThdLHsyNTk6NDMyLDI5MDpbMSw0MzNdfSksbygkVlMxLFsyLDQyMl0sezI2Mjo0MzQsMjkwOlsxLDQzNV19KSxvKCRWUzEsWzIsNDI0XSx7MjY0OjQzNiwyOTA6WzEsNDM3XX0pLHsyOTpbMSw0NDBdLDQxOlsxLDQzOF0sOTM6NDM5fSxvKCRWeSxbMiw1Nl0pLHszOTpbMSw0NDFdfSx7Mzk6WzIsMzA0XX0sezM5OlsyLDMwNV19LG8oJFZ5LFsyLDUwXSksezEzOiRWOCwxNjokVjksNTM6NDQyLDI4NjokVmJ9LG8oJFZkLFsyLDI5NF0pLG8oJFZ5LFsyLDUxXSksbygkVjIyLFsyLDE3XSksbygkVjIyLFsyLDI0NV0pLHs4MDpbMSw0NDNdfSx7ODA6WzEsNDQ0XX0sezEzOiRWOCwxNjokVjksMjg6JFZkMiwyOTokVnAxLDUzOjMxMCw2NTozMDgsNjY6MzA5LDcyOjQ0NSw3Mzo0NDYsNzQ6JFZlMiw3NTozMDcsNzY6JFZmMiw3Nzo0NDksMjQ3OjI2MiwyNDg6JFZxMSwyNDk6JFZyMSwyNTA6JFZzMSwyNTI6JFZ0MSwyNTM6MjY3LDI1NDokVnUxLDI1NTokVnYxLDI1NjoyNzAsMjU3OiRWdzEsMjU4OiRWeDEsMjYxOiRWeTEsMjYzOiRWejEsMjg2OiRWYiwzMTY6JFZBMSwzMTc6JFZCMSwzMTg6JFZDMSwzMTk6JFZEMSwzMjA6JFZFMSwzMjE6JFZGMX0sbygkVjMyLFsyLDI0OV0pLG8oJFY1MixbMiwyNDddKSx7MzE6WzEsNDUyXSwzMjpbMSw0NTFdfSx7MjM6NDUzLDQxOlsyLDIwNl0sODI6NDU0LDgzOiRWNH0sbygkVkwxLFsyLDMxOV0pLG8oJFZnMixbMiwzMjBdLHsxNTI6NDU1LDMwNDpbMSw0NTZdfSksezM5OiRWRiw1NTo0NTd9LHszOTokVkYsNTU6NDU4fSx7Mzk6JFZGLDU1OjQ1OX0sezEzOiRWOCwxNjokVjksMjg6WzEsNDYxXSw1Mzo0NjIsMTYxOjQ2MCwyODY6JFZifSxvKCRWaDIsWzIsMzMyXSx7MTYzOjQ2MywyOTc6WzEsNDY0XX0pLHsxMzokVjgsMTY6JFY5LDI5OiRWcDEsNTM6MzEwLDY1OjMwOCw2NjozMDksNzU6MzA3LDc3OjQ2NSwyNDc6MjYyLDI0ODokVnExLDI0OTokVnIxLDI1MDokVnMxLDI1MjokVnQxLDI1MzoyNjcsMjU0OiRWdTEsMjU1OiRWdjEsMjU2OjI3MCwyNTc6JFZ3MSwyNTg6JFZ4MSwyNjE6JFZ5MSwyNjM6JFZ6MSwyODY6JFZiLDMxNjokVkExLDMxNzokVkIxLDMxODokVkMxLDMxOTokVkQxLDMyMDokVkUxLDMyMTokVkYxfSx7Mjk6WzEsNDY2XX0sbygkVmkyLFsyLDc2XSksbygkVkwxLFsyLDY4XSksbygkVm8sWzIsMzI1XSx7Mzk6JFZqMiw0MTokVmoyLDgzOiRWajIsMTExOiRWajIsMTU5OiRWajIsMTYwOiRWajIsMTYyOiRWajIsMTY1OiRWajIsMTY2OiRWajJ9KSxvKCRWYTIsWzIsOTZdKSxvKCRWbyxbMiwzNjBdLHsxOTQ6NDY3fSksbygkVm8sWzIsMzU4XSksbygkVm8sWzIsMzU5XSksbygkVjcyLFsyLDM2OF0sezIwMTo0NjgsMjAyOjQ2OX0pLG8oJFZhMixbMiw5N10pLG8oJFZhMixbMiwzNTddKSx7MTM6JFY4LDE2OiRWOSwyODokVkcsMjk6JFZNMSwzMjpbMSw0NzBdLDUzOjE1Miw4MDokVkksODY6JFZKLDkxOjE1MywxNzU6NDA3LDE5MTo0MDgsMTk1OjQ3MSwyMTU6JFZOMSwyMTg6JFZMLDIxOTokVk0sMjM2OjE2MywyMzg6MTY0LDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmJ9LG8oJFZRMSxbMiwzODNdKSxvKCRWUjEsWzIsMTIyXSksbygkVlIxLFsyLDEyM10pLHsyMTY6WzEsNDcyXX0sbygkVjUsWzIsMTJdKSxvKCRWTzEsWzIsMzUxXSksbygkVk8xLFsyLDM1Ml0sezE4NToyMjUsNTM6MjI3LDE4NDo0NzMsMTgwOjQ3NCwxMzokVjgsMTY6JFY5LDI4OiRWZTEsMTg3OiRWZjEsMjg2OiRWYn0pLG8oJFZrMixbMiw5NV0sezI1MTpbMSw0NzVdfSksbygkVjAxLFsyLDEwXSksbygkVmsxLFsyLDEzMV0pLG8oJFZsMSxbMiwxMzNdKSxvKCRWbDEsWzIsMTM2XSksbygkVm0xLFsyLDEzOF0pLG8oJFZtMSxbMiwxMzldLHsyNDM6MzQ4LDI0Mjo0NzYsMjkzOiRWVDEsMzA3OiRWVTF9KSxvKCRWbTEsWzIsMTQwXSx7MjQzOjM0OCwyNDI6NDc3LDI5MzokVlQxLDMwNzokVlUxfSksbygkVm4xLFsyLDE0Ml0pLG8oJFZTMSxbMiwzMzhdLHsxNjg6NDc4fSksbygkVlMxLFsyLDMzN10pLG8oWzYsMTMsMTYsMjgsMjksMzEsMzIsMzksNDEsNzEsNzQsNzYsNzksODAsODEsODMsODYsMTExLDE1OSwxNjAsMTYyLDE2NSwxNjYsMTgzLDIxNSwyMTgsMjE5LDIyMywyMjcsMjMxLDI0NiwyNDgsMjQ5LDI1MCwyNTEsMjUyLDI1NCwyNTUsMjU3LDI1OCwyNjEsMjYzLDI2OCwyNzIsMjczLDI3NCwyNzUsMjc2LDI3NywyNzgsMjc5LDI4MCwyODEsMjgyLDI4MywyODQsMjg1LDI4NiwyOTMsMzA0LDMwNywzMTAsMzExLDMxMiwzMTMsMzE0LDMxNSwzMTYsMzE3LDMxOCwzMTksMzIwLDMyMV0sWzIsMTUyXSksezMyOlsxLDQ3OV19LHsyNTE6WzEsNDgwXX0sezI1MTpbMSw0ODFdfSxvKCRWMTEsJFYyMSx7MjIwOjE4MywyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMzA6NDgyLDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksezMyOlsxLDQ4M119LHszMjpbMSw0ODRdfSxvKCRWWDEsWzIsMTYyXSksbygkVjExLCRWMjEsezIyMDoxODMsMjI0OjE4NCwyMjg6MTg1LDIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDI2MDo0ODUsMzA6NDg3LDIwODokVjMxLDI0NjokVjQxLDI5MzpbMSw0ODZdLDMxMDokVjUxfSksbygkVmMyLFsyLDQxOV0pLG8oJFYxMSwkVjIxLHsyMjA6MTgzLDIyNDoxODQsMjI4OjE4NSwyMzI6MTg2LDI0MDoxODcsMjQ0OjE4OCwzMDo0ODgsMjA4OiRWMzEsMjQ2OiRWNDEsMzEwOiRWNTF9KSxvKCRWUzEsWzIsNDIzXSksbygkVjExLCRWMjEsezIyMDoxODMsMjI0OjE4NCwyMjg6MTg1LDIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDMwOjQ4OSwyMDg6JFYzMSwyNDY6JFY0MSwzMTA6JFY1MX0pLG8oJFZTMSxbMiw0MjVdKSxvKCRWdSxbMiwzN10pLG8oJFYwMixbMiwyNTldKSx7MTM6JFY4LDE2OiRWOSw1MzoyODQsODA6JFZJLDkwOjQ5MSw5MToyODUsOTI6JFZHMSw5NDo0OTAsMjM2OjE2MywyMzg6MTY0LDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmJ9LG8oJFZvLCRWeix7MTQ0OjEyOSwxNDA6NDkyLDE0Mzo0OTMsNDE6WzIsMzA2XX0pLG8oJFZCLFsyLDU0XSksbygkVjIyLFsyLDMwXSx7ODE6WzEsNDk0XX0pLG8oJFYyMixbMiwzMV0sezc5OlsxLDQ5NV19KSxvKCRWSTEsWzIsMjVdLHsyNDc6MjYyLDI1MzoyNjcsMjU2OjI3MCw3NTozMDcsNjU6MzA4LDY2OjMwOSw1MzozMTAsNzc6NDQ5LDczOjQ5NiwxMzokVjgsMTY6JFY5LDI4OiRWZDIsMjk6JFZwMSw3NDokVmUyLDc2OiRWZjIsMjQ4OiRWcTEsMjQ5OiRWcjEsMjUwOiRWczEsMjUyOiRWdDEsMjU0OiRWdTEsMjU1OiRWdjEsMjU3OiRWdzEsMjU4OiRWeDEsMjYxOiRWeTEsMjYzOiRWejEsMjg2OiRWYiwzMTY6JFZBMSwzMTc6JFZCMSwzMTg6JFZDMSwzMTk6JFZEMSwzMjA6JFZFMSwzMjE6JFZGMX0pLG8oJFZsMixbMiwyNTBdKSx7Mjk6JFZwMSw3NTo0OTd9LHsyOTokVnAxLDc1OjQ5OH0sbygkVmwyLFsyLDI4XSksbygkVmwyLFsyLDI5XSksbygkVjUyLFsyLDIxXSksezI4OlsxLDQ5OV19LHs0MTpbMiw3XX0sezQxOlsyLDIwN119LG8oJFZvLCRWYzEsezE1NToyMTYsMTUzOjUwMCwxNTQ6NTAxLDM5OiRWbTIsNDE6JFZtMiw4MzokVm0yLDExMTokVm0yLDE1OTokVm0yLDE2MDokVm0yLDE2MjokVm0yLDE2NTokVm0yLDE2NjokVm0yfSksbygkVmcyLFsyLDMyMV0pLG8oJFZpMixbMiw2OV0sezMwNTpbMSw1MDJdfSksbygkVmkyLFsyLDcwXSksbygkVmkyLFsyLDcxXSksezM5OiRWRiw1NTo1MDN9LHszOTpbMiwzMzBdfSx7Mzk6WzIsMzMxXX0sezEzOiRWOCwxNjokVjksMjg6WzEsNTA1XSw1Mzo1MDYsMTY0OjUwNCwyODY6JFZifSxvKCRWaDIsWzIsMzMzXSksbygkVmkyLFsyLDc0XSksbygkVjExLCRWMjEsezIyMDoxODMsMjI0OjE4NCwyMjg6MTg1LDIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDMwOjUwNywyMDg6JFYzMSwyNDY6JFY0MSwzMTA6JFY1MX0pLHsxMzokVjgsMTY6JFY5LDI4OiRWRywyOTokVk0xLDUzOjE1Miw4MDokVkksODY6JFZKLDkxOjE1MywxNzU6NDA3LDE5MTo0MDgsMTk1OjUwOCwyMTU6JFZOMSwyMTg6JFZMLDIxOTokVk0sMjM2OjE2MywyMzg6MTY0LDI2OToxNTksMjcyOiRWTiwyNzM6JFZPLDI3NDokVlAsMjc1OiRWUSwyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVLDI4MDokVlYsMjgxOiRWVywyODI6JFZYLDI4MzokVlksMjg0OiRWWiwyODU6JFZfLDI4NjokVmJ9LG8oJFZRMSxbMiwxMDFdLHszMDY6WzEsNTA5XX0pLG8oJFZuMixbMiwzNzVdLHsyMDM6NTEwLDIwNzo1MTEsMjEzOlsxLDUxMl19KSxvKCRWaDEsWzIsMTE4XSksbygkVlExLFsyLDM4NF0pLG8oJFZoMSxbMiwxMTldKSxvKCRWTzEsWzIsOTBdKSxvKCRWTzEsWzIsMzUzXSksbygkVm8sWzIsMzU1XSksbygkVm4xLFsyLDQwMl0pLG8oJFZuMSxbMiw0MDRdKSxvKCRWMTEsJFYyMSx7MjIwOjE4MywyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMzA6NTEzLDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksbygkVlgxLFsyLDE1NV0pLG8oJFYxMSwkVjIxLHsyMjA6MTgzLDIyNDoxODQsMjI4OjE4NSwyMzI6MTg2LDI0MDoxODcsMjQ0OjE4OCwzMDo1MTQsMjA4OiRWMzEsMjQ2OiRWNDEsMzEwOiRWNTF9KSxvKCRWMTEsJFYyMSx7MjIwOjE4MywyMjQ6MTg0LDIyODoxODUsMjMyOjE4NiwyNDA6MTg3LDI0NDoxODgsMzA6NTE1LDIwODokVjMxLDI0NjokVjQxLDMxMDokVjUxfSksezMyOlsxLDUxNl0sMjUxOlsxLDUxN119LG8oJFZYMSxbMiwxNTldKSxvKCRWWDEsWzIsMTYxXSksezMyOlsxLDUxOF19LHszMjpbMiw0MjBdfSx7MzI6WzIsNDIxXX0sezMyOlsxLDUxOV19LHszMjpbMiw0MjZdLDE4MzpbMSw1MjJdLDI2NTo1MjAsMjY2OjUyMX0sezEzOiRWOCwxNjokVjksMzI6WzEsNTIzXSw1MzoyODQsODA6JFZJLDkwOjUyNCw5MToyODUsOTI6JFZHMSwyMzY6MTYzLDIzODoxNjQsMjY5OjE1OSwyNzI6JFZOLDI3MzokVk8sMjc0OiRWUCwyNzU6JFZRLDI3NjokVlIsMjc3OiRWUywyNzg6JFZULDI3OTokVlUsMjgwOiRWViwyODE6JFZXLDI4MjokVlgsMjgzOiRWWSwyODQ6JFZaLDI4NTokVl8sMjg2OiRWYn0sbygkVm8yLFsyLDI2MF0pLHs0MTpbMSw1MjVdfSx7NDE6WzIsMzA3XX0sezgwOlsxLDUyNl19LHs4MDpbMSw1MjddfSxvKCRWbDIsWzIsMjUxXSksbygkVmwyLFsyLDI2XSksbygkVmwyLFsyLDI3XSksezMyOlsxLDUyOF19LG8oJFZMMSxbMiw2N10pLG8oJFZMMSxbMiwzMjNdKSx7Mzk6WzIsMzI5XX0sbygkVmkyLFsyLDcyXSksezM5OiRWRiw1NTo1Mjl9LHszOTpbMiwzMzRdfSx7Mzk6WzIsMzM1XX0sezMxOlsxLDUzMF19LG8oJFZrMixbMiwzNjJdLHsxOTY6NTMxLDI1MTpbMSw1MzJdfSksbygkVjcyLFsyLDM2N10pLG8oWzEzLDE2LDI4LDI5LDMyLDgwLDg2LDIxNSwyMTgsMjE5LDI3MiwyNzMsMjc0LDI3NSwyNzYsMjc3LDI3OCwyNzksMjgwLDI4MSwyODIsMjgzLDI4NCwyODUsMjg2LDMwNl0sWzIsMTAyXSx7MzA3OlsxLDUzM119KSx7MTM6JFY4LDE2OiRWOSwyOTpbMSw1MzldLDUzOjUzNiwxODc6WzEsNTM3XSwyMDQ6NTM0LDIwNTo1MzUsMjA4OlsxLDUzOF0sMjg2OiRWYn0sbygkVm4yLFsyLDM3Nl0pLHszMjpbMSw1NDBdLDI1MTpbMSw1NDFdfSx7MzI6WzEsNTQyXX0sezI1MTpbMSw1NDNdfSxvKCRWWDEsWzIsODNdKSxvKCRWUzEsWzIsMzQxXSksbygkVlgxLFsyLDE2M10pLG8oJFZYMSxbMiwxNjRdKSx7MzI6WzEsNTQ0XX0sezMyOlsyLDQyN119LHsyNjc6WzEsNTQ1XX0sbygkVjAyLFsyLDQxXSksbygkVm8yLFsyLDI2MV0pLG8oJFZwMixbMiwzMDhdLHsxNDE6NTQ2LDMwNDpbMSw1NDddfSksbygkVjIyLFsyLDMyXSksbygkVjIyLFsyLDMzXSksbygkVjUyLFsyLDIyXSksbygkVmkyLFsyLDczXSksezI4OlsxLDU0OF19LG8oWzM5LDQxLDgzLDExMSwxNTksMTYwLDE2MiwxNjUsMTY2LDIxNiwzMDRdLFsyLDk4XSx7MTk3OjU0OSwxODM6WzEsNTUwXX0pLG8oJFZvLFsyLDM2MV0pLG8oJFY3MixbMiwzNjldKSxvKCRWcTIsWzIsMTA0XSksbygkVnEyLFsyLDM3M10sezIwNjo1NTEsMzA4OjU1MiwyOTM6WzEsNTU0XSwzMDk6WzEsNTUzXSwzMTA6WzEsNTU1XX0pLG8oJFZyMixbMiwxMDVdKSxvKCRWcjIsWzIsMTA2XSksezEzOiRWOCwxNjokVjksMjk6WzEsNTU5XSw1Mzo1NjAsODY6WzEsNTU4XSwxODc6JFZzMiwyMDk6NTU2LDIxMDo1NTcsMjEzOiRWdDIsMjg2OiRWYn0sbygkVjcyLCRWODIsezIwMDo0MDIsMTk5OjU2M30pLG8oJFZYMSxbMiw4MV0pLG8oJFZTMSxbMiwzMzldKSxvKCRWWDEsWzIsMTU2XSksbygkVjExLCRWMjEsezIyMDoxODMsMjI0OjE4NCwyMjg6MTg1LDIzMjoxODYsMjQwOjE4NywyNDQ6MTg4LDMwOjU2NCwyMDg6JFYzMSwyNDY6JFY0MSwzMTA6JFY1MX0pLG8oJFZYMSxbMiwxNjVdKSx7MjY4OlsxLDU2NV19LG8oJFZvLCRWeix7MTQ0OjEyOSwxNDI6NTY2LDE0Mzo1NjcsNDE6JFZ1MiwxMTE6JFZ1Mn0pLG8oJFZwMixbMiwzMDldKSx7MzI6WzEsNTY4XX0sbygkVmsyLFsyLDM2M10pLG8oJFZrMixbMiw5OV0sezIwMDo0MDIsMTk4OjU2OSwxOTk6NTcwLDEzOiRWODIsMTY6JFY4MiwyOTokVjgyLDE4NzokVjgyLDIwODokVjgyLDIxMzokVjgyLDI4NjokVjgyLDI4OlsxLDU3MV19KSxvKCRWcTIsWzIsMTAzXSksbygkVnEyLFsyLDM3NF0pLG8oJFZxMixbMiwzNzBdKSxvKCRWcTIsWzIsMzcxXSksbygkVnEyLFsyLDM3Ml0pLG8oJFZyMixbMiwxMDddKSxvKCRWcjIsWzIsMTA5XSksbygkVnIyLFsyLDExMF0pLG8oJFZ2MixbMiwzNzddLHsyMTE6NTcyfSksbygkVnIyLFsyLDExMl0pLG8oJFZyMixbMiwxMTNdKSx7MTM6JFY4LDE2OiRWOSw1Mzo1NzMsMTg3OlsxLDU3NF0sMjg2OiRWYn0sezMyOlsxLDU3NV19LHszMjpbMSw1NzZdfSx7MjY5OjU3NywyNzY6JFZSLDI3NzokVlMsMjc4OiRWVCwyNzk6JFZVfSxvKCRWYTEsWzIsNjJdKSxvKCRWYTEsWzIsMzExXSksbygkVmkyLFsyLDc1XSksbygkVm8sJFZQMSx7MTg4OjMyOSwxODY6NTc4fSksbygkVm8sWzIsMzY0XSksbygkVm8sWzIsMzY1XSksezEzOiRWOCwxNjokVjksMzI6WzIsMzc5XSw1Mzo1NjAsMTg3OiRWczIsMjEwOjU4MCwyMTI6NTc5LDIxMzokVnQyLDI4NjokVmJ9LG8oJFZyMixbMiwxMTRdKSxvKCRWcjIsWzIsMTE1XSksbygkVnIyLFsyLDEwOF0pLG8oJFZYMSxbMiwxNTddKSx7MzI6WzIsMTY2XX0sbygkVmsyLFsyLDEwMF0pLHszMjpbMSw1ODFdfSx7MzI6WzIsMzgwXSwzMDY6WzEsNTgyXX0sbygkVnIyLFsyLDExMV0pLG8oJFZ2MixbMiwzNzhdKV0sXG5kZWZhdWx0QWN0aW9uczogezU6WzIsMTkyXSw2OlsyLDE5M10sODpbMiwxOTFdLDI0OlsyLDFdLDI1OlsyLDNdLDI2OlsyLDIwM10sNjk6WzIsNDJdLDc4OlsyLDI4MF0sOTI6WzIsMjM3XSw5NzpbMiwzNDNdLDIyMDpbMiwyMjFdLDIyMTpbMiw4NV0sMjUxOlsyLDM5Nl0sMjc5OlsyLDQxN10sMzcxOlsyLDMwNF0sMzcyOlsyLDMwNV0sNDUzOlsyLDddLDQ1NDpbMiwyMDddLDQ2MTpbMiwzMzBdLDQ2MjpbMiwzMzFdLDQ4NjpbMiw0MjBdLDQ4NzpbMiw0MjFdLDQ5MzpbMiwzMDddLDUwMjpbMiwzMjldLDUwNTpbMiwzMzRdLDUwNjpbMiwzMzVdLDUyMTpbMiw0MjddLDU3NzpbMiwxNjZdfSxcbnBhcnNlRXJyb3I6IGZ1bmN0aW9uIHBhcnNlRXJyb3IgKHN0ciwgaGFzaCkge1xuICAgIGlmIChoYXNoLnJlY292ZXJhYmxlKSB7XG4gICAgICAgIHRoaXMudHJhY2Uoc3RyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3Ioc3RyKTtcbiAgICAgICAgZXJyb3IuaGFzaCA9IGhhc2g7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbn0sXG5wYXJzZTogZnVuY3Rpb24gcGFyc2UoaW5wdXQpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXMsIHN0YWNrID0gWzBdLCB0c3RhY2sgPSBbXSwgdnN0YWNrID0gW251bGxdLCBsc3RhY2sgPSBbXSwgdGFibGUgPSB0aGlzLnRhYmxlLCB5eXRleHQgPSAnJywgeXlsaW5lbm8gPSAwLCB5eWxlbmcgPSAwLCByZWNvdmVyaW5nID0gMCwgVEVSUk9SID0gMiwgRU9GID0gMTtcbiAgICB2YXIgYXJncyA9IGxzdGFjay5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgdmFyIGxleGVyID0gT2JqZWN0LmNyZWF0ZSh0aGlzLmxleGVyKTtcbiAgICB2YXIgc2hhcmVkU3RhdGUgPSB7IHl5OiB7fSB9O1xuICAgIGZvciAodmFyIGsgaW4gdGhpcy55eSkge1xuICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMueXksIGspKSB7XG4gICAgICAgICAgICBzaGFyZWRTdGF0ZS55eVtrXSA9IHRoaXMueXlba107XG4gICAgICAgIH1cbiAgICB9XG4gICAgbGV4ZXIuc2V0SW5wdXQoaW5wdXQsIHNoYXJlZFN0YXRlLnl5KTtcbiAgICBzaGFyZWRTdGF0ZS55eS5sZXhlciA9IGxleGVyO1xuICAgIHNoYXJlZFN0YXRlLnl5LnBhcnNlciA9IHRoaXM7XG4gICAgaWYgKHR5cGVvZiBsZXhlci55eWxsb2MgPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgbGV4ZXIueXlsbG9jID0ge307XG4gICAgfVxuICAgIHZhciB5eWxvYyA9IGxleGVyLnl5bGxvYztcbiAgICBsc3RhY2sucHVzaCh5eWxvYyk7XG4gICAgdmFyIHJhbmdlcyA9IGxleGVyLm9wdGlvbnMgJiYgbGV4ZXIub3B0aW9ucy5yYW5nZXM7XG4gICAgaWYgKHR5cGVvZiBzaGFyZWRTdGF0ZS55eS5wYXJzZUVycm9yID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRoaXMucGFyc2VFcnJvciA9IHNoYXJlZFN0YXRlLnl5LnBhcnNlRXJyb3I7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5wYXJzZUVycm9yID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHRoaXMpLnBhcnNlRXJyb3I7XG4gICAgfVxuICAgIGZ1bmN0aW9uIHBvcFN0YWNrKG4pIHtcbiAgICAgICAgc3RhY2subGVuZ3RoID0gc3RhY2subGVuZ3RoIC0gMiAqIG47XG4gICAgICAgIHZzdGFjay5sZW5ndGggPSB2c3RhY2subGVuZ3RoIC0gbjtcbiAgICAgICAgbHN0YWNrLmxlbmd0aCA9IGxzdGFjay5sZW5ndGggLSBuO1xuICAgIH1cbiAgICBfdG9rZW5fc3RhY2s6XG4gICAgICAgIHZhciBsZXggPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdG9rZW47XG4gICAgICAgICAgICB0b2tlbiA9IGxleGVyLmxleCgpIHx8IEVPRjtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdG9rZW4gIT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgICAgdG9rZW4gPSBzZWxmLnN5bWJvbHNfW3Rva2VuXSB8fCB0b2tlbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0b2tlbjtcbiAgICAgICAgfTtcbiAgICB2YXIgc3ltYm9sLCBwcmVFcnJvclN5bWJvbCwgc3RhdGUsIGFjdGlvbiwgYSwgciwgeXl2YWwgPSB7fSwgcCwgbGVuLCBuZXdTdGF0ZSwgZXhwZWN0ZWQ7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgc3RhdGUgPSBzdGFja1tzdGFjay5sZW5ndGggLSAxXTtcbiAgICAgICAgaWYgKHRoaXMuZGVmYXVsdEFjdGlvbnNbc3RhdGVdKSB7XG4gICAgICAgICAgICBhY3Rpb24gPSB0aGlzLmRlZmF1bHRBY3Rpb25zW3N0YXRlXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChzeW1ib2wgPT09IG51bGwgfHwgdHlwZW9mIHN5bWJvbCA9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIHN5bWJvbCA9IGxleCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYWN0aW9uID0gdGFibGVbc3RhdGVdICYmIHRhYmxlW3N0YXRlXVtzeW1ib2xdO1xuICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgYWN0aW9uID09PSAndW5kZWZpbmVkJyB8fCAhYWN0aW9uLmxlbmd0aCB8fCAhYWN0aW9uWzBdKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVyclN0ciA9ICcnO1xuICAgICAgICAgICAgICAgIGV4cGVjdGVkID0gW107XG4gICAgICAgICAgICAgICAgZm9yIChwIGluIHRhYmxlW3N0YXRlXSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy50ZXJtaW5hbHNfW3BdICYmIHAgPiBURVJST1IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVjdGVkLnB1c2goJ1xcJycgKyB0aGlzLnRlcm1pbmFsc19bcF0gKyAnXFwnJyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGxleGVyLnNob3dQb3NpdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBlcnJTdHIgPSAnUGFyc2UgZXJyb3Igb24gbGluZSAnICsgKHl5bGluZW5vICsgMSkgKyAnOlxcbicgKyBsZXhlci5zaG93UG9zaXRpb24oKSArICdcXG5FeHBlY3RpbmcgJyArIGV4cGVjdGVkLmpvaW4oJywgJykgKyAnLCBnb3QgXFwnJyArICh0aGlzLnRlcm1pbmFsc19bc3ltYm9sXSB8fCBzeW1ib2wpICsgJ1xcJyc7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyU3RyID0gJ1BhcnNlIGVycm9yIG9uIGxpbmUgJyArICh5eWxpbmVubyArIDEpICsgJzogVW5leHBlY3RlZCAnICsgKHN5bWJvbCA9PSBFT0YgPyAnZW5kIG9mIGlucHV0JyA6ICdcXCcnICsgKHRoaXMudGVybWluYWxzX1tzeW1ib2xdIHx8IHN5bWJvbCkgKyAnXFwnJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMucGFyc2VFcnJvcihlcnJTdHIsIHtcbiAgICAgICAgICAgICAgICAgICAgdGV4dDogbGV4ZXIubWF0Y2gsXG4gICAgICAgICAgICAgICAgICAgIHRva2VuOiB0aGlzLnRlcm1pbmFsc19bc3ltYm9sXSB8fCBzeW1ib2wsXG4gICAgICAgICAgICAgICAgICAgIGxpbmU6IGxleGVyLnl5bGluZW5vLFxuICAgICAgICAgICAgICAgICAgICBsb2M6IHl5bG9jLFxuICAgICAgICAgICAgICAgICAgICBleHBlY3RlZDogZXhwZWN0ZWRcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgaWYgKGFjdGlvblswXSBpbnN0YW5jZW9mIEFycmF5ICYmIGFjdGlvbi5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BhcnNlIEVycm9yOiBtdWx0aXBsZSBhY3Rpb25zIHBvc3NpYmxlIGF0IHN0YXRlOiAnICsgc3RhdGUgKyAnLCB0b2tlbjogJyArIHN5bWJvbCk7XG4gICAgICAgIH1cbiAgICAgICAgc3dpdGNoIChhY3Rpb25bMF0pIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgc3RhY2sucHVzaChzeW1ib2wpO1xuICAgICAgICAgICAgdnN0YWNrLnB1c2gobGV4ZXIueXl0ZXh0KTtcbiAgICAgICAgICAgIGxzdGFjay5wdXNoKGxleGVyLnl5bGxvYyk7XG4gICAgICAgICAgICBzdGFjay5wdXNoKGFjdGlvblsxXSk7XG4gICAgICAgICAgICBzeW1ib2wgPSBudWxsO1xuICAgICAgICAgICAgaWYgKCFwcmVFcnJvclN5bWJvbCkge1xuICAgICAgICAgICAgICAgIHl5bGVuZyA9IGxleGVyLnl5bGVuZztcbiAgICAgICAgICAgICAgICB5eXRleHQgPSBsZXhlci55eXRleHQ7XG4gICAgICAgICAgICAgICAgeXlsaW5lbm8gPSBsZXhlci55eWxpbmVubztcbiAgICAgICAgICAgICAgICB5eWxvYyA9IGxleGVyLnl5bGxvYztcbiAgICAgICAgICAgICAgICBpZiAocmVjb3ZlcmluZyA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgcmVjb3ZlcmluZy0tO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3ltYm9sID0gcHJlRXJyb3JTeW1ib2w7XG4gICAgICAgICAgICAgICAgcHJlRXJyb3JTeW1ib2wgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAgIGxlbiA9IHRoaXMucHJvZHVjdGlvbnNfW2FjdGlvblsxXV1bMV07XG4gICAgICAgICAgICB5eXZhbC4kID0gdnN0YWNrW3ZzdGFjay5sZW5ndGggLSBsZW5dO1xuICAgICAgICAgICAgeXl2YWwuXyQgPSB7XG4gICAgICAgICAgICAgICAgZmlyc3RfbGluZTogbHN0YWNrW2xzdGFjay5sZW5ndGggLSAobGVuIHx8IDEpXS5maXJzdF9saW5lLFxuICAgICAgICAgICAgICAgIGxhc3RfbGluZTogbHN0YWNrW2xzdGFjay5sZW5ndGggLSAxXS5sYXN0X2xpbmUsXG4gICAgICAgICAgICAgICAgZmlyc3RfY29sdW1uOiBsc3RhY2tbbHN0YWNrLmxlbmd0aCAtIChsZW4gfHwgMSldLmZpcnN0X2NvbHVtbixcbiAgICAgICAgICAgICAgICBsYXN0X2NvbHVtbjogbHN0YWNrW2xzdGFjay5sZW5ndGggLSAxXS5sYXN0X2NvbHVtblxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChyYW5nZXMpIHtcbiAgICAgICAgICAgICAgICB5eXZhbC5fJC5yYW5nZSA9IFtcbiAgICAgICAgICAgICAgICAgICAgbHN0YWNrW2xzdGFjay5sZW5ndGggLSAobGVuIHx8IDEpXS5yYW5nZVswXSxcbiAgICAgICAgICAgICAgICAgICAgbHN0YWNrW2xzdGFjay5sZW5ndGggLSAxXS5yYW5nZVsxXVxuICAgICAgICAgICAgICAgIF07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByID0gdGhpcy5wZXJmb3JtQWN0aW9uLmFwcGx5KHl5dmFsLCBbXG4gICAgICAgICAgICAgICAgeXl0ZXh0LFxuICAgICAgICAgICAgICAgIHl5bGVuZyxcbiAgICAgICAgICAgICAgICB5eWxpbmVubyxcbiAgICAgICAgICAgICAgICBzaGFyZWRTdGF0ZS55eSxcbiAgICAgICAgICAgICAgICBhY3Rpb25bMV0sXG4gICAgICAgICAgICAgICAgdnN0YWNrLFxuICAgICAgICAgICAgICAgIGxzdGFja1xuICAgICAgICAgICAgXS5jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiByICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGxlbikge1xuICAgICAgICAgICAgICAgIHN0YWNrID0gc3RhY2suc2xpY2UoMCwgLTEgKiBsZW4gKiAyKTtcbiAgICAgICAgICAgICAgICB2c3RhY2sgPSB2c3RhY2suc2xpY2UoMCwgLTEgKiBsZW4pO1xuICAgICAgICAgICAgICAgIGxzdGFjayA9IGxzdGFjay5zbGljZSgwLCAtMSAqIGxlbik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzdGFjay5wdXNoKHRoaXMucHJvZHVjdGlvbnNfW2FjdGlvblsxXV1bMF0pO1xuICAgICAgICAgICAgdnN0YWNrLnB1c2goeXl2YWwuJCk7XG4gICAgICAgICAgICBsc3RhY2sucHVzaCh5eXZhbC5fJCk7XG4gICAgICAgICAgICBuZXdTdGF0ZSA9IHRhYmxlW3N0YWNrW3N0YWNrLmxlbmd0aCAtIDJdXVtzdGFja1tzdGFjay5sZW5ndGggLSAxXV07XG4gICAgICAgICAgICBzdGFjay5wdXNoKG5ld1N0YXRlKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn19O1xuXG4gIC8qXG4gICAgU1BBUlFMIHBhcnNlciBpbiB0aGUgSmlzb24gcGFyc2VyIGdlbmVyYXRvciBmb3JtYXQuXG4gICovXG5cbiAgLy8gQ29tbW9uIG5hbWVzcGFjZXMgYW5kIGVudGl0aWVzXG4gIHZhciBSREYgPSAnaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIycsXG4gICAgICBSREZfVFlQRSAgPSBSREYgKyAndHlwZScsXG4gICAgICBSREZfRklSU1QgPSBSREYgKyAnZmlyc3QnLFxuICAgICAgUkRGX1JFU1QgID0gUkRGICsgJ3Jlc3QnLFxuICAgICAgUkRGX05JTCAgID0gUkRGICsgJ25pbCcsXG4gICAgICBYU0QgPSAnaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjJyxcbiAgICAgIFhTRF9JTlRFR0VSICA9IFhTRCArICdpbnRlZ2VyJyxcbiAgICAgIFhTRF9ERUNJTUFMICA9IFhTRCArICdkZWNpbWFsJyxcbiAgICAgIFhTRF9ET1VCTEUgICA9IFhTRCArICdkb3VibGUnLFxuICAgICAgWFNEX0JPT0xFQU4gID0gWFNEICsgJ2Jvb2xlYW4nLFxuICAgICAgWFNEX1RSVUUgPSAgJ1widHJ1ZVwiXl4nICArIFhTRF9CT09MRUFOLFxuICAgICAgWFNEX0ZBTFNFID0gJ1wiZmFsc2VcIl5eJyArIFhTRF9CT09MRUFOO1xuXG4gIHZhciBiYXNlID0gJycsIGJhc2VQYXRoID0gJycsIGJhc2VSb290ID0gJyc7XG5cbiAgLy8gUmV0dXJucyBhIGxvd2VyY2FzZSB2ZXJzaW9uIG9mIHRoZSBnaXZlbiBzdHJpbmdcbiAgZnVuY3Rpb24gbG93ZXJjYXNlKHN0cmluZykge1xuICAgIHJldHVybiBzdHJpbmcudG9Mb3dlckNhc2UoKTtcbiAgfVxuXG4gIC8vIEFwcGVuZHMgdGhlIGl0ZW0gdG8gdGhlIGFycmF5IGFuZCByZXR1cm5zIHRoZSBhcnJheVxuICBmdW5jdGlvbiBhcHBlbmRUbyhhcnJheSwgaXRlbSkge1xuICAgIHJldHVybiBhcnJheS5wdXNoKGl0ZW0pLCBhcnJheTtcbiAgfVxuXG4gIC8vIEFwcGVuZHMgdGhlIGl0ZW1zIHRvIHRoZSBhcnJheSBhbmQgcmV0dXJucyB0aGUgYXJyYXlcbiAgZnVuY3Rpb24gYXBwZW5kQWxsVG8oYXJyYXksIGl0ZW1zKSB7XG4gICAgcmV0dXJuIGFycmF5LnB1c2guYXBwbHkoYXJyYXksIGl0ZW1zKSwgYXJyYXk7XG4gIH1cblxuICAvLyBFeHRlbmRzIGEgYmFzZSBvYmplY3Qgd2l0aCBwcm9wZXJ0aWVzIG9mIG90aGVyIG9iamVjdHNcbiAgZnVuY3Rpb24gZXh0ZW5kKGJhc2UpIHtcbiAgICBpZiAoIWJhc2UpIGJhc2UgPSB7fTtcbiAgICBmb3IgKHZhciBpID0gMSwgbCA9IGFyZ3VtZW50cy5sZW5ndGgsIGFyZzsgaSA8IGwgJiYgKGFyZyA9IGFyZ3VtZW50c1tpXSB8fCB7fSk7IGkrKylcbiAgICAgIGZvciAodmFyIG5hbWUgaW4gYXJnKVxuICAgICAgICBiYXNlW25hbWVdID0gYXJnW25hbWVdO1xuICAgIHJldHVybiBiYXNlO1xuICB9XG5cbiAgLy8gQ3JlYXRlcyBhbiBhcnJheSB0aGF0IGNvbnRhaW5zIGFsbCBpdGVtcyBvZiB0aGUgZ2l2ZW4gYXJyYXlzXG4gIGZ1bmN0aW9uIHVuaW9uQWxsKCkge1xuICAgIHZhciB1bmlvbiA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwLCBsID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IGw7IGkrKylcbiAgICAgIHVuaW9uID0gdW5pb24uY29uY2F0LmFwcGx5KHVuaW9uLCBhcmd1bWVudHNbaV0pO1xuICAgIHJldHVybiB1bmlvbjtcbiAgfVxuXG4gIC8vIFJlc29sdmVzIGFuIElSSSBhZ2FpbnN0IGEgYmFzZSBwYXRoXG4gIGZ1bmN0aW9uIHJlc29sdmVJUkkoaXJpKSB7XG4gICAgLy8gU3RyaXAgb2ZmIHBvc3NpYmxlIGFuZ3VsYXIgYnJhY2tldHNcbiAgICBpZiAoaXJpWzBdID09PSAnPCcpXG4gICAgICBpcmkgPSBpcmkuc3Vic3RyaW5nKDEsIGlyaS5sZW5ndGggLSAxKTtcbiAgICAvLyBSZXR1cm4gYWJzb2x1dGUgSVJJcyB1bm1vZGlmaWVkXG4gICAgaWYgKC9eW2Etel0rOi8udGVzdChpcmkpKVxuICAgICAgcmV0dXJuIGlyaTtcbiAgICBpZiAoIVBhcnNlci5iYXNlKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgcmVzb2x2ZSByZWxhdGl2ZSBJUkkgJyArIGlyaSArICcgYmVjYXVzZSBubyBiYXNlIElSSSB3YXMgc2V0LicpO1xuICAgIGlmICghYmFzZSkge1xuICAgICAgYmFzZSA9IFBhcnNlci5iYXNlO1xuICAgICAgYmFzZVBhdGggPSBiYXNlLnJlcGxhY2UoL1teXFwvOl0qJC8sICcnKTtcbiAgICAgIGJhc2VSb290ID0gYmFzZS5tYXRjaCgvXig/OlthLXpdKzpcXC8qKT9bXlxcL10qLylbMF07XG4gICAgfVxuICAgIHN3aXRjaCAoaXJpWzBdKSB7XG4gICAgLy8gQW4gZW1wdHkgcmVsYXRpdmUgSVJJIGluZGljYXRlcyB0aGUgYmFzZSBJUklcbiAgICBjYXNlIHVuZGVmaW5lZDpcbiAgICAgIHJldHVybiBiYXNlO1xuICAgIC8vIFJlc29sdmUgcmVsYXRpdmUgZnJhZ21lbnQgSVJJcyBhZ2FpbnN0IHRoZSBiYXNlIElSSVxuICAgIGNhc2UgJyMnOlxuICAgICAgcmV0dXJuIGJhc2UgKyBpcmk7XG4gICAgLy8gUmVzb2x2ZSByZWxhdGl2ZSBxdWVyeSBzdHJpbmcgSVJJcyBieSByZXBsYWNpbmcgdGhlIHF1ZXJ5IHN0cmluZ1xuICAgIGNhc2UgJz8nOlxuICAgICAgcmV0dXJuIGJhc2UucmVwbGFjZSgvKD86XFw/LiopPyQvLCBpcmkpO1xuICAgIC8vIFJlc29sdmUgcm9vdCByZWxhdGl2ZSBJUklzIGF0IHRoZSByb290IG9mIHRoZSBiYXNlIElSSVxuICAgIGNhc2UgJy8nOlxuICAgICAgcmV0dXJuIGJhc2VSb290ICsgaXJpO1xuICAgIC8vIFJlc29sdmUgYWxsIG90aGVyIElSSXMgYXQgdGhlIGJhc2UgSVJJJ3MgcGF0aFxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gYmFzZVBhdGggKyBpcmk7XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgdGhlIGl0ZW0gaXMgYSB2YXJpYWJsZSwgZW5zdXJlcyBpdCBzdGFydHMgd2l0aCBhIHF1ZXN0aW9uIG1hcmtcbiAgZnVuY3Rpb24gdG9WYXIodmFyaWFibGUpIHtcbiAgICBpZiAodmFyaWFibGUpIHtcbiAgICAgIHZhciBmaXJzdCA9IHZhcmlhYmxlWzBdO1xuICAgICAgaWYgKGZpcnN0ID09PSAnPycpIHJldHVybiB2YXJpYWJsZTtcbiAgICAgIGlmIChmaXJzdCA9PT0gJyQnKSByZXR1cm4gJz8nICsgdmFyaWFibGUuc3Vic3RyKDEpO1xuICAgIH1cbiAgICByZXR1cm4gdmFyaWFibGU7XG4gIH1cblxuICAvLyBDcmVhdGVzIGFuIG9wZXJhdGlvbiB3aXRoIHRoZSBnaXZlbiBuYW1lIGFuZCBhcmd1bWVudHNcbiAgZnVuY3Rpb24gb3BlcmF0aW9uKG9wZXJhdG9yTmFtZSwgYXJncykge1xuICAgIHJldHVybiB7IHR5cGU6ICdvcGVyYXRpb24nLCBvcGVyYXRvcjogb3BlcmF0b3JOYW1lLCBhcmdzOiBhcmdzIHx8IFtdIH07XG4gIH1cblxuICAvLyBDcmVhdGVzIGFuIGV4cHJlc3Npb24gd2l0aCB0aGUgZ2l2ZW4gdHlwZSBhbmQgYXR0cmlidXRlc1xuICBmdW5jdGlvbiBleHByZXNzaW9uKGV4cHIsIGF0dHIpIHtcbiAgICB2YXIgZXhwcmVzc2lvbiA9IHsgZXhwcmVzc2lvbjogZXhwciB9O1xuICAgIGlmIChhdHRyKVxuICAgICAgZm9yICh2YXIgYSBpbiBhdHRyKVxuICAgICAgICBleHByZXNzaW9uW2FdID0gYXR0clthXTtcbiAgICByZXR1cm4gZXhwcmVzc2lvbjtcbiAgfVxuXG4gIC8vIENyZWF0ZXMgYSBwYXRoIHdpdGggdGhlIGdpdmVuIHR5cGUgYW5kIGl0ZW1zXG4gIGZ1bmN0aW9uIHBhdGgodHlwZSwgaXRlbXMpIHtcbiAgICByZXR1cm4geyB0eXBlOiAncGF0aCcsIHBhdGhUeXBlOiB0eXBlLCBpdGVtczogaXRlbXMgfTtcbiAgfVxuXG4gIC8vIFRyYW5zZm9ybXMgYSBsaXN0IG9mIG9wZXJhdGlvbnMgdHlwZXMgYW5kIGFyZ3VtZW50cyBpbnRvIGEgdHJlZSBvZiBvcGVyYXRpb25zXG4gIGZ1bmN0aW9uIGNyZWF0ZU9wZXJhdGlvblRyZWUoaW5pdGlhbEV4cHJlc3Npb24sIG9wZXJhdGlvbkxpc3QpIHtcbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IG9wZXJhdGlvbkxpc3QubGVuZ3RoLCBpdGVtOyBpIDwgbCAmJiAoaXRlbSA9IG9wZXJhdGlvbkxpc3RbaV0pOyBpKyspXG4gICAgICBpbml0aWFsRXhwcmVzc2lvbiA9IG9wZXJhdGlvbihpdGVtWzBdLCBbaW5pdGlhbEV4cHJlc3Npb24sIGl0ZW1bMV1dKTtcbiAgICByZXR1cm4gaW5pdGlhbEV4cHJlc3Npb247XG4gIH1cblxuICAvLyBHcm91cCBkYXRhc2V0cyBieSBkZWZhdWx0IGFuZCBuYW1lZFxuICBmdW5jdGlvbiBncm91cERhdGFzZXRzKGZyb21DbGF1c2VzKSB7XG4gICAgdmFyIGRlZmF1bHRzID0gW10sIG5hbWVkID0gW10sIGwgPSBmcm9tQ2xhdXNlcy5sZW5ndGgsIGZyb21DbGF1c2U7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsICYmIChmcm9tQ2xhdXNlID0gZnJvbUNsYXVzZXNbaV0pOyBpKyspXG4gICAgICAoZnJvbUNsYXVzZS5uYW1lZCA/IG5hbWVkIDogZGVmYXVsdHMpLnB1c2goZnJvbUNsYXVzZS5pcmkpO1xuICAgIHJldHVybiBsID8geyBmcm9tOiB7IGRlZmF1bHQ6IGRlZmF1bHRzLCBuYW1lZDogbmFtZWQgfSB9IDogbnVsbDtcbiAgfVxuXG4gIC8vIENvbnZlcnRzIHRoZSBudW1iZXIgdG8gYSBzdHJpbmdcbiAgZnVuY3Rpb24gdG9JbnQoc3RyaW5nKSB7XG4gICAgcmV0dXJuIHBhcnNlSW50KHN0cmluZywgMTApO1xuICB9XG5cbiAgLy8gVHJhbnNmb3JtcyBhIHBvc3NpYmx5IHNpbmdsZSBncm91cCBpbnRvIGl0cyBwYXR0ZXJuc1xuICBmdW5jdGlvbiBkZWdyb3VwU2luZ2xlKGdyb3VwKSB7XG4gICAgcmV0dXJuIGdyb3VwLnR5cGUgPT09ICdncm91cCcgJiYgZ3JvdXAucGF0dGVybnMubGVuZ3RoID09PSAxID8gZ3JvdXAucGF0dGVybnNbMF0gOiBncm91cDtcbiAgfVxuXG4gIC8vIENyZWF0ZXMgYSBsaXRlcmFsIHdpdGggdGhlIGdpdmVuIHZhbHVlIGFuZCB0eXBlXG4gIGZ1bmN0aW9uIGNyZWF0ZUxpdGVyYWwodmFsdWUsIHR5cGUpIHtcbiAgICByZXR1cm4gJ1wiJyArIHZhbHVlICsgJ1wiXl4nICsgdHlwZTtcbiAgfVxuXG4gIC8vIENyZWF0ZXMgYSB0cmlwbGUgd2l0aCB0aGUgZ2l2ZW4gc3ViamVjdCwgcHJlZGljYXRlLCBhbmQgb2JqZWN0XG4gIGZ1bmN0aW9uIHRyaXBsZShzdWJqZWN0LCBwcmVkaWNhdGUsIG9iamVjdCkge1xuICAgIHZhciB0cmlwbGUgPSB7fTtcbiAgICBpZiAoc3ViamVjdCAgICE9IG51bGwpIHRyaXBsZS5zdWJqZWN0ICAgPSBzdWJqZWN0O1xuICAgIGlmIChwcmVkaWNhdGUgIT0gbnVsbCkgdHJpcGxlLnByZWRpY2F0ZSA9IHByZWRpY2F0ZTtcbiAgICBpZiAob2JqZWN0ICAgICE9IG51bGwpIHRyaXBsZS5vYmplY3QgICAgPSBvYmplY3Q7XG4gICAgcmV0dXJuIHRyaXBsZTtcbiAgfVxuXG4gIC8vIENyZWF0ZXMgYSBuZXcgYmxhbmsgbm9kZSBpZGVudGlmaWVyXG4gIGZ1bmN0aW9uIGJsYW5rKCkge1xuICAgIHJldHVybiAnXzpiJyArIGJsYW5rSWQrKztcbiAgfTtcbiAgdmFyIGJsYW5rSWQgPSAwO1xuICBQYXJzZXIuX3Jlc2V0QmxhbmtzID0gZnVuY3Rpb24gKCkgeyBibGFua0lkID0gMDsgfVxuXG4gIC8vIFJlZ3VsYXIgZXhwcmVzc2lvbiBhbmQgcmVwbGFjZW1lbnQgc3RyaW5ncyB0byBlc2NhcGUgc3RyaW5nc1xuICB2YXIgZXNjYXBlU2VxdWVuY2UgPSAvXFxcXHUoW2EtZkEtRjAtOV17NH0pfFxcXFxVKFthLWZBLUYwLTldezh9KXxcXFxcKC4pL2csXG4gICAgICBlc2NhcGVSZXBsYWNlbWVudHMgPSB7ICdcXFxcJzogJ1xcXFwnLCBcIidcIjogXCInXCIsICdcIic6ICdcIicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICd0JzogJ1xcdCcsICdiJzogJ1xcYicsICduJzogJ1xcbicsICdyJzogJ1xccicsICdmJzogJ1xcZicgfSxcbiAgICAgIGZyb21DaGFyQ29kZSA9IFN0cmluZy5mcm9tQ2hhckNvZGU7XG5cbiAgLy8gVHJhbnNsYXRlcyBlc2NhcGUgY29kZXMgaW4gdGhlIHN0cmluZyBpbnRvIHRoZWlyIHRleHR1YWwgZXF1aXZhbGVudFxuICBmdW5jdGlvbiB1bmVzY2FwZVN0cmluZyhzdHJpbmcsIHRyaW1MZW5ndGgpIHtcbiAgICBzdHJpbmcgPSBzdHJpbmcuc3Vic3RyaW5nKHRyaW1MZW5ndGgsIHN0cmluZy5sZW5ndGggLSB0cmltTGVuZ3RoKTtcbiAgICB0cnkge1xuICAgICAgc3RyaW5nID0gc3RyaW5nLnJlcGxhY2UoZXNjYXBlU2VxdWVuY2UsIGZ1bmN0aW9uIChzZXF1ZW5jZSwgdW5pY29kZTQsIHVuaWNvZGU4LCBlc2NhcGVkQ2hhcikge1xuICAgICAgICB2YXIgY2hhckNvZGU7XG4gICAgICAgIGlmICh1bmljb2RlNCkge1xuICAgICAgICAgIGNoYXJDb2RlID0gcGFyc2VJbnQodW5pY29kZTQsIDE2KTtcbiAgICAgICAgICBpZiAoaXNOYU4oY2hhckNvZGUpKSB0aHJvdyBuZXcgRXJyb3IoKTsgLy8gY2FuIG5ldmVyIGhhcHBlbiAocmVnZXgpLCBidXQgaGVscHMgcGVyZm9ybWFuY2VcbiAgICAgICAgICByZXR1cm4gZnJvbUNoYXJDb2RlKGNoYXJDb2RlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh1bmljb2RlOCkge1xuICAgICAgICAgIGNoYXJDb2RlID0gcGFyc2VJbnQodW5pY29kZTgsIDE2KTtcbiAgICAgICAgICBpZiAoaXNOYU4oY2hhckNvZGUpKSB0aHJvdyBuZXcgRXJyb3IoKTsgLy8gY2FuIG5ldmVyIGhhcHBlbiAocmVnZXgpLCBidXQgaGVscHMgcGVyZm9ybWFuY2VcbiAgICAgICAgICBpZiAoY2hhckNvZGUgPCAweEZGRkYpIHJldHVybiBmcm9tQ2hhckNvZGUoY2hhckNvZGUpO1xuICAgICAgICAgIHJldHVybiBmcm9tQ2hhckNvZGUoMHhEODAwICsgKChjaGFyQ29kZSAtPSAweDEwMDAwKSA+PiAxMCksIDB4REMwMCArIChjaGFyQ29kZSAmIDB4M0ZGKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgdmFyIHJlcGxhY2VtZW50ID0gZXNjYXBlUmVwbGFjZW1lbnRzW2VzY2FwZWRDaGFyXTtcbiAgICAgICAgICBpZiAoIXJlcGxhY2VtZW50KSB0aHJvdyBuZXcgRXJyb3IoKTtcbiAgICAgICAgICByZXR1cm4gcmVwbGFjZW1lbnQ7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgICBjYXRjaCAoZXJyb3IpIHsgcmV0dXJuICcnOyB9XG4gICAgcmV0dXJuICdcIicgKyBzdHJpbmcgKyAnXCInO1xuICB9XG5cbiAgLy8gQ3JlYXRlcyBhIGxpc3QsIGNvbGxlY3RpbmcgaXRzIChwb3NzaWJseSBibGFuaykgaXRlbXMgYW5kIHRyaXBsZXMgYXNzb2NpYXRlZCB3aXRoIHRob3NlIGl0ZW1zXG4gIGZ1bmN0aW9uIGNyZWF0ZUxpc3Qob2JqZWN0cykge1xuICAgIHZhciBsaXN0ID0gYmxhbmsoKSwgaGVhZCA9IGxpc3QsIGxpc3RJdGVtcyA9IFtdLCBsaXN0VHJpcGxlcywgdHJpcGxlcyA9IFtdO1xuICAgIG9iamVjdHMuZm9yRWFjaChmdW5jdGlvbiAobykgeyBsaXN0SXRlbXMucHVzaChvLmVudGl0eSk7IGFwcGVuZEFsbFRvKHRyaXBsZXMsIG8udHJpcGxlcyk7IH0pO1xuXG4gICAgLy8gQnVpbGQgYW4gUkRGIGxpc3Qgb3V0IG9mIHRoZSBpdGVtc1xuICAgIGZvciAodmFyIGkgPSAwLCBqID0gMCwgbCA9IGxpc3RJdGVtcy5sZW5ndGgsIGxpc3RUcmlwbGVzID0gQXJyYXkobCAqIDIpOyBpIDwgbDspXG4gICAgICBsaXN0VHJpcGxlc1tqKytdID0gdHJpcGxlKGhlYWQsIFJERl9GSVJTVCwgbGlzdEl0ZW1zW2ldKSxcbiAgICAgIGxpc3RUcmlwbGVzW2orK10gPSB0cmlwbGUoaGVhZCwgUkRGX1JFU1QsICBoZWFkID0gKytpIDwgbCA/IGJsYW5rKCkgOiBSREZfTklMKTtcblxuICAgIC8vIFJldHVybiB0aGUgbGlzdCdzIGlkZW50aWZpZXIsIGl0cyB0cmlwbGVzLCBhbmQgdGhlIHRyaXBsZXMgYXNzb2NpYXRlZCB3aXRoIGl0cyBpdGVtc1xuICAgIHJldHVybiB7IGVudGl0eTogbGlzdCwgdHJpcGxlczogYXBwZW5kQWxsVG8obGlzdFRyaXBsZXMsIHRyaXBsZXMpIH07XG4gIH1cblxuICAvLyBDcmVhdGVzIGEgYmxhbmsgbm9kZSBpZGVudGlmaWVyLCBjb2xsZWN0aW5nIHRyaXBsZXMgd2l0aCB0aGF0IGJsYW5rIG5vZGUgYXMgc3ViamVjdFxuICBmdW5jdGlvbiBjcmVhdGVBbm9ueW1vdXNPYmplY3QocHJvcGVydHlMaXN0KSB7XG4gICAgdmFyIGVudGl0eSA9IGJsYW5rKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGVudGl0eTogZW50aXR5LFxuICAgICAgdHJpcGxlczogcHJvcGVydHlMaXN0Lm1hcChmdW5jdGlvbiAodCkgeyByZXR1cm4gZXh0ZW5kKHRyaXBsZShlbnRpdHkpLCB0KTsgfSlcbiAgICB9O1xuICB9XG5cbiAgLy8gQ29sbGVjdHMgYWxsIChwb3NzaWJseSBibGFuaykgb2JqZWN0cywgYW5kIHRyaXBsZXMgdGhhdCBoYXZlIHRoZW0gYXMgc3ViamVjdFxuICBmdW5jdGlvbiBvYmplY3RMaXN0VG9UcmlwbGVzKHByZWRpY2F0ZSwgb2JqZWN0TGlzdCwgb3RoZXJUcmlwbGVzKSB7XG4gICAgdmFyIG9iamVjdHMgPSBbXSwgdHJpcGxlcyA9IFtdO1xuICAgIG9iamVjdExpc3QuZm9yRWFjaChmdW5jdGlvbiAobCkge1xuICAgICAgb2JqZWN0cy5wdXNoKHRyaXBsZShudWxsLCBwcmVkaWNhdGUsIGwuZW50aXR5KSk7XG4gICAgICBhcHBlbmRBbGxUbyh0cmlwbGVzLCBsLnRyaXBsZXMpO1xuICAgIH0pO1xuICAgIHJldHVybiB1bmlvbkFsbChvYmplY3RzLCBvdGhlclRyaXBsZXMgfHwgW10sIHRyaXBsZXMpO1xuICB9XG5cbiAgLy8gU2ltcGxpZmllcyBncm91cHMgYnkgbWVyZ2luZyBhZGphY2VudCBCR1BzXG4gIGZ1bmN0aW9uIG1lcmdlQWRqYWNlbnRCR1BzKGdyb3Vwcykge1xuICAgIHZhciBtZXJnZWQgPSBbXSwgY3VycmVudEJncDtcbiAgICBmb3IgKHZhciBpID0gMCwgZ3JvdXA7IGdyb3VwID0gZ3JvdXBzW2ldOyBpKyspIHtcbiAgICAgIHN3aXRjaCAoZ3JvdXAudHlwZSkge1xuICAgICAgICAvLyBBZGQgYSBCR1AncyB0cmlwbGVzIHRvIHRoZSBjdXJyZW50IEJHUFxuICAgICAgICBjYXNlICdiZ3AnOlxuICAgICAgICAgIGlmIChncm91cC50cmlwbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgaWYgKCFjdXJyZW50QmdwKVxuICAgICAgICAgICAgICBhcHBlbmRUbyhtZXJnZWQsIGN1cnJlbnRCZ3AgPSBncm91cCk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgIGFwcGVuZEFsbFRvKGN1cnJlbnRCZ3AudHJpcGxlcywgZ3JvdXAudHJpcGxlcyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvLyBBbGwgb3RoZXIgZ3JvdXBzIGJyZWFrIHVwIGEgQkdQXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgLy8gT25seSBhZGQgdGhlIGdyb3VwIGlmIGl0cyBwYXR0ZXJuIGlzIG5vbi1lbXB0eVxuICAgICAgICAgIGlmICghZ3JvdXAucGF0dGVybnMgfHwgZ3JvdXAucGF0dGVybnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgYXBwZW5kVG8obWVyZ2VkLCBncm91cCk7XG4gICAgICAgICAgICBjdXJyZW50QmdwID0gbnVsbDtcbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBtZXJnZWQ7XG4gIH1cbi8qIGdlbmVyYXRlZCBieSBqaXNvbi1sZXggMC4zLjQgKi9cbnZhciBsZXhlciA9IChmdW5jdGlvbigpe1xudmFyIGxleGVyID0gKHtcblxuRU9GOjEsXG5cbnBhcnNlRXJyb3I6ZnVuY3Rpb24gcGFyc2VFcnJvcihzdHIsIGhhc2gpIHtcbiAgICAgICAgaWYgKHRoaXMueXkucGFyc2VyKSB7XG4gICAgICAgICAgICB0aGlzLnl5LnBhcnNlci5wYXJzZUVycm9yKHN0ciwgaGFzaCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3Ioc3RyKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbi8vIHJlc2V0cyB0aGUgbGV4ZXIsIHNldHMgbmV3IGlucHV0XG5zZXRJbnB1dDpmdW5jdGlvbiAoaW5wdXQsIHl5KSB7XG4gICAgICAgIHRoaXMueXkgPSB5eSB8fCB0aGlzLnl5IHx8IHt9O1xuICAgICAgICB0aGlzLl9pbnB1dCA9IGlucHV0O1xuICAgICAgICB0aGlzLl9tb3JlID0gdGhpcy5fYmFja3RyYWNrID0gdGhpcy5kb25lID0gZmFsc2U7XG4gICAgICAgIHRoaXMueXlsaW5lbm8gPSB0aGlzLnl5bGVuZyA9IDA7XG4gICAgICAgIHRoaXMueXl0ZXh0ID0gdGhpcy5tYXRjaGVkID0gdGhpcy5tYXRjaCA9ICcnO1xuICAgICAgICB0aGlzLmNvbmRpdGlvblN0YWNrID0gWydJTklUSUFMJ107XG4gICAgICAgIHRoaXMueXlsbG9jID0ge1xuICAgICAgICAgICAgZmlyc3RfbGluZTogMSxcbiAgICAgICAgICAgIGZpcnN0X2NvbHVtbjogMCxcbiAgICAgICAgICAgIGxhc3RfbGluZTogMSxcbiAgICAgICAgICAgIGxhc3RfY29sdW1uOiAwXG4gICAgICAgIH07XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMucmFuZ2VzKSB7XG4gICAgICAgICAgICB0aGlzLnl5bGxvYy5yYW5nZSA9IFswLDBdO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub2Zmc2V0ID0gMDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuLy8gY29uc3VtZXMgYW5kIHJldHVybnMgb25lIGNoYXIgZnJvbSB0aGUgaW5wdXRcbmlucHV0OmZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNoID0gdGhpcy5faW5wdXRbMF07XG4gICAgICAgIHRoaXMueXl0ZXh0ICs9IGNoO1xuICAgICAgICB0aGlzLnl5bGVuZysrO1xuICAgICAgICB0aGlzLm9mZnNldCsrO1xuICAgICAgICB0aGlzLm1hdGNoICs9IGNoO1xuICAgICAgICB0aGlzLm1hdGNoZWQgKz0gY2g7XG4gICAgICAgIHZhciBsaW5lcyA9IGNoLm1hdGNoKC8oPzpcXHJcXG4/fFxcbikuKi9nKTtcbiAgICAgICAgaWYgKGxpbmVzKSB7XG4gICAgICAgICAgICB0aGlzLnl5bGluZW5vKys7XG4gICAgICAgICAgICB0aGlzLnl5bGxvYy5sYXN0X2xpbmUrKztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMueXlsbG9jLmxhc3RfY29sdW1uKys7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5yYW5nZXMpIHtcbiAgICAgICAgICAgIHRoaXMueXlsbG9jLnJhbmdlWzFdKys7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9pbnB1dCA9IHRoaXMuX2lucHV0LnNsaWNlKDEpO1xuICAgICAgICByZXR1cm4gY2g7XG4gICAgfSxcblxuLy8gdW5zaGlmdHMgb25lIGNoYXIgKG9yIGEgc3RyaW5nKSBpbnRvIHRoZSBpbnB1dFxudW5wdXQ6ZnVuY3Rpb24gKGNoKSB7XG4gICAgICAgIHZhciBsZW4gPSBjaC5sZW5ndGg7XG4gICAgICAgIHZhciBsaW5lcyA9IGNoLnNwbGl0KC8oPzpcXHJcXG4/fFxcbikvZyk7XG5cbiAgICAgICAgdGhpcy5faW5wdXQgPSBjaCArIHRoaXMuX2lucHV0O1xuICAgICAgICB0aGlzLnl5dGV4dCA9IHRoaXMueXl0ZXh0LnN1YnN0cigwLCB0aGlzLnl5dGV4dC5sZW5ndGggLSBsZW4pO1xuICAgICAgICAvL3RoaXMueXlsZW5nIC09IGxlbjtcbiAgICAgICAgdGhpcy5vZmZzZXQgLT0gbGVuO1xuICAgICAgICB2YXIgb2xkTGluZXMgPSB0aGlzLm1hdGNoLnNwbGl0KC8oPzpcXHJcXG4/fFxcbikvZyk7XG4gICAgICAgIHRoaXMubWF0Y2ggPSB0aGlzLm1hdGNoLnN1YnN0cigwLCB0aGlzLm1hdGNoLmxlbmd0aCAtIDEpO1xuICAgICAgICB0aGlzLm1hdGNoZWQgPSB0aGlzLm1hdGNoZWQuc3Vic3RyKDAsIHRoaXMubWF0Y2hlZC5sZW5ndGggLSAxKTtcblxuICAgICAgICBpZiAobGluZXMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgdGhpcy55eWxpbmVubyAtPSBsaW5lcy5sZW5ndGggLSAxO1xuICAgICAgICB9XG4gICAgICAgIHZhciByID0gdGhpcy55eWxsb2MucmFuZ2U7XG5cbiAgICAgICAgdGhpcy55eWxsb2MgPSB7XG4gICAgICAgICAgICBmaXJzdF9saW5lOiB0aGlzLnl5bGxvYy5maXJzdF9saW5lLFxuICAgICAgICAgICAgbGFzdF9saW5lOiB0aGlzLnl5bGluZW5vICsgMSxcbiAgICAgICAgICAgIGZpcnN0X2NvbHVtbjogdGhpcy55eWxsb2MuZmlyc3RfY29sdW1uLFxuICAgICAgICAgICAgbGFzdF9jb2x1bW46IGxpbmVzID9cbiAgICAgICAgICAgICAgICAobGluZXMubGVuZ3RoID09PSBvbGRMaW5lcy5sZW5ndGggPyB0aGlzLnl5bGxvYy5maXJzdF9jb2x1bW4gOiAwKVxuICAgICAgICAgICAgICAgICArIG9sZExpbmVzW29sZExpbmVzLmxlbmd0aCAtIGxpbmVzLmxlbmd0aF0ubGVuZ3RoIC0gbGluZXNbMF0ubGVuZ3RoIDpcbiAgICAgICAgICAgICAgdGhpcy55eWxsb2MuZmlyc3RfY29sdW1uIC0gbGVuXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5yYW5nZXMpIHtcbiAgICAgICAgICAgIHRoaXMueXlsbG9jLnJhbmdlID0gW3JbMF0sIHJbMF0gKyB0aGlzLnl5bGVuZyAtIGxlbl07XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy55eWxlbmcgPSB0aGlzLnl5dGV4dC5sZW5ndGg7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbi8vIFdoZW4gY2FsbGVkIGZyb20gYWN0aW9uLCBjYWNoZXMgbWF0Y2hlZCB0ZXh0IGFuZCBhcHBlbmRzIGl0IG9uIG5leHQgYWN0aW9uXG5tb3JlOmZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5fbW9yZSA9IHRydWU7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbi8vIFdoZW4gY2FsbGVkIGZyb20gYWN0aW9uLCBzaWduYWxzIHRoZSBsZXhlciB0aGF0IHRoaXMgcnVsZSBmYWlscyB0byBtYXRjaCB0aGUgaW5wdXQsIHNvIHRoZSBuZXh0IG1hdGNoaW5nIHJ1bGUgKHJlZ2V4KSBzaG91bGQgYmUgdGVzdGVkIGluc3RlYWQuXG5yZWplY3Q6ZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmJhY2t0cmFja19sZXhlcikge1xuICAgICAgICAgICAgdGhpcy5fYmFja3RyYWNrID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcnNlRXJyb3IoJ0xleGljYWwgZXJyb3Igb24gbGluZSAnICsgKHRoaXMueXlsaW5lbm8gKyAxKSArICcuIFlvdSBjYW4gb25seSBpbnZva2UgcmVqZWN0KCkgaW4gdGhlIGxleGVyIHdoZW4gdGhlIGxleGVyIGlzIG9mIHRoZSBiYWNrdHJhY2tpbmcgcGVyc3Vhc2lvbiAob3B0aW9ucy5iYWNrdHJhY2tfbGV4ZXIgPSB0cnVlKS5cXG4nICsgdGhpcy5zaG93UG9zaXRpb24oKSwge1xuICAgICAgICAgICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgICAgICAgICAgdG9rZW46IG51bGwsXG4gICAgICAgICAgICAgICAgbGluZTogdGhpcy55eWxpbmVub1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4vLyByZXRhaW4gZmlyc3QgbiBjaGFyYWN0ZXJzIG9mIHRoZSBtYXRjaFxubGVzczpmdW5jdGlvbiAobikge1xuICAgICAgICB0aGlzLnVucHV0KHRoaXMubWF0Y2guc2xpY2UobikpO1xuICAgIH0sXG5cbi8vIGRpc3BsYXlzIGFscmVhZHkgbWF0Y2hlZCBpbnB1dCwgaS5lLiBmb3IgZXJyb3IgbWVzc2FnZXNcbnBhc3RJbnB1dDpmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBwYXN0ID0gdGhpcy5tYXRjaGVkLnN1YnN0cigwLCB0aGlzLm1hdGNoZWQubGVuZ3RoIC0gdGhpcy5tYXRjaC5sZW5ndGgpO1xuICAgICAgICByZXR1cm4gKHBhc3QubGVuZ3RoID4gMjAgPyAnLi4uJzonJykgKyBwYXN0LnN1YnN0cigtMjApLnJlcGxhY2UoL1xcbi9nLCBcIlwiKTtcbiAgICB9LFxuXG4vLyBkaXNwbGF5cyB1cGNvbWluZyBpbnB1dCwgaS5lLiBmb3IgZXJyb3IgbWVzc2FnZXNcbnVwY29taW5nSW5wdXQ6ZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgbmV4dCA9IHRoaXMubWF0Y2g7XG4gICAgICAgIGlmIChuZXh0Lmxlbmd0aCA8IDIwKSB7XG4gICAgICAgICAgICBuZXh0ICs9IHRoaXMuX2lucHV0LnN1YnN0cigwLCAyMC1uZXh0Lmxlbmd0aCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIChuZXh0LnN1YnN0cigwLDIwKSArIChuZXh0Lmxlbmd0aCA+IDIwID8gJy4uLicgOiAnJykpLnJlcGxhY2UoL1xcbi9nLCBcIlwiKTtcbiAgICB9LFxuXG4vLyBkaXNwbGF5cyB0aGUgY2hhcmFjdGVyIHBvc2l0aW9uIHdoZXJlIHRoZSBsZXhpbmcgZXJyb3Igb2NjdXJyZWQsIGkuZS4gZm9yIGVycm9yIG1lc3NhZ2VzXG5zaG93UG9zaXRpb246ZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgcHJlID0gdGhpcy5wYXN0SW5wdXQoKTtcbiAgICAgICAgdmFyIGMgPSBuZXcgQXJyYXkocHJlLmxlbmd0aCArIDEpLmpvaW4oXCItXCIpO1xuICAgICAgICByZXR1cm4gcHJlICsgdGhpcy51cGNvbWluZ0lucHV0KCkgKyBcIlxcblwiICsgYyArIFwiXlwiO1xuICAgIH0sXG5cbi8vIHRlc3QgdGhlIGxleGVkIHRva2VuOiByZXR1cm4gRkFMU0Ugd2hlbiBub3QgYSBtYXRjaCwgb3RoZXJ3aXNlIHJldHVybiB0b2tlblxudGVzdF9tYXRjaDpmdW5jdGlvbihtYXRjaCwgaW5kZXhlZF9ydWxlKSB7XG4gICAgICAgIHZhciB0b2tlbixcbiAgICAgICAgICAgIGxpbmVzLFxuICAgICAgICAgICAgYmFja3VwO1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuYmFja3RyYWNrX2xleGVyKSB7XG4gICAgICAgICAgICAvLyBzYXZlIGNvbnRleHRcbiAgICAgICAgICAgIGJhY2t1cCA9IHtcbiAgICAgICAgICAgICAgICB5eWxpbmVubzogdGhpcy55eWxpbmVubyxcbiAgICAgICAgICAgICAgICB5eWxsb2M6IHtcbiAgICAgICAgICAgICAgICAgICAgZmlyc3RfbGluZTogdGhpcy55eWxsb2MuZmlyc3RfbGluZSxcbiAgICAgICAgICAgICAgICAgICAgbGFzdF9saW5lOiB0aGlzLmxhc3RfbGluZSxcbiAgICAgICAgICAgICAgICAgICAgZmlyc3RfY29sdW1uOiB0aGlzLnl5bGxvYy5maXJzdF9jb2x1bW4sXG4gICAgICAgICAgICAgICAgICAgIGxhc3RfY29sdW1uOiB0aGlzLnl5bGxvYy5sYXN0X2NvbHVtblxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgeXl0ZXh0OiB0aGlzLnl5dGV4dCxcbiAgICAgICAgICAgICAgICBtYXRjaDogdGhpcy5tYXRjaCxcbiAgICAgICAgICAgICAgICBtYXRjaGVzOiB0aGlzLm1hdGNoZXMsXG4gICAgICAgICAgICAgICAgbWF0Y2hlZDogdGhpcy5tYXRjaGVkLFxuICAgICAgICAgICAgICAgIHl5bGVuZzogdGhpcy55eWxlbmcsXG4gICAgICAgICAgICAgICAgb2Zmc2V0OiB0aGlzLm9mZnNldCxcbiAgICAgICAgICAgICAgICBfbW9yZTogdGhpcy5fbW9yZSxcbiAgICAgICAgICAgICAgICBfaW5wdXQ6IHRoaXMuX2lucHV0LFxuICAgICAgICAgICAgICAgIHl5OiB0aGlzLnl5LFxuICAgICAgICAgICAgICAgIGNvbmRpdGlvblN0YWNrOiB0aGlzLmNvbmRpdGlvblN0YWNrLnNsaWNlKDApLFxuICAgICAgICAgICAgICAgIGRvbmU6IHRoaXMuZG9uZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMucmFuZ2VzKSB7XG4gICAgICAgICAgICAgICAgYmFja3VwLnl5bGxvYy5yYW5nZSA9IHRoaXMueXlsbG9jLnJhbmdlLnNsaWNlKDApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbGluZXMgPSBtYXRjaFswXS5tYXRjaCgvKD86XFxyXFxuP3xcXG4pLiovZyk7XG4gICAgICAgIGlmIChsaW5lcykge1xuICAgICAgICAgICAgdGhpcy55eWxpbmVubyArPSBsaW5lcy5sZW5ndGg7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy55eWxsb2MgPSB7XG4gICAgICAgICAgICBmaXJzdF9saW5lOiB0aGlzLnl5bGxvYy5sYXN0X2xpbmUsXG4gICAgICAgICAgICBsYXN0X2xpbmU6IHRoaXMueXlsaW5lbm8gKyAxLFxuICAgICAgICAgICAgZmlyc3RfY29sdW1uOiB0aGlzLnl5bGxvYy5sYXN0X2NvbHVtbixcbiAgICAgICAgICAgIGxhc3RfY29sdW1uOiBsaW5lcyA/XG4gICAgICAgICAgICAgICAgICAgICAgICAgbGluZXNbbGluZXMubGVuZ3RoIC0gMV0ubGVuZ3RoIC0gbGluZXNbbGluZXMubGVuZ3RoIC0gMV0ubWF0Y2goL1xccj9cXG4/LylbMF0ubGVuZ3RoIDpcbiAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnl5bGxvYy5sYXN0X2NvbHVtbiArIG1hdGNoWzBdLmxlbmd0aFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLnl5dGV4dCArPSBtYXRjaFswXTtcbiAgICAgICAgdGhpcy5tYXRjaCArPSBtYXRjaFswXTtcbiAgICAgICAgdGhpcy5tYXRjaGVzID0gbWF0Y2g7XG4gICAgICAgIHRoaXMueXlsZW5nID0gdGhpcy55eXRleHQubGVuZ3RoO1xuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnJhbmdlcykge1xuICAgICAgICAgICAgdGhpcy55eWxsb2MucmFuZ2UgPSBbdGhpcy5vZmZzZXQsIHRoaXMub2Zmc2V0ICs9IHRoaXMueXlsZW5nXTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9tb3JlID0gZmFsc2U7XG4gICAgICAgIHRoaXMuX2JhY2t0cmFjayA9IGZhbHNlO1xuICAgICAgICB0aGlzLl9pbnB1dCA9IHRoaXMuX2lucHV0LnNsaWNlKG1hdGNoWzBdLmxlbmd0aCk7XG4gICAgICAgIHRoaXMubWF0Y2hlZCArPSBtYXRjaFswXTtcbiAgICAgICAgdG9rZW4gPSB0aGlzLnBlcmZvcm1BY3Rpb24uY2FsbCh0aGlzLCB0aGlzLnl5LCB0aGlzLCBpbmRleGVkX3J1bGUsIHRoaXMuY29uZGl0aW9uU3RhY2tbdGhpcy5jb25kaXRpb25TdGFjay5sZW5ndGggLSAxXSk7XG4gICAgICAgIGlmICh0aGlzLmRvbmUgJiYgdGhpcy5faW5wdXQpIHtcbiAgICAgICAgICAgIHRoaXMuZG9uZSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0b2tlbikge1xuICAgICAgICAgICAgcmV0dXJuIHRva2VuO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2JhY2t0cmFjaykge1xuICAgICAgICAgICAgLy8gcmVjb3ZlciBjb250ZXh0XG4gICAgICAgICAgICBmb3IgKHZhciBrIGluIGJhY2t1cCkge1xuICAgICAgICAgICAgICAgIHRoaXNba10gPSBiYWNrdXBba107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7IC8vIHJ1bGUgYWN0aW9uIGNhbGxlZCByZWplY3QoKSBpbXBseWluZyB0aGUgbmV4dCBydWxlIHNob3VsZCBiZSB0ZXN0ZWQgaW5zdGVhZC5cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSxcblxuLy8gcmV0dXJuIG5leHQgbWF0Y2ggaW4gaW5wdXRcbm5leHQ6ZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy5kb25lKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5FT0Y7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLl9pbnB1dCkge1xuICAgICAgICAgICAgdGhpcy5kb25lID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB0b2tlbixcbiAgICAgICAgICAgIG1hdGNoLFxuICAgICAgICAgICAgdGVtcE1hdGNoLFxuICAgICAgICAgICAgaW5kZXg7XG4gICAgICAgIGlmICghdGhpcy5fbW9yZSkge1xuICAgICAgICAgICAgdGhpcy55eXRleHQgPSAnJztcbiAgICAgICAgICAgIHRoaXMubWF0Y2ggPSAnJztcbiAgICAgICAgfVxuICAgICAgICB2YXIgcnVsZXMgPSB0aGlzLl9jdXJyZW50UnVsZXMoKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBydWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdGVtcE1hdGNoID0gdGhpcy5faW5wdXQubWF0Y2godGhpcy5ydWxlc1tydWxlc1tpXV0pO1xuICAgICAgICAgICAgaWYgKHRlbXBNYXRjaCAmJiAoIW1hdGNoIHx8IHRlbXBNYXRjaFswXS5sZW5ndGggPiBtYXRjaFswXS5sZW5ndGgpKSB7XG4gICAgICAgICAgICAgICAgbWF0Y2ggPSB0ZW1wTWF0Y2g7XG4gICAgICAgICAgICAgICAgaW5kZXggPSBpO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuYmFja3RyYWNrX2xleGVyKSB7XG4gICAgICAgICAgICAgICAgICAgIHRva2VuID0gdGhpcy50ZXN0X21hdGNoKHRlbXBNYXRjaCwgcnVsZXNbaV0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAodG9rZW4gIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fYmFja3RyYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtYXRjaCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7IC8vIHJ1bGUgYWN0aW9uIGNhbGxlZCByZWplY3QoKSBpbXBseWluZyBhIHJ1bGUgTUlTbWF0Y2guXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlbHNlOiB0aGlzIGlzIGEgbGV4ZXIgcnVsZSB3aGljaCBjb25zdW1lcyBpbnB1dCB3aXRob3V0IHByb2R1Y2luZyBhIHRva2VuIChlLmcuIHdoaXRlc3BhY2UpXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLm9wdGlvbnMuZmxleCkge1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgICAgICB0b2tlbiA9IHRoaXMudGVzdF9tYXRjaChtYXRjaCwgcnVsZXNbaW5kZXhdKTtcbiAgICAgICAgICAgIGlmICh0b2tlbiAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBlbHNlOiB0aGlzIGlzIGEgbGV4ZXIgcnVsZSB3aGljaCBjb25zdW1lcyBpbnB1dCB3aXRob3V0IHByb2R1Y2luZyBhIHRva2VuIChlLmcuIHdoaXRlc3BhY2UpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuX2lucHV0ID09PSBcIlwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5FT0Y7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJzZUVycm9yKCdMZXhpY2FsIGVycm9yIG9uIGxpbmUgJyArICh0aGlzLnl5bGluZW5vICsgMSkgKyAnLiBVbnJlY29nbml6ZWQgdGV4dC5cXG4nICsgdGhpcy5zaG93UG9zaXRpb24oKSwge1xuICAgICAgICAgICAgICAgIHRleHQ6IFwiXCIsXG4gICAgICAgICAgICAgICAgdG9rZW46IG51bGwsXG4gICAgICAgICAgICAgICAgbGluZTogdGhpcy55eWxpbmVub1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4vLyByZXR1cm4gbmV4dCBtYXRjaCB0aGF0IGhhcyBhIHRva2VuXG5sZXg6ZnVuY3Rpb24gbGV4ICgpIHtcbiAgICAgICAgdmFyIHIgPSB0aGlzLm5leHQoKTtcbiAgICAgICAgaWYgKHIpIHtcbiAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubGV4KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4vLyBhY3RpdmF0ZXMgYSBuZXcgbGV4ZXIgY29uZGl0aW9uIHN0YXRlIChwdXNoZXMgdGhlIG5ldyBsZXhlciBjb25kaXRpb24gc3RhdGUgb250byB0aGUgY29uZGl0aW9uIHN0YWNrKVxuYmVnaW46ZnVuY3Rpb24gYmVnaW4gKGNvbmRpdGlvbikge1xuICAgICAgICB0aGlzLmNvbmRpdGlvblN0YWNrLnB1c2goY29uZGl0aW9uKTtcbiAgICB9LFxuXG4vLyBwb3AgdGhlIHByZXZpb3VzbHkgYWN0aXZlIGxleGVyIGNvbmRpdGlvbiBzdGF0ZSBvZmYgdGhlIGNvbmRpdGlvbiBzdGFja1xucG9wU3RhdGU6ZnVuY3Rpb24gcG9wU3RhdGUgKCkge1xuICAgICAgICB2YXIgbiA9IHRoaXMuY29uZGl0aW9uU3RhY2subGVuZ3RoIC0gMTtcbiAgICAgICAgaWYgKG4gPiAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb25kaXRpb25TdGFjay5wb3AoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmRpdGlvblN0YWNrWzBdO1xuICAgICAgICB9XG4gICAgfSxcblxuLy8gcHJvZHVjZSB0aGUgbGV4ZXIgcnVsZSBzZXQgd2hpY2ggaXMgYWN0aXZlIGZvciB0aGUgY3VycmVudGx5IGFjdGl2ZSBsZXhlciBjb25kaXRpb24gc3RhdGVcbl9jdXJyZW50UnVsZXM6ZnVuY3Rpb24gX2N1cnJlbnRSdWxlcyAoKSB7XG4gICAgICAgIGlmICh0aGlzLmNvbmRpdGlvblN0YWNrLmxlbmd0aCAmJiB0aGlzLmNvbmRpdGlvblN0YWNrW3RoaXMuY29uZGl0aW9uU3RhY2subGVuZ3RoIC0gMV0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmRpdGlvbnNbdGhpcy5jb25kaXRpb25TdGFja1t0aGlzLmNvbmRpdGlvblN0YWNrLmxlbmd0aCAtIDFdXS5ydWxlcztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmRpdGlvbnNbXCJJTklUSUFMXCJdLnJ1bGVzO1xuICAgICAgICB9XG4gICAgfSxcblxuLy8gcmV0dXJuIHRoZSBjdXJyZW50bHkgYWN0aXZlIGxleGVyIGNvbmRpdGlvbiBzdGF0ZTsgd2hlbiBhbiBpbmRleCBhcmd1bWVudCBpcyBwcm92aWRlZCBpdCBwcm9kdWNlcyB0aGUgTi10aCBwcmV2aW91cyBjb25kaXRpb24gc3RhdGUsIGlmIGF2YWlsYWJsZVxudG9wU3RhdGU6ZnVuY3Rpb24gdG9wU3RhdGUgKG4pIHtcbiAgICAgICAgbiA9IHRoaXMuY29uZGl0aW9uU3RhY2subGVuZ3RoIC0gMSAtIE1hdGguYWJzKG4gfHwgMCk7XG4gICAgICAgIGlmIChuID49IDApIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbmRpdGlvblN0YWNrW25dO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIFwiSU5JVElBTFwiO1xuICAgICAgICB9XG4gICAgfSxcblxuLy8gYWxpYXMgZm9yIGJlZ2luKGNvbmRpdGlvbilcbnB1c2hTdGF0ZTpmdW5jdGlvbiBwdXNoU3RhdGUgKGNvbmRpdGlvbikge1xuICAgICAgICB0aGlzLmJlZ2luKGNvbmRpdGlvbik7XG4gICAgfSxcblxuLy8gcmV0dXJuIHRoZSBudW1iZXIgb2Ygc3RhdGVzIGN1cnJlbnRseSBvbiB0aGUgc3RhY2tcbnN0YXRlU3RhY2tTaXplOmZ1bmN0aW9uIHN0YXRlU3RhY2tTaXplKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25kaXRpb25TdGFjay5sZW5ndGg7XG4gICAgfSxcbm9wdGlvbnM6IHtcImZsZXhcIjp0cnVlLFwiY2FzZS1pbnNlbnNpdGl2ZVwiOnRydWV9LFxucGVyZm9ybUFjdGlvbjogZnVuY3Rpb24gYW5vbnltb3VzKHl5LHl5XywkYXZvaWRpbmdfbmFtZV9jb2xsaXNpb25zLFlZX1NUQVJUKSB7XG52YXIgWVlTVEFURT1ZWV9TVEFSVDtcbnN3aXRjaCgkYXZvaWRpbmdfbmFtZV9jb2xsaXNpb25zKSB7XG5jYXNlIDA6LyogaWdub3JlICovXG5icmVhaztcbmNhc2UgMTpyZXR1cm4gMTJcbmJyZWFrO1xuY2FzZSAyOnJldHVybiAxNVxuYnJlYWs7XG5jYXNlIDM6cmV0dXJuIDI0XG5icmVhaztcbmNhc2UgNDpyZXR1cm4gMjkwXG5icmVhaztcbmNhc2UgNTpyZXR1cm4gMjkxXG5icmVhaztcbmNhc2UgNjpyZXR1cm4gMjlcbmJyZWFrO1xuY2FzZSA3OnJldHVybiAzMVxuYnJlYWs7XG5jYXNlIDg6cmV0dXJuIDMyXG5icmVhaztcbmNhc2UgOTpyZXR1cm4gMjkzXG5icmVhaztcbmNhc2UgMTA6cmV0dXJuIDM0XG5icmVhaztcbmNhc2UgMTE6cmV0dXJuIDM4XG5icmVhaztcbmNhc2UgMTI6cmV0dXJuIDM5XG5icmVhaztcbmNhc2UgMTM6cmV0dXJuIDQxXG5icmVhaztcbmNhc2UgMTQ6cmV0dXJuIDQzXG5icmVhaztcbmNhc2UgMTU6cmV0dXJuIDQ4XG5icmVhaztcbmNhc2UgMTY6cmV0dXJuIDUxXG5icmVhaztcbmNhc2UgMTc6cmV0dXJuIDI5NlxuYnJlYWs7XG5jYXNlIDE4OnJldHVybiA2MVxuYnJlYWs7XG5jYXNlIDE5OnJldHVybiA2MlxuYnJlYWs7XG5jYXNlIDIwOnJldHVybiA2OFxuYnJlYWs7XG5jYXNlIDIxOnJldHVybiA3MVxuYnJlYWs7XG5jYXNlIDIyOnJldHVybiA3NFxuYnJlYWs7XG5jYXNlIDIzOnJldHVybiA3NlxuYnJlYWs7XG5jYXNlIDI0OnJldHVybiA3OVxuYnJlYWs7XG5jYXNlIDI1OnJldHVybiA4MVxuYnJlYWs7XG5jYXNlIDI2OnJldHVybiA4M1xuYnJlYWs7XG5jYXNlIDI3OnJldHVybiAxODNcbmJyZWFrO1xuY2FzZSAyODpyZXR1cm4gOTlcbmJyZWFrO1xuY2FzZSAyOTpyZXR1cm4gMjk3XG5icmVhaztcbmNhc2UgMzA6cmV0dXJuIDEzMlxuYnJlYWs7XG5jYXNlIDMxOnJldHVybiAyOThcbmJyZWFrO1xuY2FzZSAzMjpyZXR1cm4gMjk5XG5icmVhaztcbmNhc2UgMzM6cmV0dXJuIDEwOVxuYnJlYWs7XG5jYXNlIDM0OnJldHVybiAzMDBcbmJyZWFrO1xuY2FzZSAzNTpyZXR1cm4gMTA4XG5icmVhaztcbmNhc2UgMzY6cmV0dXJuIDMwMVxuYnJlYWs7XG5jYXNlIDM3OnJldHVybiAzMDJcbmJyZWFrO1xuY2FzZSAzODpyZXR1cm4gMTEyXG5icmVhaztcbmNhc2UgMzk6cmV0dXJuIDExNFxuYnJlYWs7XG5jYXNlIDQwOnJldHVybiAxMTVcbmJyZWFrO1xuY2FzZSA0MTpyZXR1cm4gMTMwXG5icmVhaztcbmNhc2UgNDI6cmV0dXJuIDEyNFxuYnJlYWs7XG5jYXNlIDQzOnJldHVybiAxMjVcbmJyZWFrO1xuY2FzZSA0NDpyZXR1cm4gMTI3XG5icmVhaztcbmNhc2UgNDU6cmV0dXJuIDEzM1xuYnJlYWs7XG5jYXNlIDQ2OnJldHVybiAxMTFcbmJyZWFrO1xuY2FzZSA0NzpyZXR1cm4gMzAzXG5icmVhaztcbmNhc2UgNDg6cmV0dXJuIDMwNFxuYnJlYWs7XG5jYXNlIDQ5OnJldHVybiAxNTlcbmJyZWFrO1xuY2FzZSA1MDpyZXR1cm4gMTYyXG5icmVhaztcbmNhc2UgNTE6cmV0dXJuIDE2NlxuYnJlYWs7XG5jYXNlIDUyOnJldHVybiA5MlxuYnJlYWs7XG5jYXNlIDUzOnJldHVybiAxNjBcbmJyZWFrO1xuY2FzZSA1NDpyZXR1cm4gMzA1XG5icmVhaztcbmNhc2UgNTU6cmV0dXJuIDE2NVxuYnJlYWs7XG5jYXNlIDU2OnJldHVybiAyNTFcbmJyZWFrO1xuY2FzZSA1NzpyZXR1cm4gMTg3XG5icmVhaztcbmNhc2UgNTg6cmV0dXJuIDMwNlxuYnJlYWs7XG5jYXNlIDU5OnJldHVybiAzMDdcbmJyZWFrO1xuY2FzZSA2MDpyZXR1cm4gMjEzXG5icmVhaztcbmNhc2UgNjE6cmV0dXJuIDMwOVxuYnJlYWs7XG5jYXNlIDYyOnJldHVybiAzMTBcbmJyZWFrO1xuY2FzZSA2MzpyZXR1cm4gMjA4XG5icmVhaztcbmNhc2UgNjQ6cmV0dXJuIDIxNVxuYnJlYWs7XG5jYXNlIDY1OnJldHVybiAyMTZcbmJyZWFrO1xuY2FzZSA2NjpyZXR1cm4gMjIzXG5icmVhaztcbmNhc2UgNjc6cmV0dXJuIDIyN1xuYnJlYWs7XG5jYXNlIDY4OnJldHVybiAyNjhcbmJyZWFrO1xuY2FzZSA2OTpyZXR1cm4gMzExXG5icmVhaztcbmNhc2UgNzA6cmV0dXJuIDMxMlxuYnJlYWs7XG5jYXNlIDcxOnJldHVybiAzMTNcbmJyZWFrO1xuY2FzZSA3MjpyZXR1cm4gMzE0XG5icmVhaztcbmNhc2UgNzM6cmV0dXJuIDMxNVxuYnJlYWs7XG5jYXNlIDc0OnJldHVybiAyMzFcbmJyZWFrO1xuY2FzZSA3NTpyZXR1cm4gMzE2XG5icmVhaztcbmNhc2UgNzY6cmV0dXJuIDI0NlxuYnJlYWs7XG5jYXNlIDc3OnJldHVybiAyNTRcbmJyZWFrO1xuY2FzZSA3ODpyZXR1cm4gMjU1XG5icmVhaztcbmNhc2UgNzk6cmV0dXJuIDI0OFxuYnJlYWs7XG5jYXNlIDgwOnJldHVybiAyNDlcbmJyZWFrO1xuY2FzZSA4MTpyZXR1cm4gMjUwXG5icmVhaztcbmNhc2UgODI6cmV0dXJuIDMxN1xuYnJlYWs7XG5jYXNlIDgzOnJldHVybiAzMThcbmJyZWFrO1xuY2FzZSA4NDpyZXR1cm4gMjUyXG5icmVhaztcbmNhc2UgODU6cmV0dXJuIDMyMFxuYnJlYWs7XG5jYXNlIDg2OnJldHVybiAzMTlcbmJyZWFrO1xuY2FzZSA4NzpyZXR1cm4gMzIxXG5icmVhaztcbmNhc2UgODg6cmV0dXJuIDI1N1xuYnJlYWs7XG5jYXNlIDg5OnJldHVybiAyNThcbmJyZWFrO1xuY2FzZSA5MDpyZXR1cm4gMjYxXG5icmVhaztcbmNhc2UgOTE6cmV0dXJuIDI2M1xuYnJlYWs7XG5jYXNlIDkyOnJldHVybiAyNjdcbmJyZWFrO1xuY2FzZSA5MzpyZXR1cm4gMjcxXG5icmVhaztcbmNhc2UgOTQ6cmV0dXJuIDI3NFxuYnJlYWs7XG5jYXNlIDk1OnJldHVybiAyNzVcbmJyZWFrO1xuY2FzZSA5NjpyZXR1cm4gMTNcbmJyZWFrO1xuY2FzZSA5NzpyZXR1cm4gMTZcbmJyZWFrO1xuY2FzZSA5ODpyZXR1cm4gMjg2XG5icmVhaztcbmNhc2UgOTk6cmV0dXJuIDIxOFxuYnJlYWs7XG5jYXNlIDEwMDpyZXR1cm4gMjhcbmJyZWFrO1xuY2FzZSAxMDE6cmV0dXJuIDI3MFxuYnJlYWs7XG5jYXNlIDEwMjpyZXR1cm4gODBcbmJyZWFrO1xuY2FzZSAxMDM6cmV0dXJuIDI3MlxuYnJlYWs7XG5jYXNlIDEwNDpyZXR1cm4gMjczXG5icmVhaztcbmNhc2UgMTA1OnJldHVybiAyODBcbmJyZWFrO1xuY2FzZSAxMDY6cmV0dXJuIDI4MVxuYnJlYWs7XG5jYXNlIDEwNzpyZXR1cm4gMjgyXG5icmVhaztcbmNhc2UgMTA4OnJldHVybiAyODNcbmJyZWFrO1xuY2FzZSAxMDk6cmV0dXJuIDI4NFxuYnJlYWs7XG5jYXNlIDExMDpyZXR1cm4gMjg1XG5icmVhaztcbmNhc2UgMTExOnJldHVybiAnRVhQT05FTlQnXG5icmVhaztcbmNhc2UgMTEyOnJldHVybiAyNzZcbmJyZWFrO1xuY2FzZSAxMTM6cmV0dXJuIDI3N1xuYnJlYWs7XG5jYXNlIDExNDpyZXR1cm4gMjc4XG5icmVhaztcbmNhc2UgMTE1OnJldHVybiAyNzlcbmJyZWFrO1xuY2FzZSAxMTY6cmV0dXJuIDg2XG5icmVhaztcbmNhc2UgMTE3OnJldHVybiAyMTlcbmJyZWFrO1xuY2FzZSAxMTg6cmV0dXJuIDZcbmJyZWFrO1xuY2FzZSAxMTk6cmV0dXJuICdJTlZBTElEJ1xuYnJlYWs7XG5jYXNlIDEyMDpjb25zb2xlLmxvZyh5eV8ueXl0ZXh0KTtcbmJyZWFrO1xufVxufSxcbnJ1bGVzOiBbL14oPzpcXHMrfCNbXlxcblxccl0qKS9pLC9eKD86QkFTRSkvaSwvXig/OlBSRUZJWCkvaSwvXig/OlNFTEVDVCkvaSwvXig/OkRJU1RJTkNUKS9pLC9eKD86UkVEVUNFRCkvaSwvXig/OlxcKCkvaSwvXig/OkFTKS9pLC9eKD86XFwpKS9pLC9eKD86XFwqKS9pLC9eKD86Q09OU1RSVUNUKS9pLC9eKD86V0hFUkUpL2ksL14oPzpcXHspL2ksL14oPzpcXH0pL2ksL14oPzpERVNDUklCRSkvaSwvXig/OkFTSykvaSwvXig/OkZST00pL2ksL14oPzpOQU1FRCkvaSwvXig/OkdST1VQKS9pLC9eKD86QlkpL2ksL14oPzpIQVZJTkcpL2ksL14oPzpPUkRFUikvaSwvXig/OkFTQykvaSwvXig/OkRFU0MpL2ksL14oPzpMSU1JVCkvaSwvXig/Ok9GRlNFVCkvaSwvXig/OlZBTFVFUykvaSwvXig/OjspL2ksL14oPzpMT0FEKS9pLC9eKD86U0lMRU5UKS9pLC9eKD86SU5UTykvaSwvXig/OkNMRUFSKS9pLC9eKD86RFJPUCkvaSwvXig/OkNSRUFURSkvaSwvXig/OkFERCkvaSwvXig/OlRPKS9pLC9eKD86TU9WRSkvaSwvXig/OkNPUFkpL2ksL14oPzpJTlNFUlRcXHMrREFUQSkvaSwvXig/OkRFTEVURVxccytEQVRBKS9pLC9eKD86REVMRVRFXFxzK1dIRVJFKS9pLC9eKD86V0lUSCkvaSwvXig/OkRFTEVURSkvaSwvXig/OklOU0VSVCkvaSwvXig/OlVTSU5HKS9pLC9eKD86REVGQVVMVCkvaSwvXig/OkdSQVBIKS9pLC9eKD86QUxMKS9pLC9eKD86XFwuKS9pLC9eKD86T1BUSU9OQUwpL2ksL14oPzpTRVJWSUNFKS9pLC9eKD86QklORCkvaSwvXig/OlVOREVGKS9pLC9eKD86TUlOVVMpL2ksL14oPzpVTklPTikvaSwvXig/OkZJTFRFUikvaSwvXig/OiwpL2ksL14oPzphKS9pLC9eKD86XFx8KS9pLC9eKD86XFwvKS9pLC9eKD86XFxeKS9pLC9eKD86XFw/KS9pLC9eKD86XFwrKS9pLC9eKD86ISkvaSwvXig/OlxcWykvaSwvXig/OlxcXSkvaSwvXig/OlxcfFxcfCkvaSwvXig/OiYmKS9pLC9eKD86PSkvaSwvXig/OiE9KS9pLC9eKD86PCkvaSwvXig/Oj4pL2ksL14oPzo8PSkvaSwvXig/Oj49KS9pLC9eKD86SU4pL2ksL14oPzpOT1QpL2ksL14oPzotKS9pLC9eKD86Qk9VTkQpL2ksL14oPzpCTk9ERSkvaSwvXig/OihSQU5EfE5PV3xVVUlEfFNUUlVVSUQpKS9pLC9eKD86KExBTkd8REFUQVRZUEV8SVJJfFVSSXxBQlN8Q0VJTHxGTE9PUnxST1VORHxTVFJMRU58U1RSfFVDQVNFfExDQVNFfEVOQ09ERV9GT1JfVVJJfFlFQVJ8TU9OVEh8REFZfEhPVVJTfE1JTlVURVN8U0VDT05EU3xUSU1FWk9ORXxUWnxNRDV8U0hBMXxTSEEyNTZ8U0hBMzg0fFNIQTUxMnxpc0lSSXxpc1VSSXxpc0JMQU5LfGlzTElURVJBTHxpc05VTUVSSUMpKS9pLC9eKD86KExBTkdNQVRDSEVTfENPTlRBSU5TfFNUUlNUQVJUU3xTVFJFTkRTfFNUUkJFRk9SRXxTVFJBRlRFUnxTVFJMQU5HfFNUUkRUfHNhbWVUZXJtKSkvaSwvXig/OkNPTkNBVCkvaSwvXig/OkNPQUxFU0NFKS9pLC9eKD86SUYpL2ksL14oPzpSRUdFWCkvaSwvXig/OlNVQlNUUikvaSwvXig/OlJFUExBQ0UpL2ksL14oPzpFWElTVFMpL2ksL14oPzpDT1VOVCkvaSwvXig/OlNVTXxNSU58TUFYfEFWR3xTQU1QTEUpL2ksL14oPzpHUk9VUF9DT05DQVQpL2ksL14oPzpTRVBBUkFUT1IpL2ksL14oPzpcXF5cXF4pL2ksL14oPzp0cnVlKS9pLC9eKD86ZmFsc2UpL2ksL14oPzooPChbXjw+XFxcIlxce1xcfVxcfFxcXmBcXFxcXFx1MDAwMC1cXHUwMDIwXSkqPikpL2ksL14oPzooKChbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKSgoKCgoPzooW0EtWl18W2Etel18W1xcdTAwQzAtXFx1MDBENl18W1xcdTAwRDgtXFx1MDBGNl18W1xcdTAwRjgtXFx1MDJGRl18W1xcdTAzNzAtXFx1MDM3RF18W1xcdTAzN0YtXFx1MUZGRl18W1xcdTIwMEMtXFx1MjAwRF18W1xcdTIwNzAtXFx1MjE4Rl18W1xcdTJDMDAtXFx1MkZFRl18W1xcdTMwMDEtXFx1RDdGRl18W1xcdUY5MDAtXFx1RkRDRl18W1xcdUZERjAtXFx1RkZGRF18W1xcdUQ4MDAtXFx1REI3Rl1bXFx1REMwMC1cXHVERkZGXSl8XykpfC18WzAtOV18XFx1MDBCN3xbXFx1MDMwMC1cXHUwMzZGXXxbXFx1MjAzRi1cXHUyMDQwXSl8XFwuKSooKCg/OihbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKXxfKSl8LXxbMC05XXxcXHUwMEI3fFtcXHUwMzAwLVxcdTAzNkZdfFtcXHUyMDNGLVxcdTIwNDBdKSk/KT86KSkvaSwvXig/OigoKChbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKSgoKCgoPzooW0EtWl18W2Etel18W1xcdTAwQzAtXFx1MDBENl18W1xcdTAwRDgtXFx1MDBGNl18W1xcdTAwRjgtXFx1MDJGRl18W1xcdTAzNzAtXFx1MDM3RF18W1xcdTAzN0YtXFx1MUZGRl18W1xcdTIwMEMtXFx1MjAwRF18W1xcdTIwNzAtXFx1MjE4Rl18W1xcdTJDMDAtXFx1MkZFRl18W1xcdTMwMDEtXFx1RDdGRl18W1xcdUY5MDAtXFx1RkRDRl18W1xcdUZERjAtXFx1RkZGRF18W1xcdUQ4MDAtXFx1REI3Rl1bXFx1REMwMC1cXHVERkZGXSl8XykpfC18WzAtOV18XFx1MDBCN3xbXFx1MDMwMC1cXHUwMzZGXXxbXFx1MjAzRi1cXHUyMDQwXSl8XFwuKSooKCg/OihbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKXxfKSl8LXxbMC05XXxcXHUwMEI3fFtcXHUwMzAwLVxcdTAzNkZdfFtcXHUyMDNGLVxcdTIwNDBdKSk/KT86KSgoKCg/OihbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKXxfKSl8OnxbMC05XXwoKCUoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKSl8KFxcXFwoX3x+fFxcLnwtfCF8XFwkfCZ8J3xcXCh8XFwpfFxcKnxcXCt8LHw7fD18XFwvfFxcP3wjfEB8JSkpKSkoKCgoKD86KFtBLVpdfFthLXpdfFtcXHUwMEMwLVxcdTAwRDZdfFtcXHUwMEQ4LVxcdTAwRjZdfFtcXHUwMEY4LVxcdTAyRkZdfFtcXHUwMzcwLVxcdTAzN0RdfFtcXHUwMzdGLVxcdTFGRkZdfFtcXHUyMDBDLVxcdTIwMERdfFtcXHUyMDcwLVxcdTIxOEZdfFtcXHUyQzAwLVxcdTJGRUZdfFtcXHUzMDAxLVxcdUQ3RkZdfFtcXHVGOTAwLVxcdUZEQ0ZdfFtcXHVGREYwLVxcdUZGRkRdfFtcXHVEODAwLVxcdURCN0ZdW1xcdURDMDAtXFx1REZGRl0pfF8pKXwtfFswLTldfFxcdTAwQjd8W1xcdTAzMDAtXFx1MDM2Rl18W1xcdTIwM0YtXFx1MjA0MF0pfFxcLnw6fCgoJShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKXwoXFxcXChffH58XFwufC18IXxcXCR8JnwnfFxcKHxcXCl8XFwqfFxcK3wsfDt8PXxcXC98XFw/fCN8QHwlKSkpKSooKCgoPzooW0EtWl18W2Etel18W1xcdTAwQzAtXFx1MDBENl18W1xcdTAwRDgtXFx1MDBGNl18W1xcdTAwRjgtXFx1MDJGRl18W1xcdTAzNzAtXFx1MDM3RF18W1xcdTAzN0YtXFx1MUZGRl18W1xcdTIwMEMtXFx1MjAwRF18W1xcdTIwNzAtXFx1MjE4Rl18W1xcdTJDMDAtXFx1MkZFRl18W1xcdTMwMDEtXFx1RDdGRl18W1xcdUY5MDAtXFx1RkRDRl18W1xcdUZERjAtXFx1RkZGRF18W1xcdUQ4MDAtXFx1REI3Rl1bXFx1REMwMC1cXHVERkZGXSl8XykpfC18WzAtOV18XFx1MDBCN3xbXFx1MDMwMC1cXHUwMzZGXXxbXFx1MjAzRi1cXHUyMDQwXSl8OnwoKCUoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKSl8KFxcXFwoX3x+fFxcLnwtfCF8XFwkfCZ8J3xcXCh8XFwpfFxcKnxcXCt8LHw7fD18XFwvfFxcP3wjfEB8JSkpKSkpPykpKS9pLC9eKD86KF86KCgoPzooW0EtWl18W2Etel18W1xcdTAwQzAtXFx1MDBENl18W1xcdTAwRDgtXFx1MDBGNl18W1xcdTAwRjgtXFx1MDJGRl18W1xcdTAzNzAtXFx1MDM3RF18W1xcdTAzN0YtXFx1MUZGRl18W1xcdTIwMEMtXFx1MjAwRF18W1xcdTIwNzAtXFx1MjE4Rl18W1xcdTJDMDAtXFx1MkZFRl18W1xcdTMwMDEtXFx1RDdGRl18W1xcdUY5MDAtXFx1RkRDRl18W1xcdUZERjAtXFx1RkZGRF18W1xcdUQ4MDAtXFx1REI3Rl1bXFx1REMwMC1cXHVERkZGXSl8XykpfFswLTldKSgoKCgoPzooW0EtWl18W2Etel18W1xcdTAwQzAtXFx1MDBENl18W1xcdTAwRDgtXFx1MDBGNl18W1xcdTAwRjgtXFx1MDJGRl18W1xcdTAzNzAtXFx1MDM3RF18W1xcdTAzN0YtXFx1MUZGRl18W1xcdTIwMEMtXFx1MjAwRF18W1xcdTIwNzAtXFx1MjE4Rl18W1xcdTJDMDAtXFx1MkZFRl18W1xcdTMwMDEtXFx1RDdGRl18W1xcdUY5MDAtXFx1RkRDRl18W1xcdUZERjAtXFx1RkZGRF18W1xcdUQ4MDAtXFx1REI3Rl1bXFx1REMwMC1cXHVERkZGXSl8XykpfC18WzAtOV18XFx1MDBCN3xbXFx1MDMwMC1cXHUwMzZGXXxbXFx1MjAzRi1cXHUyMDQwXSl8XFwuKSooKCg/OihbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKXxfKSl8LXxbMC05XXxcXHUwMEI3fFtcXHUwMzAwLVxcdTAzNkZdfFtcXHUyMDNGLVxcdTIwNDBdKSk/KSkvaSwvXig/OihbXFw/XFwkXSgoKCg/OihbQS1aXXxbYS16XXxbXFx1MDBDMC1cXHUwMEQ2XXxbXFx1MDBEOC1cXHUwMEY2XXxbXFx1MDBGOC1cXHUwMkZGXXxbXFx1MDM3MC1cXHUwMzdEXXxbXFx1MDM3Ri1cXHUxRkZGXXxbXFx1MjAwQy1cXHUyMDBEXXxbXFx1MjA3MC1cXHUyMThGXXxbXFx1MkMwMC1cXHUyRkVGXXxbXFx1MzAwMS1cXHVEN0ZGXXxbXFx1RjkwMC1cXHVGRENGXXxbXFx1RkRGMC1cXHVGRkZEXXxbXFx1RDgwMC1cXHVEQjdGXVtcXHVEQzAwLVxcdURGRkZdKXxfKSl8WzAtOV0pKCgoPzooW0EtWl18W2Etel18W1xcdTAwQzAtXFx1MDBENl18W1xcdTAwRDgtXFx1MDBGNl18W1xcdTAwRjgtXFx1MDJGRl18W1xcdTAzNzAtXFx1MDM3RF18W1xcdTAzN0YtXFx1MUZGRl18W1xcdTIwMEMtXFx1MjAwRF18W1xcdTIwNzAtXFx1MjE4Rl18W1xcdTJDMDAtXFx1MkZFRl18W1xcdTMwMDEtXFx1RDdGRl18W1xcdUY5MDAtXFx1RkRDRl18W1xcdUZERjAtXFx1RkZGRF18W1xcdUQ4MDAtXFx1REI3Rl1bXFx1REMwMC1cXHVERkZGXSl8XykpfFswLTldfFxcdTAwQjd8W1xcdTAzMDAtXFx1MDM2Rl18W1xcdTIwM0YtXFx1MjA0MF0pKikpKS9pLC9eKD86KEBbYS16QS1aXSsoLVthLXpBLVowLTldKykqKSkvaSwvXig/OihbMC05XSspKS9pLC9eKD86KFswLTldKlxcLlswLTldKykpL2ksL14oPzooWzAtOV0rXFwuWzAtOV0qKFtlRV1bKy1dP1swLTldKyl8XFwuKFswLTldKSsoW2VFXVsrLV0/WzAtOV0rKXwoWzAtOV0pKyhbZUVdWystXT9bMC05XSspKSkvaSwvXig/OihcXCsoWzAtOV0rKSkpL2ksL14oPzooXFwrKFswLTldKlxcLlswLTldKykpKS9pLC9eKD86KFxcKyhbMC05XStcXC5bMC05XSooW2VFXVsrLV0/WzAtOV0rKXxcXC4oWzAtOV0pKyhbZUVdWystXT9bMC05XSspfChbMC05XSkrKFtlRV1bKy1dP1swLTldKykpKSkvaSwvXig/OigtKFswLTldKykpKS9pLC9eKD86KC0oWzAtOV0qXFwuWzAtOV0rKSkpL2ksL14oPzooLShbMC05XStcXC5bMC05XSooW2VFXVsrLV0/WzAtOV0rKXxcXC4oWzAtOV0pKyhbZUVdWystXT9bMC05XSspfChbMC05XSkrKFtlRV1bKy1dP1swLTldKykpKSkvaSwvXig/OihbZUVdWystXT9bMC05XSspKS9pLC9eKD86KCcoKFteXFx1MDAyN1xcdTAwNUNcXHUwMDBBXFx1MDAwRF0pfChcXFxcW3RibnJmXFxcXFxcXCInXXxcXFxcdShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSl8XFxcXFUoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKSkpKicpKS9pLC9eKD86KFwiKChbXlxcdTAwMjJcXHUwMDVDXFx1MDAwQVxcdTAwMERdKXwoXFxcXFt0Ym5yZlxcXFxcXFwiJ118XFxcXHUoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pfFxcXFxVKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkpKSpcIikpL2ksL14oPzooJycnKCgnfCcnKT8oW14nXFxcXF18KFxcXFxbdGJucmZcXFxcXFxcIiddfFxcXFx1KFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKXxcXFxcVShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKSkpKicnJykpL2ksL14oPzooXCJcIlwiKChcInxcIlwiKT8oW15cXFwiXFxcXF18KFxcXFxbdGJucmZcXFxcXFxcIiddfFxcXFx1KFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKXxcXFxcVShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKFswLTldfFtBLUZdfFthLWZdKShbMC05XXxbQS1GXXxbYS1mXSkoWzAtOV18W0EtRl18W2EtZl0pKSkpKlwiXCJcIikpL2ksL14oPzooXFwoKFxcdTAwMjB8XFx1MDAwOXxcXHUwMDBEfFxcdTAwMEEpKlxcKSkpL2ksL14oPzooXFxbKFxcdTAwMjB8XFx1MDAwOXxcXHUwMDBEfFxcdTAwMEEpKlxcXSkpL2ksL14oPzokKS9pLC9eKD86LikvaSwvXig/Oi4pL2ldLFxuY29uZGl0aW9uczoge1wiSU5JVElBTFwiOntcInJ1bGVzXCI6WzAsMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTksMjAsMjEsMjIsMjMsMjQsMjUsMjYsMjcsMjgsMjksMzAsMzEsMzIsMzMsMzQsMzUsMzYsMzcsMzgsMzksNDAsNDEsNDIsNDMsNDQsNDUsNDYsNDcsNDgsNDksNTAsNTEsNTIsNTMsNTQsNTUsNTYsNTcsNTgsNTksNjAsNjEsNjIsNjMsNjQsNjUsNjYsNjcsNjgsNjksNzAsNzEsNzIsNzMsNzQsNzUsNzYsNzcsNzgsNzksODAsODEsODIsODMsODQsODUsODYsODcsODgsODksOTAsOTEsOTIsOTMsOTQsOTUsOTYsOTcsOTgsOTksMTAwLDEwMSwxMDIsMTAzLDEwNCwxMDUsMTA2LDEwNywxMDgsMTA5LDExMCwxMTEsMTEyLDExMywxMTQsMTE1LDExNiwxMTcsMTE4LDExOSwxMjBdLFwiaW5jbHVzaXZlXCI6dHJ1ZX19XG59KTtcbnJldHVybiBsZXhlcjtcbn0pKCk7XG5wYXJzZXIubGV4ZXIgPSBsZXhlcjtcbmZ1bmN0aW9uIFBhcnNlciAoKSB7XG4gIHRoaXMueXkgPSB7fTtcbn1cblBhcnNlci5wcm90b3R5cGUgPSBwYXJzZXI7cGFyc2VyLlBhcnNlciA9IFBhcnNlcjtcbnJldHVybiBuZXcgUGFyc2VyO1xufSkoKTtcblxuXG5pZiAodHlwZW9mIHJlcXVpcmUgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBleHBvcnRzICE9PSAndW5kZWZpbmVkJykge1xuZXhwb3J0cy5wYXJzZXIgPSBTcGFycWxQYXJzZXI7XG5leHBvcnRzLlBhcnNlciA9IFNwYXJxbFBhcnNlci5QYXJzZXI7XG5leHBvcnRzLnBhcnNlID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gU3BhcnFsUGFyc2VyLnBhcnNlLmFwcGx5KFNwYXJxbFBhcnNlciwgYXJndW1lbnRzKTsgfTtcbmV4cG9ydHMubWFpbiA9IGZ1bmN0aW9uIGNvbW1vbmpzTWFpbiAoYXJncykge1xuICAgIGlmICghYXJnc1sxXSkge1xuICAgICAgICBjb25zb2xlLmxvZygnVXNhZ2U6ICcrYXJnc1swXSsnIEZJTEUnKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgICB2YXIgc291cmNlID0gcmVxdWlyZSgnZnMnKS5yZWFkRmlsZVN5bmMocmVxdWlyZSgncGF0aCcpLm5vcm1hbGl6ZShhcmdzWzFdKSwgXCJ1dGY4XCIpO1xuICAgIHJldHVybiBleHBvcnRzLnBhcnNlci5wYXJzZShzb3VyY2UpO1xufTtcbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyAmJiByZXF1aXJlLm1haW4gPT09IG1vZHVsZSkge1xuICBleHBvcnRzLm1haW4ocHJvY2Vzcy5hcmd2LnNsaWNlKDEpKTtcbn1cbn0iLCJ2YXIgUGFyc2VyID0gcmVxdWlyZSgnLi9saWIvU3BhcnFsUGFyc2VyJykuUGFyc2VyO1xudmFyIEdlbmVyYXRvciA9IHJlcXVpcmUoJy4vbGliL1NwYXJxbEdlbmVyYXRvcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBTUEFSUUwgcGFyc2VyIHdpdGggdGhlIGdpdmVuIHByZS1kZWZpbmVkIHByZWZpeGVzIGFuZCBiYXNlIElSSVxuICAgKiBAcGFyYW0gcHJlZml4ZXMgeyBbcHJlZml4OiBzdHJpbmddOiBzdHJpbmcgfVxuICAgKiBAcGFyYW0gYmFzZUlSSSBzdHJpbmdcbiAgICovXG4gIFBhcnNlcjogZnVuY3Rpb24gKHByZWZpeGVzLCBiYXNlSVJJKSB7XG4gICAgLy8gQ3JlYXRlIGEgY29weSBvZiB0aGUgcHJlZml4ZXNcbiAgICB2YXIgcHJlZml4ZXNDb3B5ID0ge307XG4gICAgZm9yICh2YXIgcHJlZml4IGluIHByZWZpeGVzIHx8IHt9KVxuICAgICAgcHJlZml4ZXNDb3B5W3ByZWZpeF0gPSBwcmVmaXhlc1twcmVmaXhdO1xuXG4gICAgLy8gQ3JlYXRlIGEgbmV3IHBhcnNlciB3aXRoIHRoZSBnaXZlbiBwcmVmaXhlc1xuICAgIC8vIChXb3JrYXJvdW5kIGZvciBodHRwczovL2dpdGh1Yi5jb20vemFhY2gvamlzb24vaXNzdWVzLzI0MSlcbiAgICB2YXIgcGFyc2VyID0gbmV3IFBhcnNlcigpO1xuICAgIHBhcnNlci5wYXJzZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIFBhcnNlci5iYXNlID0gYmFzZUlSSSB8fCAnJztcbiAgICAgIFBhcnNlci5wcmVmaXhlcyA9IE9iamVjdC5jcmVhdGUocHJlZml4ZXNDb3B5KTtcbiAgICAgIHJldHVybiBQYXJzZXIucHJvdG90eXBlLnBhcnNlLmFwcGx5KHBhcnNlciwgYXJndW1lbnRzKTtcbiAgICB9O1xuICAgIHBhcnNlci5fcmVzZXRCbGFua3MgPSBQYXJzZXIuX3Jlc2V0QmxhbmtzO1xuICAgIHJldHVybiBwYXJzZXI7XG4gIH0sXG4gIEdlbmVyYXRvcjogR2VuZXJhdG9yLFxufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24obW9kdWxlKSB7XG5cdGlmICghbW9kdWxlLndlYnBhY2tQb2x5ZmlsbCkge1xuXHRcdG1vZHVsZS5kZXByZWNhdGUgPSBmdW5jdGlvbigpIHt9O1xuXHRcdG1vZHVsZS5wYXRocyA9IFtdO1xuXHRcdC8vIG1vZHVsZS5wYXJlbnQgPSB1bmRlZmluZWQgYnkgZGVmYXVsdFxuXHRcdGlmICghbW9kdWxlLmNoaWxkcmVuKSBtb2R1bGUuY2hpbGRyZW4gPSBbXTtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobW9kdWxlLCBcImxvYWRlZFwiLCB7XG5cdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0Z2V0OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIG1vZHVsZS5sO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShtb2R1bGUsIFwiaWRcIiwge1xuXHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdGdldDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiBtb2R1bGUuaTtcblx0XHRcdH1cblx0XHR9KTtcblx0XHRtb2R1bGUud2VicGFja1BvbHlmaWxsID0gMTtcblx0fVxuXHRyZXR1cm4gbW9kdWxlO1xufTtcbiIsImltcG9ydCB7IFBhcnNlciwgRGVzY3JpYmVRdWVyeSwgVmFyaWFibGUsIFZhcmlhYmxlRXhwcmVzc2lvbiwgVGVybSB9IGZyb20gJ3NwYXJxbGpzJztcbmltcG9ydCB7IFF1ZXJ5QnVpbGRlciB9IGZyb20gJy4vUXVlcnlCdWlsZGVyJztcblxuZXhwb3J0IGNsYXNzIERlc2NyaWJlQnVpbGRlciBleHRlbmRzIFF1ZXJ5QnVpbGRlclxue1xuXG4gICAgY29uc3RydWN0b3IoZGVzY3JpYmU6IERlc2NyaWJlUXVlcnkpXG4gICAge1xuICAgICAgICBzdXBlcihkZXNjcmliZSk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBmcm9tU3RyaW5nKHF1ZXJ5U3RyaW5nOiBzdHJpbmcsIHByZWZpeGVzPzogeyBbcHJlZml4OiBzdHJpbmddOiBzdHJpbmc7IH0gfCB1bmRlZmluZWQsIGJhc2VJUkk/OiBzdHJpbmcgfCB1bmRlZmluZWQpOiBEZXNjcmliZUJ1aWxkZXJcbiAgICB7XG4gICAgICAgIGxldCBxdWVyeSA9IG5ldyBQYXJzZXIocHJlZml4ZXMsIGJhc2VJUkkpLnBhcnNlKHF1ZXJ5U3RyaW5nKTtcbiAgICAgICAgaWYgKCE8RGVzY3JpYmVRdWVyeT5xdWVyeSkgdGhyb3cgbmV3IEVycm9yKFwiT25seSBERVNDSUJFIGlzIHN1cHBvcnRlZFwiKTtcblxuICAgICAgICByZXR1cm4gbmV3IERlc2NyaWJlQnVpbGRlcig8RGVzY3JpYmVRdWVyeT5xdWVyeSk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBmcm9tUXVlcnkocXVlcnk6IERlc2NyaWJlUXVlcnkpOiBEZXNjcmliZUJ1aWxkZXJcbiAgICB7XG4gICAgICAgIHJldHVybiBuZXcgRGVzY3JpYmVCdWlsZGVyKHF1ZXJ5KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIG5ldygpOiBEZXNjcmliZUJ1aWxkZXJcbiAgICB7XG4gICAgICAgIHJldHVybiBuZXcgRGVzY3JpYmVCdWlsZGVyKHtcbiAgICAgICAgICBcInF1ZXJ5VHlwZVwiOiBcIkRFU0NSSUJFXCIsXG4gICAgICAgICAgXCJ2YXJpYWJsZXNcIjogW1xuICAgICAgICAgICAgXCIqXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwidHlwZVwiOiBcInF1ZXJ5XCIsXG4gICAgICAgICAgXCJwcmVmaXhlc1wiOiB7fVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdmFyaWFibGVzQWxsKCk6IERlc2NyaWJlQnVpbGRlclxuICAgIHtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLnZhcmlhYmxlcyA9IFsgXCIqXCIgXTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgdmFyaWFibGVzKHZhcmlhYmxlczogVmFyaWFibGVbXSk6IERlc2NyaWJlQnVpbGRlclxuICAgIHtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLnZhcmlhYmxlcyA9IHZhcmlhYmxlcztcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgdmFyaWFibGUodGVybTogVGVybSk6IERlc2NyaWJlQnVpbGRlclxuICAgIHtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLnZhcmlhYmxlcy5wdXNoKDxUZXJtICYgXCIqXCI+dGVybSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcHVibGljIGlzVmFyaWFibGUodGVybTogVGVybSk6IGJvb2xlYW5cbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFF1ZXJ5KCkudmFyaWFibGVzLmluY2x1ZGVzKDxUZXJtICYgXCIqXCI+dGVybSk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGdldFF1ZXJ5KCk6IERlc2NyaWJlUXVlcnlcbiAgICB7XG4gICAgICAgIHJldHVybiA8RGVzY3JpYmVRdWVyeT5zdXBlci5nZXRRdWVyeSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBidWlsZCgpOiBEZXNjcmliZVF1ZXJ5XG4gICAge1xuICAgICAgICByZXR1cm4gPERlc2NyaWJlUXVlcnk+c3VwZXIuYnVpbGQoKTtcbiAgICB9XG5cbn0iLCJpbXBvcnQgeyBQYXJzZXIsIFF1ZXJ5LCBCYXNlUXVlcnksIFBhdHRlcm4sIEV4cHJlc3Npb24sIEJsb2NrUGF0dGVybiwgRmlsdGVyUGF0dGVybiwgQmdwUGF0dGVybiwgR3JhcGhQYXR0ZXJuLCBHcm91cFBhdHRlcm4sIE9wZXJhdGlvbkV4cHJlc3Npb24sIFRyaXBsZSwgVGVybSwgUHJvcGVydHlQYXRoLCBHZW5lcmF0b3IsIFNwYXJxbEdlbmVyYXRvciB9IGZyb20gJ3NwYXJxbGpzJztcblxuZXhwb3J0IGNsYXNzIFF1ZXJ5QnVpbGRlclxue1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBxdWVyeTogUXVlcnk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBnZW5lcmF0b3I6IFNwYXJxbEdlbmVyYXRvcjtcblxuICAgIGNvbnN0cnVjdG9yKHF1ZXJ5OiBRdWVyeSlcbiAgICB7XG4gICAgICAgIHRoaXMucXVlcnkgPSBxdWVyeTtcbiAgICAgICAgdGhpcy5nZW5lcmF0b3IgPSBuZXcgR2VuZXJhdG9yKCk7XG4gICAgICAgIGlmICghdGhpcy5xdWVyeS5wcmVmaXhlcykgdGhpcy5xdWVyeS5wcmVmaXhlcyA9IHt9O1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZnJvbVF1ZXJ5KHF1ZXJ5OiBRdWVyeSk6IFF1ZXJ5QnVpbGRlclxuICAgIHtcbiAgICAgICAgcmV0dXJuIG5ldyBRdWVyeUJ1aWxkZXIocXVlcnkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZnJvbVN0cmluZyhxdWVyeVN0cmluZzogc3RyaW5nLCBwcmVmaXhlcz86IHsgW3ByZWZpeDogc3RyaW5nXTogc3RyaW5nOyB9IHwgdW5kZWZpbmVkLCBiYXNlSVJJPzogc3RyaW5nIHwgdW5kZWZpbmVkKTogUXVlcnlCdWlsZGVyXG4gICAge1xuICAgICAgICBsZXQgcXVlcnkgPSBuZXcgUGFyc2VyKHByZWZpeGVzLCBiYXNlSVJJKS5wYXJzZShxdWVyeVN0cmluZyk7XG4gICAgICAgIGlmICghPFF1ZXJ5PnF1ZXJ5KSB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IFNQQVJRTCBxdWVyaWVzIGFyZSBzdXBwb3J0ZWQsIG5vdCB1cGRhdGVzXCIpO1xuXG4gICAgICAgIHJldHVybiBuZXcgUXVlcnlCdWlsZGVyKDxRdWVyeT5xdWVyeSk7XG4gICAgfVxuXG4gICAgcHVibGljIHdoZXJlKHBhdHRlcm46IFBhdHRlcm5bXSk6IFF1ZXJ5QnVpbGRlclxuICAgIHtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLndoZXJlID0gcGF0dGVybjtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgd2hlcmVQYXR0ZXJuKHBhdHRlcm46IFBhdHRlcm4pOiBRdWVyeUJ1aWxkZXJcbiAgICB7XG4gICAgICAgIGlmICghdGhpcy5nZXRRdWVyeSgpLndoZXJlKSB0aGlzLndoZXJlKFtdKTtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLndoZXJlIS5wdXNoKHBhdHRlcm4pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyBiZ3BUcmlwbGVzKHRyaXBsZXM6IFRyaXBsZVtdKTogUXVlcnlCdWlsZGVyXG4gICAge1xuICAgICAgICAvLyBpZiB0aGUgbGFzdCBwYXR0ZXJuIGlzIEJHUCwgYXBwZW5kIHRyaXBsZXMgdG8gaXQgaW5zdGVhZCBvZiBhZGRpbmcgbmV3IEJHUFxuICAgICAgICBpZiAodGhpcy5nZXRRdWVyeSgpLndoZXJlKVxuICAgICAgICB7XG4gICAgICAgICAgICBsZXQgbGFzdFBhdHRlcm4gPSB0aGlzLmdldFF1ZXJ5KCkud2hlcmUhW3RoaXMuZ2V0UXVlcnkoKS53aGVyZSEubGVuZ3RoIC0gMV07XG4gICAgICAgICAgICBpZiAobGFzdFBhdHRlcm4udHlwZSA9PT0gXCJiZ3BcIilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBsYXN0UGF0dGVybi50cmlwbGVzID0gbGFzdFBhdHRlcm4udHJpcGxlcy5jb25jYXQodHJpcGxlcyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy53aGVyZVBhdHRlcm4oUXVlcnlCdWlsZGVyLmJncCh0cmlwbGVzKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGJncFRyaXBsZSh0cmlwbGU6IFRyaXBsZSk6IFF1ZXJ5QnVpbGRlclxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYmdwVHJpcGxlcyhbdHJpcGxlXSk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGdldFF1ZXJ5KCk6IFF1ZXJ5XG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWVyeTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZ2V0R2VuZXJhdG9yKCk6IFNwYXJxbEdlbmVyYXRvclxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2VuZXJhdG9yO1xuICAgIH1cblxuICAgIHB1YmxpYyBidWlsZCgpOiBRdWVyeVxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0UXVlcnkoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdG9TdHJpbmcoKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRHZW5lcmF0b3IoKS5zdHJpbmdpZnkodGhpcy5nZXRRdWVyeSgpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHRlcm0odmFsdWU6IHN0cmluZyk6IFRlcm1cbiAgICB7XG4gICAgICAgIHJldHVybiA8VGVybT52YWx1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHZhcih2YXJOYW1lOiBzdHJpbmcpOiBUZXJtXG4gICAge1xuICAgICAgICByZXR1cm4gPFRlcm0+KFwiP1wiICsgdmFyTmFtZSk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBsaXRlcmFsKHZhbHVlOiBzdHJpbmcpOiBUZXJtXG4gICAge1xuICAgICAgICByZXR1cm4gPFRlcm0+KFwiXFxcIlwiICsgdmFsdWUgKyBcIlxcXCJcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyB0eXBlZExpdGVyYWwodmFsdWU6IHN0cmluZywgZGF0YXR5cGU6IHN0cmluZyk6IFRlcm1cbiAgICB7XG4gICAgICAgIHJldHVybiA8VGVybT4oXCJcXFwiXCIgKyB2YWx1ZSArIFwiXFxcIl5eXCIgKyBkYXRhdHlwZSk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyB1cmkodmFsdWU6IHN0cmluZyk6IFRlcm1cbiAgICB7XG4gICAgICAgIHJldHVybiA8VGVybT52YWx1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHRyaXBsZShzdWJqZWN0OiBUZXJtLCBwcmVkaWNhdGU6IFByb3BlcnR5UGF0aCB8IFRlcm0sIG9iamVjdDogVGVybSk6IFRyaXBsZVxuICAgIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIFwic3ViamVjdFwiOiBzdWJqZWN0LFxuICAgICAgICAgICAgXCJwcmVkaWNhdGVcIjogcHJlZGljYXRlLFxuICAgICAgICAgICAgXCJvYmplY3RcIjogb2JqZWN0XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBiZ3AodHJpcGxlczogVHJpcGxlW10pOiBCZ3BQYXR0ZXJuXG4gICAge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIFwidHlwZVwiOiBcImJncFwiLFxuICAgICAgICAgIFwidHJpcGxlc1wiOiB0cmlwbGVzXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBncmFwaChuYW1lOiBzdHJpbmcsIHBhdHRlcm5zOiBQYXR0ZXJuW10pOiBHcmFwaFBhdHRlcm5cbiAgICB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJncmFwaFwiLFxuICAgICAgICAgICAgXCJuYW1lXCI6IDxUZXJtPm5hbWUsXG4gICAgICAgICAgICBcInBhdHRlcm5zXCI6IHBhdHRlcm5zXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdyb3VwKHBhdHRlcm5zOiBQYXR0ZXJuW10pOiBHcm91cFBhdHRlcm5cbiAgICB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJncm91cFwiLFxuICAgICAgICAgICAgXCJwYXR0ZXJuc1wiOiBwYXR0ZXJuc1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyB1bmlvbihwYXR0ZXJuczogUGF0dGVybltdKTogQmxvY2tQYXR0ZXJuXG4gICAge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidW5pb25cIixcbiAgICAgICAgICAgIFwicGF0dGVybnNcIjogcGF0dGVybnNcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZmlsdGVyKGV4cHJlc3Npb246IEV4cHJlc3Npb24pOiBGaWx0ZXJQYXR0ZXJuXG4gICAge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZmlsdGVyXCIsXG4gICAgICAgICAgICBcImV4cHJlc3Npb25cIjogZXhwcmVzc2lvblxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBvcGVyYXRpb24ob3BlcmF0b3I6IHN0cmluZywgYXJnczogRXhwcmVzc2lvbltdKTogT3BlcmF0aW9uRXhwcmVzc2lvblxuICAgIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIm9wZXJhdGlvblwiLFxuICAgICAgICAgICAgXCJvcGVyYXRvclwiOiBvcGVyYXRvcixcbiAgICAgICAgICAgIFwiYXJnc1wiOiBhcmdzXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBpbih0ZXJtOiBUZXJtLCBsaXN0OiBUZXJtW10pOiBPcGVyYXRpb25FeHByZXNzaW9uXG4gICAge1xuICAgICAgICByZXR1cm4gUXVlcnlCdWlsZGVyLm9wZXJhdGlvbihcImluXCIsIFsgdGVybSwgbGlzdCBdKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHJlZ2V4KHRlcm06IFRlcm0sIHBhdHRlcm46IFRlcm0sIGNhc2VJbnNlbnNpdGl2ZT86IGJvb2xlYW4pOiBPcGVyYXRpb25FeHByZXNzaW9uXG4gICAge1xuICAgICAgICBsZXQgZXhwcmVzc2lvbjogT3BlcmF0aW9uRXhwcmVzc2lvbiA9IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIm9wZXJhdGlvblwiLFxuICAgICAgICAgICAgXCJvcGVyYXRvclwiOiBcInJlZ2V4XCIsXG4gICAgICAgICAgICBcImFyZ3NcIjogWyB0ZXJtLCA8VGVybT4oXCJcXFwiXCIgKyBwYXR0ZXJuICsgXCJcXFwiXCIpIF1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoY2FzZUluc2Vuc2l0aXZlKSBleHByZXNzaW9uLmFyZ3MucHVzaCg8VGVybT5cIlxcXCJpXFxcIlwiKTtcblxuICAgICAgICByZXR1cm4gZXhwcmVzc2lvbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGVxKGFyZzE6IEV4cHJlc3Npb24sIGFyZzI6IEV4cHJlc3Npb24pOiBPcGVyYXRpb25FeHByZXNzaW9uXG4gICAge1xuICAgICAgICByZXR1cm4gUXVlcnlCdWlsZGVyLm9wZXJhdGlvbihcIj1cIiwgWyBhcmcxLCBhcmcyIF0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgc3RyKGFyZzogRXhwcmVzc2lvbik6IE9wZXJhdGlvbkV4cHJlc3Npb25cbiAgICB7XG4gICAgICAgIHJldHVybiBRdWVyeUJ1aWxkZXIub3BlcmF0aW9uKFwic3RyXCIsIFsgYXJnIF0pO1xuICAgIH1cblxufSIsImV4cG9ydCB7IFF1ZXJ5QnVpbGRlciB9IGZyb20gJy4vUXVlcnlCdWlsZGVyJztcbmV4cG9ydCB7IFNlbGVjdEJ1aWxkZXIgfSBmcm9tICcuL1NlbGVjdEJ1aWxkZXInO1xuZXhwb3J0IHsgRGVzY3JpYmVCdWlsZGVyIH0gZnJvbSAnLi9EZXNjcmliZUJ1aWxkZXInOyIsImltcG9ydCB7IFBhcnNlciwgU2VsZWN0UXVlcnksIE9yZGVyaW5nLCBUZXJtLCBWYXJpYWJsZSwgRXhwcmVzc2lvbiB9IGZyb20gJ3NwYXJxbGpzJztcbmltcG9ydCB7IFF1ZXJ5QnVpbGRlciB9IGZyb20gJy4vUXVlcnlCdWlsZGVyJztcblxuZXhwb3J0IGNsYXNzIFNlbGVjdEJ1aWxkZXIgZXh0ZW5kcyBRdWVyeUJ1aWxkZXJcbntcblxuICAgIGNvbnN0cnVjdG9yKHNlbGVjdDogU2VsZWN0UXVlcnkpXG4gICAge1xuICAgICAgICBzdXBlcihzZWxlY3QpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZnJvbVN0cmluZyhxdWVyeVN0cmluZzogc3RyaW5nLCBwcmVmaXhlcz86IHsgW3ByZWZpeDogc3RyaW5nXTogc3RyaW5nOyB9IHwgdW5kZWZpbmVkLCBiYXNlSVJJPzogc3RyaW5nIHwgdW5kZWZpbmVkKTogU2VsZWN0QnVpbGRlclxuICAgIHtcbiAgICAgICAgbGV0IHF1ZXJ5ID0gbmV3IFBhcnNlcihwcmVmaXhlcywgYmFzZUlSSSkucGFyc2UocXVlcnlTdHJpbmcpO1xuICAgICAgICBpZiAoITxTZWxlY3RRdWVyeT5xdWVyeSkgdGhyb3cgbmV3IEVycm9yKFwiT25seSBTRUxFQ1QgaXMgc3VwcG9ydGVkXCIpO1xuXG4gICAgICAgIHJldHVybiBuZXcgU2VsZWN0QnVpbGRlcig8U2VsZWN0UXVlcnk+cXVlcnkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZnJvbVF1ZXJ5KHF1ZXJ5OiBTZWxlY3RRdWVyeSk6IFNlbGVjdEJ1aWxkZXJcbiAgICB7XG4gICAgICAgIHJldHVybiBuZXcgU2VsZWN0QnVpbGRlcihxdWVyeSk7XG4gICAgfVxuXG4gICAgcHVibGljIHZhcmlhYmxlc0FsbCgpOiBTZWxlY3RCdWlsZGVyXG4gICAge1xuICAgICAgICB0aGlzLmdldFF1ZXJ5KCkudmFyaWFibGVzID0gWyBcIipcIiBdO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyB2YXJpYWJsZXModmFyaWFibGVzOiBWYXJpYWJsZVtdKTogU2VsZWN0QnVpbGRlclxuICAgIHtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLnZhcmlhYmxlcyA9IHZhcmlhYmxlcztcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgdmFyaWFibGUodGVybTogVGVybSk6IFNlbGVjdEJ1aWxkZXJcbiAgICB7XG4gICAgICAgIHRoaXMuZ2V0UXVlcnkoKS52YXJpYWJsZXMucHVzaCg8VGVybSAmIFwiKlwiPnRlcm0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc1ZhcmlhYmxlKHRlcm06IFRlcm0pOiBib29sZWFuXG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRRdWVyeSgpLnZhcmlhYmxlcy5pbmNsdWRlcyg8VGVybSAmIFwiKlwiPnRlcm0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBvcmRlckJ5KG9yZGVyaW5nOiBPcmRlcmluZyk6IFNlbGVjdEJ1aWxkZXJcbiAgICB7XG4gICAgICAgIGlmICghdGhpcy5nZXRRdWVyeSgpLm9yZGVyKSB0aGlzLmdldFF1ZXJ5KCkub3JkZXIgPSBbXTtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLm9yZGVyIS5wdXNoKG9yZGVyaW5nKTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgb2Zmc2V0KG9mZnNldDogbnVtYmVyKTogU2VsZWN0QnVpbGRlclxuICAgIHtcbiAgICAgICAgdGhpcy5nZXRRdWVyeSgpLm9mZnNldCA9IG9mZnNldDtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBwdWJsaWMgbGltaXQobGltaXQ6IG51bWJlcik6IFNlbGVjdEJ1aWxkZXJcbiAgICB7XG4gICAgICAgIHRoaXMuZ2V0UXVlcnkoKS5saW1pdCA9IGxpbWl0O1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBnZXRRdWVyeSgpOiBTZWxlY3RRdWVyeVxuICAgIHtcbiAgICAgICAgcmV0dXJuIDxTZWxlY3RRdWVyeT5zdXBlci5nZXRRdWVyeSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBidWlsZCgpOiBTZWxlY3RRdWVyeVxuICAgIHtcbiAgICAgICAgcmV0dXJuIDxTZWxlY3RRdWVyeT5zdXBlci5idWlsZCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgb3JkZXJpbmcoZXhwcjogRXhwcmVzc2lvbiwgZGVzYz86IGJvb2xlYW4pOiBPcmRlcmluZ1xuICAgIHtcbiAgICAgICAgbGV0IG9yZGVyaW5nOiBPcmRlcmluZyA9IHtcbiAgICAgICAgICBcImV4cHJlc3Npb25cIjogZXhwcixcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoZGVzYyAhPT0gdW5kZWZpbmVkICYmIGRlc2MgPT0gdHJ1ZSkgb3JkZXJpbmcuZGVzY2VuZGluZyA9IGRlc2M7XG5cbiAgICAgICAgcmV0dXJuIG9yZGVyaW5nO1xuICAgIH1cblxufSIsIi8qIChpZ25vcmVkKSAqLyIsIi8qIChpZ25vcmVkKSAqLyJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client.xsl index 27024acf67..a9fd3f2a10 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client.xsl @@ -315,7 +315,7 @@ WHERE - + @@ -330,8 +330,12 @@ WHERE - - + + + + @@ -1601,14 +1605,19 @@ WHERE - - + + - - + + + + diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/chart.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/chart.xsl index 1ac6a366ad..3c40190cce 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/chart.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/chart.xsl @@ -643,8 +643,6 @@ exclude-result-prefixes="#all" - - diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/view.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/view.xsl index 94e7e969f2..cb169ce675 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/view.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/block/view.xsl @@ -378,7 +378,7 @@ exclude-result-prefixes="#all" - + - + - + @@ -838,7 +838,7 @@ exclude-result-prefixes="#all" - + @@ -1471,7 +1471,9 @@ exclude-result-prefixes="#all" - + + @@ -1519,11 +1521,10 @@ exclude-result-prefixes="#all" - - + - + @@ -1541,17 +1542,12 @@ exclude-result-prefixes="#all" - - - - - - - - - - - + + + + + + @@ -1909,7 +1905,7 @@ exclude-result-prefixes="#all" - + - - + @@ -2463,7 +2458,7 @@ exclude-result-prefixes="#all" - + - - + @@ -2916,13 +2910,12 @@ exclude-result-prefixes="#all" - - + - + @@ -3515,6 +3508,15 @@ exclude-result-prefixes="#all" + + + + + + + @@ -1990,7 +1989,7 @@ WHERE - + diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/map.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/map.xsl index 53c476d42b..4a912061a5 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/map.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/map.xsl @@ -132,7 +132,7 @@ exclude-result-prefixes="#all" - + diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/memento.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/memento.xsl index 1f6da4cdc3..5801ad66fa 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/memento.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/memento.xsl @@ -5,6 +5,7 @@ + ]> @@ -18,6 +19,7 @@ xmlns:lds="&lds;" xmlns:ac="∾" xmlns:rdf="&rdf;" xmlns:prov="&prov;" +xmlns:dct="&dct;" xmlns:sp="&sp;" xmlns:acl="&acl;" xmlns:xhtml="http://www.w3.org/1999/xhtml" @@ -44,6 +46,7 @@ version="3.0" => ixsl:then(ldh:rethread-response($context, ?)) => ixsl:then(ldh:handle-response#1) => ixsl:then(ldh:load-document-modes#1) + => ixsl:then(ldh:load-creator-metadata#1) => ixsl:then(ldh:timemap-response#1) => ixsl:finally(ldh:reset-cursor#0) " on-failure="ldh:promise-failure($container, 'version-history-not-loaded', ?)"/> @@ -61,6 +64,30 @@ version="3.0" "/> + + + + + + + + + + + + + + + + + + @@ -90,6 +117,17 @@ version="3.0" + + + + + + + + + + + @@ -136,6 +174,7 @@ version="3.0" + @@ -226,11 +265,12 @@ version="3.0" + was rendered. Started from a ?version= view the browser holds no tag for the live document - a + memento's is never stored as its - so ldh:with-document-etag HEADs the live document for one --> diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/modal.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/modal.xsl index e88c34fefb..c375bde4d9 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/modal.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/modal.xsl @@ -411,11 +411,13 @@ LIMIT 10 @@ -1462,8 +1464,7 @@ LIMIT 10 - - + @@ -1477,7 +1478,7 @@ LIMIT 10 - + - - + - + @@ -872,8 +871,7 @@ ORDER BY DESC(?created) - - + @@ -1007,8 +1005,7 @@ ORDER BY DESC(?created) - - + @@ -1122,8 +1119,7 @@ ORDER BY DESC(?created) - - + @@ -1352,8 +1348,7 @@ ORDER BY DESC(?created) - - + diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/query-transforms.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/query-transforms.xsl index 52d04e956d..e27408f5be 100644 --- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/query-transforms.xsl +++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client/query-transforms.xsl @@ -100,6 +100,18 @@ extension-element-prefixes="ixsl" + + + + + + + + @@ -216,7 +228,7 @@ extension-element-prefixes="ixsl" - + @@ -333,9 +345,20 @@ extension-element-prefixes="ixsl" + + + + + + + + + + + - + @@ -357,7 +380,7 @@ extension-element-prefixes="ixsl" - + @@ -787,6 +810,33 @@ extension-element-prefixes="ixsl" + + + + query + SELECT + + ? + + + + + + + group + + + + + + + + @@ -796,8 +846,21 @@ extension-element-prefixes="ixsl" + + + + + + + + + + + - + @@ -853,6 +916,17 @@ extension-element-prefixes="ixsl" + + + + + + + + + + + - +