From a18527dcd95301ac91fc3c70211861952b1d8dde Mon Sep 17 00:00:00 2001 From: tsande16 Date: Mon, 18 Nov 2024 13:54:32 -0500 Subject: [PATCH 1/7] Update Pass Support top level README.md --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0152c553..2a942215 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ -# Introduction - -The pass-support repository contains components which sit outside pass-core. - +# PASS Support + +PASS Support contains ancillary components that assist in the submission process and is composed of the Data Loaders, +Notification Services, and Deposit Services. The Data Loaders handle data ingestion from external systems like PubMed +Central, NIH, FIBI (JHU Grant Management System), transforming grant, journal, and manuscript submission data into a +standardized format within PASS. Deposit Services is responsible for the managing, packaging, and transfer of these +submissions to downstream repositories such as PubMed Central and institutional repositories. Notification Services +provide alerts and updates to relevant stakeholders based on submission workflows and events. + +You can find further documentation and details about the [Data Loaders](https://docs.eclipse-pass.org/developer-documentation/data-loaders), +[Deposit Services](https://docs.eclipse-pass.org/developer-documentation/deposit-service), and [Notification Services](https://docs.eclipse-pass.org/developer-documentation/notification-service) +on the [full documentation site](https://docs.eclipse-pass.org). A full list of all the Eclipse PASS projects can also +be found in the PASS Main repository [README](https://github.com/eclipse-pass/main/blob/main/README.md). From 8d5f7d80947d6c5df82666542debb51bcf6623f9 Mon Sep 17 00:00:00 2001 From: tsande16 Date: Mon, 18 Nov 2024 15:30:35 -0500 Subject: [PATCH 2/7] Remove module READMEs --- pass-deposit-services/ASSEMBLER.md | 230 ----------------- pass-deposit-services/DEVELOPER.md | 250 ------------------ pass-deposit-services/OVERVIEW.md | 181 ------------- pass-deposit-services/README.md | 210 ---------------- pass-deposit-services/pass-model.png | Bin 23852 -> 0 bytes pass-grant-loader/README.md | 60 ----- pass-journal-loader/README.md | 39 --- pass-notification-service/README.md | 364 --------------------------- 8 files changed, 1334 deletions(-) delete mode 100644 pass-deposit-services/ASSEMBLER.md delete mode 100644 pass-deposit-services/DEVELOPER.md delete mode 100644 pass-deposit-services/OVERVIEW.md delete mode 100644 pass-deposit-services/README.md delete mode 100644 pass-deposit-services/pass-model.png delete mode 100644 pass-grant-loader/README.md delete mode 100644 pass-journal-loader/README.md delete mode 100644 pass-notification-service/README.md diff --git a/pass-deposit-services/ASSEMBLER.md b/pass-deposit-services/ASSEMBLER.md deleted file mode 100644 index f36ef424..00000000 --- a/pass-deposit-services/ASSEMBLER.md +++ /dev/null @@ -1,230 +0,0 @@ -# Assemblers - -Assemblers are responsible for gathering custodial and supplemental resources associated with a submission and returning -a stream of those resources - a `PackageStream` - according to a packaging specification. Deposit Services will then -stream the package to a downstream repository via a `Transport`. - -## Use Case - -Why develop an `Assembler`? Broadly speaking, an `Assembler` implementation is required for every packaging -specification you wish to support. For example, if you want to -produce [BagIt packages](https://tools.ietf.org/html/rfc8493) -and [DSpace METS packages](https://wiki.duraspace.org/display/DSPACE/DSpaceMETSSIPProfile), you would need -two `Assembler` implementations, each one responsible for producing packages that comport with their respective -specifications. - -Another reason to develop an `Assembler` is to control how the metadata of a submission is mapped into your package. For -example, if your DSpace installation requires custom metadata elements, you would need to develop or extend an -existing `Assembler` (for example, by implementing a custom Package Provider) to include the custom metadata as -appropriate to your environment. - -Fortunately, you should be able to extend a base `Assembler` class without having to write something from scratch. - -## Quick Start - -1. Create your Assembler class that extends `org.eclipse.pass.deposit.assembler.AbstractAssembler` -2. Create your Package Provider class that - implements `org.eclipse.pass.deposit.assembler.PackageProvider` - -To get started with testing: -Create your package verifier that implements `org.eclipse.pass.deposit.assembler.PackageVerifier` -Extend and implement `org.eclipse.pass.deposit.assembler.AbstractThreadedAssemblyIT` - -# API Overview - -## Assembler API - -The main entrypoint into the Assembler API is on the `Assembler` interface: -`PackageStream assemble(DepositSubmission, Map)` -where the `DepositSubmission` is the internal representation of a `Submission`, and the `Map` is a set of package -options read from `repositories.json`. - -The `AbstractAssembler` provides an implementation of `assemble(DepositSubmission, Map)`, and requires its subclasses to implement: - - PackageStream createPackageStream(DepositSubmission, List, MetadataBuilder, ResourceBuilderFactory, Map) - -Where the `List` is the custodial content of the submission, the `MetadataBuilder` allowing -modification of the package-level metadata, and the `ResourceBuilderFactory` used to generate an instance -of `ResourceBuilder` for each `DepositFileResource`. - -The primary benefit of extending `AbstractAssembler` is that the logic for identifying the custodial resources in the -submission and creating their representation as `List` is shared. Subclasses of `AbstractAssembler` -must instantiate and return a `PackageStream`. - -Examples can be found at: `DspaceMetsAssembler`, `NihmsAssembler`, and `BagItAssembler` - -## PackageStream API - -Assemblers are invoked by Deposit Services and return -a `PackageStream`. The `PackageStream` represents the content to be sent to a downstream repository. Conceptually, -the `PackageStream` behaves like a Java `InputStream`: the bytes for the stream can come from anywhere (memory, a -file on disk, or retrieved from another network resource), and can generally only be read once. - -Practically, the `PackageStream` represents an archive file: either a ZIP, TAR, or some variant like TAR.GZ. This is -encapsulated by the `ArchivingPackageStream`class. Re-using the `ArchivingPackageStream` class has the advantage -that your package resources will be bundled up in a single archive file according to the options supplied to -the `Assembler` (e.g. compression and archive type to use). - -To instantiate an `ArchivingPackageStream` class requires an instance of `PackageProvider`. - -## PackageProvider API - -The `PackageProvider` -interface was developed as an ad hoc lifecycle for streaming a package: there's a `start(...)` and `finish(...)` method, -along with a `packagePath(...)` method. `PackageProvider` also defines a new -interface: `SupplementalResource` -. This interface is returned by the `finish(...)` method, allowing the `PackageProvider` implementation to generate -supplemental (i.e. BagIt tag files or METS.xml files) content after the rest of the package has been streamed. - -Implementing this interface therefore allows for customizing where resources will appear in the package, and to -customize the metadata that appears in the package. - -Because packaging specifications generally have something to say about what resources are included where in the package, -a Package Provider is loosely coupled to a package specification. For example, a Package Provider that placed custodial -resources in the `/foo` directory would be incompatible with a BagIt packaging specification, which -requires custodial resources to appear under `/data`. Similarly, if your Package Provider is to comport -with a DSpace METS packaging scheme, it will need to produce a `/METS.xml` file with the required content. -Therefore, any `PackageProvider` implementation can be used with any `Assembler` implementation as long as the package -specification shared between the two is not violated. - -Examples: `DspaceMetsPackageProvider` -, `NihmsPackageProvider` -, `BagItPackageProvider` - -## Recap - -Implementations of `AbstractAssembler` return an `ArchivingPackageStream` which uses a `PackageProvider` to path -resources and generate supplemental metadata contained in the package. - -When developing your own `Assembler`, you will need to: - -* Extend `AbstractAssembler` -* Implement `PackageProvider`, including the logic to produce supplemental package content like BagIt tag files or - DSpace METS.xml files -* Construct `ArchivingPackageStream` with your `PackageProvider` and return that from your `AbstractAssembler` - implementation - -Here are three examples: - -* `DspaceMetsPackageProvider` -* `NihmsPackageProvider` -* `BagItPackageProvider` - -# Concurrency - -Assemblers exist in the Deposit Services runtime as singletons. A single `Assembler` instance may be invoked from -multiple threads, therefore all the code paths executed by an `Assembler` must be thread-safe. - -`AbstractAssembler` and `ArchivingPackageStream` are already thread-safe; your concrete implementation -of `AbstractAssembler` and `PackageProvider` will need to maintain that thread safety. Streaming a package inherently -involves maintaining state, including the updating of metadata for resources as they are streamed. Package Providers -will often maintain state as they generate supplemental resources for a package; the `J10PMetadataDomWriter` -, for example, builds a METS.xml file using a DOM. - -One strategy for maintaining thread safety is to scope any state maintained over the course of streaming a package to -the executing thread. `Assembler` implementations are free to use whatever mechanisms they wish to insure thread -safety, but Deposit Services accomplishes this in its codebase by simply instantiating a new instance of -state-maintaining classes each time the `Assembler.assemble(...)` is invoked, and insures that state is not shared (i.e. -kept on the Thread stack and not in the JVM heap). For example: - -* `AbstractAssembler` instantiates a new `MetadataBuilder` each time using a factory pattern -* `AbstractAssembler` implementations instantiate a new `ArchivingPackageStream` each time -* `DefaultStreamWriterImpl` instantiates a new `ResourceBuilder` for each resource being streamed using a factory - pattern -* The `DspaceMetsAssembler` uses a factory pattern to instantiate its state-maintaining objects. - -The factory objects may be kept in shared memory (i.e. as instance member variables), but the objects produced by the -factories are maintained in the Thread stack (as method variables). After a `PackageStream` has been opened and -subsequently closed, these objects will be released and garbage collected by the JVM. To help insure thread safety, -there is an integration test fixture, `ThreadedAssemblyIT` -, which can be subclassed and used by `Assembler` integration tests to verify thread safety. - -# Testing - -Adequate test coverage of `Assemblers` includes proper unit testing. This document presumes that you've adequately unit -tested your implementation, and instead focuses on integration testing. - -Integration testing of `Assemblers` is supported by some shared test fixtures in the core Deposit Services codebase. - -## ThreadedAssemblyIT - -The approach taken by the shared `ThreadedAssemblyIT` is to invoke the `Assembler` under test directly using -random `DepositSubmission`s. -a singleton `Assembler` implementation under test is retrieved from the IT subclass that you provide a number of -different `DepositSubmission`s are used to concurrently invoke `Assembler.assemble(...)` on the singleton instance under -test the `PackageStreams` returned by the `Assembler` under test are streamed to and stored on the filesystem A package -verifier supplied by the IT subclass verifies the content of the packages. - -The advantage of extending `ThreadedAssemblyIT` is that it insures that your `Assembler` can be invoked concurrently by -multiple threads while avoiding the complexity of setting up and configuring the Deposit Services runtime. The Spring -Framework is not used, the Deposit Services runtime is not required, and no Docker containers are needed: the IT is -simple Java and JUnit. The downside is that your full runtime is not being integration tested, only your `Assembler`. - -To use `ThreadedAssemblyIT`, extend it, and implement the required methods: - -* `assemblerUnderTest()`: provide an AbstractAssembler instance, fully initialized and ready to be invoked -* `packageOptions()`: provides a set of package options, used when creating the PackageStream and storing it on disk. - The package options include: - * The package specification to be used - * The compression algorithm used when creating the package - * The checksumming algorithm to be used when calculating package and package resource checksums -* `packageVerifier()`: answers a `PackageVerifier` which inspects a package stored on the filesystem and verifies its - content. You must implement a `PackageVerifier` for each `Assembler` being tested. - -The test logic will execute automatically in `ThreadedAssemblyIT.testMultiplePackageStreams()`. The `PackageVerifier` is -very important: it does most of the heavy lifting with respect to passing or failing the integration test, so it must be -well written and test all aspects of a generated package. - -Example: `BagItThreadedAssemblyIT` -, `J10PMetsThreadedAssemblyIT` -, `NihmsThreadedAssemblyIT` - -## PackageVerifier - -Each `Assembler` that is developed should have a corresponding `PackageVerifier`. The `PackageVerifier` is the primary -interface for verifying that a package written to disk contains the expected content. The primary method to implement -is: -`void verify(DepositSubmission, ExplodedPackage, Map)` where the `DepositSubmission` is the original -submission, `ExplodedPackage` is the generated package on disk, and the `Map` includes the options supplied to -the `Assembler` that created the package. - -The verifier is responsible for: - -* Insuring that every custodial file from the submission is present and accounted for in the package -* Insuring there are no extraneous custodial files in the package that are not in the submission -* Insuring that the custodial files checksums are correct -* Insuring that the proper supplemental files are present in the package and have the correct content - -Essentially all aspects of a generated package must be verified through a `PackageVerifier`. - -The `PackageVerifier` interface does come with -a helper method `verifyCustodialFiles` -for ensuring that there is a custodial file in the package for each submitted file, and that there are no unexplained -custodial files present in the package. -`void verifyCustodialFiles(DepositSubmission, File, FileFilter, BiFunction)` -where `DepositSubmission` is the original submission, the `File` is the directory on the filesystem that contains the -exploded package, the `FileFilter` selects custodial files from the package directory, and the `BiFunction` accepts -a `DepositFile` from the submission and maps it to its expected location in the package directory. - -Examples: `DspaceMetsPackageVerifier` -, `NihmsPackageVerifier` - -# Runtime - -Deposit Services is a Spring Boot application, and `Assembler`s are simply a component executed within the application. -If you are familiar with Spring and/or Spring Boot, you are welcome to leverage its features as you wish. Regardless of -your views of Spring, you need to be aware of Spring in these cases: - -* When extending `SubmitAndValidatePackagesIT` (your IT will need to use the `SpringRunner`) -* Your `Assembler` implementation must be annotated with `@Component` - -## Wiring - -So, how is your `Assembler`, `PackageStream`, and `PackageProvider` wired together? As outlined above, the wiring of -these components is straightforward. You can either "hardwire" your implementations at compile-time, or you can leverage -Spring dependency injection as you wish. - -Deposit Services uses Spring Auto Configuration to discover your `Assembler` on the classpath on boot. Supporting Spring -Auto Configuration is very simple: - -* Insure your `Assembler` implementation is annotated with `@Component`. \ No newline at end of file diff --git a/pass-deposit-services/DEVELOPER.md b/pass-deposit-services/DEVELOPER.md deleted file mode 100644 index abe528f4..00000000 --- a/pass-deposit-services/DEVELOPER.md +++ /dev/null @@ -1,250 +0,0 @@ -# Developers - -Deposit Services is implemented using Spring Boot, which heavily relies on Spring-based annotations and conventions to -create and populate a Spring `ApplicationContext`, arguably the most important object managed by the Spring runtime. -Unfortunately, if you aren't familiar with Spring or its conventions, it can make the code harder to understand. - -The entrypoint into the deposit services is the `DepositApp`, which accepts command line parameters that set the "mode" -of the deposit services runtime. Spring beans are created entirely in Java code by the `DepositConfig` and `JmsConfig` -classes. - -## Message flow and concurrency - -Each JMS listener (one each for the `deposit` and `submission` queues) can process messages concurrently. - -The `submission` queue is processed by the `SubmissionListener`,which resolves the `Submission` resource represented -in the message, and hands off processing to the `SubmissionProcessor`. The `SubmissionProcessor` builds -a `DepositSubmission`, which is the Deposit Services' analog of a `Submission` containing all of the metadata and -custodial content associated with a `Submission`. After building the `DepositSubmission`, the processor creates -a `DepositTask` and hands off the actual packaging and transfer of submission content to the deposit worker thread pool. -Importantly, the `SubmissionProcessor` updates the `Submission` resource in the repository as being _in progress_. - -There is a thread pool of so-called "deposit workers" that perform the actual packaging and transport of custodial -content to downstream repositories. The size of the worker pool is determined by the -property `pass.deposit.workers.concurrency` (or its environment equivalent: `PASS_DEPOSIT_WORKERS_CONCURRENCY`). The -deposit worker pool accepts instances of `DepositTask`, which contains the primary logic for packaging, streaming, and -verifying the transfer of content from the PASS repository to downstream repositories. The `DepositTask` will determine -whether or not the transfer of custodial content has succeed, failed, or is indeterminable (i.e. an asyc deposit process -that has not yet concluded). The status of the `Deposit` resource associated with the `Submission` will be updated -accordingly. - -## Common Abstractions and Patterns - -### Failure Handling - -Certain Spring sub-systems like Spring MVC, or Spring Messaging, support the notion of a "global" [`ErrorHandler`][2]. -Deposit services provides an implementation **`DepositServicesErrorHandler`**, and it is used to catch exceptions thrown -by the `DepositListener`, `SubmissionListener`, and is adapted as a [`Thread.UncaughtExceptionHandler`][3] and -as a [`RejectedExecutionHandler`][4]. - -Deposit services provides a `DepositServicesRuntimeException` (`DSRE` for short), which has a -field `PassEntity resource`. If the `DepositServicesErrorHandler` catches a `DSRE` with a non-`null` resource, the error -handler will test the type of the resource, mark it as failed, and save it in the repository. - -The take-home point is: `Deposit` and `Submission` resources will be marked as failed if -a `DepositServicesRuntimeException` is thrown from one of the JMS processors, or from the `DepositTask`. As a developer, -if an exceptional condition does **not** warrant a failure, then do not throw `DepositServicesRuntimeException`. -Instead, consider logging a warning or throwing a `DSRE` with a `null` resource. Likewise, to fail a resource, all you -need to do is throw a `DSRE` with a non-`null` resource. The `DepositServicesErrorHandler` will do the rest. - -Finally, one last word. Because the state of a resource can be modified at any time by any actor in the PASS -infrastructure, the `DepositServicesErrorHandler` encapsulates the act of saving the failed state of a resource within -a `CRI`. A _pre-condition_ for updating the resource is that it must _not_ be in a _terminal_ state. For example, if the -error handler is updating the state from `SUBMITTED` to `FAILED`, but another actor has modified the state of the -resource to `REJECTED` in the interim, the _pre-condition_ will fail. It makes no sense to modify the state of a -resource after it is in its _terminal_ state. The take-home point is: the `DepositServicesErrorHandler` will not mark a -resource as failed if it is in a _terminal_ state. - -### CriticalRepositoryInteraction - -A central, yet awkwardly-named, abstraction is `CriticalRepositoryInteraction`. This interface is used to prevent -interleaved updates of individual repository resources by different threads. A `CriticalRepositoryInteraction` (`CRI` -for short) isolates the execution of a `Function` on a specific repository resource, and provides the boilerplate (i.e. -template) for retrieving and updating the state of the resource. There are four main components -to `CriticalRepositoryInteraction`: the repository resource itself, a _pre-condition_, _post-condition_, and the _ -critical_ update (i.e. the `Function` to be executed). The only implementation of `CRI` is the class `CriticalPath`, and -the particulars of that implementation are discussed below. - -1. First, `CriticalPath` obtains a lock over the string form of the ID of the resource being updated. This insures that - any other threads executing a `CRI` for the _same resource_ _in the same JVM_ must wait their turn before executing - their critical update of the resource. - -> This occurs more often than one might think, as Deposit Services receives many messages for the same resource almost "all at once" when a submission occurs. The thread model for Spring and the Deposit Workers would be rife with conflicts unless something like the `CRI` was uniformly adopted in Deposit Services. - -2. Second, the resource is read from the repository. - -3. Third, the _pre-condition_ `Predicate` is executed over the resource. If the _pre-condition_ fails, the - entire `CriticalPath` is failed, and returns. - -4. Fourth, the critical `Function` is executed, assured that the resource _at the time it was retrieved_ in step 2 meets - the _pre-condition_ applied in step 3. It is assumed that the `Function` modifies the state of the resource. - The `Function` may return the updated state of the resource, or it may return an entirely different object (remember - the `Function` is parameterized by two types; while it _must_ accept a `PassEntity`, it does not have to return - a `PassEntity`). - -5. After updating the state of the resource in step 4, an attempt is made to store and re-read the updated resource in - the repository. In this step, an `UpdateConflictException` may occur, because some other process outside of the JVM - may have modified the resource after step 2 but before step 5. If `UpdateConflictException` is caught, it is the - responsibility of the `ConflictHandler` to resolve the conflict. Otherwise, the update is successful, and processing - of the resource by the `CriticalPath` continues. - -6. Finally, the _post-condition_ `BiPredicate` is executed. It accepts the resource as updated and read by step 5, and - the object returned by the critical update in step 4. This determines the logical success or failure of - the `CriticalPath`. Steps 1 through 5 may have executed without error, but the _post-condition_ has final say of the - overall success of the `CriticalPath`. - -### CriticalRepositoryInteraction Example - -Here is a real example of a `CRI` in action, used when packaging and depositing custodial content to a downstream -repository. - -The _pre-condition_ insures that we are operating on `Deposit` resources acceptable for processing. The _critical -update_ creates a package and streams it to the remote repository, and obtains a `TransportResult`. The status of -the `Deposit` resource is modified, and the `TransportResult` is returned by the _critical update_. Finally, the _ -post-condition_ uses the state of the `Deposit` resource _and_ the `TransportResult` to evaluate the success of the _ -critical update_. - -Behind the scenes, the `CriticalPath` is insuring that the state of the `Deposit` is properly stored in the repository, -and that any conflicts are handled. - -After the `CriticalPath` executes, its `CriticalResult` can be examined for success or failure. - - CriticalResult result = critical.performCritical(dc.deposit().getId(), Deposit.class, - - /* - * Pre-condition: only "dirty" deposits can be processed by {@code DepositTask} - */ - (deposit) -> { - boolean accept = DepositStatus.isTerminalStatus(deposit.getDepositStatus()); - if (!accept) { - LOG.debug(">>>> Update precondition failed for {}", deposit.getId()); - } - - return accept; - }, - - /* - * Post-conditon: determines *physical* success of the Deposit: were the bytes of the package successfully received? - * Note: uses the TransportResponse as well as the resource state to determine the success of this CRI - */ - (deposit, tr) -> { - boolean success = deposit.getDepositStatus() == SUBMITTED; - if (!success) { - LOG.debug(">>>> Update postcondition failed for {} - expected status '{}' but actual status " + - "is '{}'", deposit.getId(), SUBMITTED, deposit.getDepositStatus()); - } - - success &= tr.success(); - - if (!success) { - LOG.debug(">>>> Update postcondition failed for {} - transport of package to endpoint " + - "failed: {}", deposit.getId(), tr.error().getMessage(), tr.error()); - } - - return success; - }, - - /* - * Critical update: Assemble and stream a package of content to the repository endpoint, update status to SUBMITTED - * Note: this Function accepts a Deposit resource, but returns a TransportResponse. Both are used by the - * post-condition to determine the success of the CRI - */ - (deposit) -> { - Packager packager = dc.packager(); - PackageStream packageStream = packager.getAssembler().assemble(dc.depositSubmission()); - Map packagerConfig = packager.getConfiguration(); - try (TransportSession transport = packager.getTransport().open(packagerConfig)) { - TransportResponse tr = transport.send(packageStream, packagerConfig); - deposit.setDepositStatus(SUBMITTED); - return tr; - } catch (Exception e) { - throw new RuntimeException("Error closing transport session for deposit " + - dc.deposit().getId() + ": " + e.getMessage(), e); - } - }); - -### Status - -Deposit services primarily acts on three types of resources: `Submission`, `Deposit`, and `RepositoryCopy`. Each of -these resources carries a status. Managing and reacting to the values of resource status is a large part of what Deposit -services does. - -Abstractly, Deposit services considers the value of any status to be _intermediate_, or _terminal_. - -> It isn't clear, yet, whether this abstract notion of _intermediate_ and _terminal_ need to be shared amongst components of PASS. If so, then certain classes and interfaces in the Deposit Services code base should be extracted out into a shared component. - -The semantics of _terminal_ state are that the resource has been through a workflow of some kind, and has reached the -end of that workflow. Because the workflow has reached a terminus, no additional state is expected to be placed on the -resource, and no existing state of the resource is expected to change. - -The semantics of _intermediate_ state are that the resource is currently in a workflow of some kind, and has yet to -reach the end of that workflow. Because the workflow has _not_ reached a terminus, the resource is expected to be -modified at any time, until the _terminal_ state is achieved. - -A general pattern within Deposit services is that resources with _terminal_ status are explicitly accounted for (this is -largely enforced by _policies_ which are documented elsewhere), and are considered "read-only". - -#### Submission Status - -Submission status is enumerated in the `AggregatedDepositStatus` class. Deposit services considers the following values: - -* `NOT_STARTED` (_intermediate_): Incoming Submissions from the UI must have this status value -* `IN_PROGRESS` (_intermediate_): Deposit services places the Submission in an `IN_PROGRESS` state right away. When a - thread observes a `Submission` in this state, it assumes that _another_ thread is processing this resource. -* `FAILED` (_intermediate_): Occurs when a non-recoverable error happens when processing the `Submission` -* `ACCEPTED` (_terminal_): Deposit services places the Submission into this state when all of its `Deposit`s have - been `ACCEPTED` -* `REJECTED` (_terminal_): Deposit services places the Submission into this state when all of its `Deposit`s have - been `REJECTED` - -#### Deposit Status - -Deposit status is enumerated in the `DepositStatus` class. Deposit services considers the following values: - -* `SUBMITTED` (_intermediate_): the custodial content of the `Submission` has been successfully transferred to - the `Deposit`s `Repository` -* `ACCEPTED` (_terminal_): the custodial content of the `Submission` has been accessioned by the `Deposit` - s `Repository` (i.e. custody of the `Submission` has successfully been transferred to the downstream `Repository`) -* `REJECTED` (_terminal_): the custodial content of the `Submission` has been rejected by the `Deposit`'s `Repository` ( - i.e. the downstream `Repository` has refused to accept custody of the `Submission` content) -* `FAILED` (_intermediate_): the transfer of custodial content to the `Repository` failed, or there was some other error - updating the status of the `Deposit` - -#### RepositoryCopy Status - -RepositoryCopy status is enumerated in the `CopyStatus` class. Deposit services considers the following values: - -* `COMPLETE` (_terminal_): a copy of the custodial content is available in the `Repository` at this location -* `IN_PROGRESS` (_intermediate_): a copy of the custodial content is _expected to be_ available in the `Repository` at - this location. The custodial content should not be expected to exist until the `Deposit` status is `ACCEPTED` -* `REJECTED` (_terminal_): the copy should be considered to be invalid. Even if the custodial content is made available - at the location indicated by the `RepositoryCopy`, it should not be mistaken for a successful transfer of custody. - -RepositoryCopy status is subservient to the Deposit status. They will always be congruent. For example, a RepositoryCopy -cannot be `COMPLETE` if the Deposit is `REJECTED`. If a Deposit is `REJECTED`, then the RepositoryCopy must also -be `REJECTED`. - -#### Common Permutations - -There are some common permutations of these statuses that will be observed: - -* `ACCEPTED` `Submission`s will only have `Deposit`s that are `ACCEPTED`. Each `Deposit` will have - a `COMPLETE` `RepositoryCopy`. -* `REJECTED` `Submission`s will only have `Deposit`s that are `REJECTED`. `REJECTED` `Deposit`s will not have - any `RepositoryCopy` at all. -* `IN_PROGRESS` `Submission`s may have zero or more `Deposit`s in any state. -* `FAILED` `Submission`s should have zero `Deposit`s. -* `ACCEPTED` `Deposit`s should have a `COMPLETE` `RepositoryCopy`. -* `REJECTED` `Deposit`s will have a `REJECTED` `RepositoryCopy` -* `SUBMITTED` `Deposit`s will have an `IN_PROGRESS` `RepositoryCopy` -* `FAILED` `Deposit`s will have no `RepositoryCopy` - -### Policies - -[1]: https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/core.html#resources-implementations - -[2]: https://docs.spring.io/spring/docs/5.0.7.RELEASE/javadoc-api/org/springframework/util/ErrorHandler.html - -[3]: https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.UncaughtExceptionHandler.html - -[4]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/RejectedExecutionHandler.html \ No newline at end of file diff --git a/pass-deposit-services/OVERVIEW.md b/pass-deposit-services/OVERVIEW.md deleted file mode 100644 index dbfda746..00000000 --- a/pass-deposit-services/OVERVIEW.md +++ /dev/null @@ -1,181 +0,0 @@ -# Deposit Services Overview - -Provides an overview of Deposit Services with respect to developing Deposit Services package providers. - -Developing a package provider primarily deals with extending or re-using `Assembler`-related abstract classes and -implementations, but it helps to understand the context in which `Assembler`s operate. This document serves to provide -that context. - -## Model - -Overview of model entities relevant to Deposit Services. - -### PASS Model - -Deposit Services uses objects in the PASS data model (distinct from the Deposit Services' internal model). -Objects in the PASS data model are persisted in the PASS core service. Thus, any interaction -with PASS resources will require CRUD operations (using the PassClient) by Deposit -Services. - -PASS objects used by Deposit Services are: - -* **`Submission`**: only ever read by Deposit Services, never modified. -* **`Repository`**: only ever read by Deposit Services, never modified. -* **`Deposit`**: are created and modified by Deposit Services. -* **`RepositoryCopy`**: are created and modified by Deposit Services (note that the NIHMS loader also creates - RepositoryCopy resources) - -![Deposit Services PASS model](pass-model.png) - -Each `Submission` resource links to one or more `Repository` resources. Deposit Services will create a `Deposit` -and `RepositoryCopy` resource for each `Repository` linked to the `Submission`. A deposit attempt will be made by -Deposit Services to the downstream system represented by the `Repository`. The status of a deposit to a downstream -repository will be recorded on the `Deposit` resource. That is to say, the `Deposit` records the transaction and its -success or failure with a `Repository`, and the `RepositoryCopy` records where the Repository stored the content of -the `Deposit`. - -### Deposit Services Internal Model - -Deposit Services has an internal object model, distinct from the PASS data model. Instances of the internal object model -are not persisted in the PASS repository, or anywhere else. Upon receipt of a `Submission` (i.e. the external PASS -model), Deposit Services immediately converts it to an instance of the internal model using a Model Builder. - -#### Deposit Model - -* **`DepositSubmission`**: internal representation of a PASS Submission -* **`DepositMetadata`**: metadata describing the submission, parsed from the "metadata blob" (**`Submission.metadata`**) - and other `Submission` properties. - -#### Configuration Model - -* **`Packager`**: encapsulates configuration of the `Assembler`, `Transport`, and `DepositStatusProcessor` for every - downstream repository in `repositories.json`. Each repository configured in `repositories.json` ought to reference - a `Repository` resource in the PASS repository. -* **`RepositoryConfig`**: Java representation of a single repository configuration in `repositories.json`. The - configuration for a repository includes directives for the transport protocol used for deposit (including - authentication credentials), packaging specification used for deposit, and packaging options. - -#### Packaging Model - -* **`Assembler`**: responsible for creating and streaming the content (i.e. the files uploaded by the end-user and any - metadata required by the packaging specification) of a Submission according to a packaging specification -* **`PackageStream`**: content of a `Submission` to be deposited to a downstream repository as a stream, as opposed to - bytes held in a buffer or stored on a file system -* **`Transport`**: an abstraction representing the physical protocol used to transfer the package stream from the PASS - repository to the downstream repository. - -#### Messaging Model - -* **`DepositStatusProcessor`**: responsible for updating the `Deposit.depositStatus` property of a `Deposit` resource, - typically by resolving the URL in the `Deposit.depositStatusRef` property and parsing its content. -* **`CriticalRepositoryInteraction`**: CRI for short. Performs an opportunistic (`If-Match` using an Etag) "critical" - modification on a PASS resource, with a built-in retry mechanism when a modification fails. Each CRI has a - pre-condition, critical section, and post-condition. The pre-condition must be met before the critical section is - executed. The post-condition determines whether the application of the critical section was successful. The built-in - retry mechanism re-uses the pre/post/critical functions in the case of a conflict. - -## Model Builder - -Upon receipt of a Submission, the `DepositSubmissionModelBuilder` is invoked to produce an instance of `DepositSubmission`. -The `DepositSubmissionModelBuilder` accepts a `Submission` ID for conversion to `DepositSubmission`. - -## Assembler - -Responsible for assembling the content of a submission into a streamable package (i.e. the `Assembler` returns -a `PackageStream` instance). This includes: - -* Resolving the custodial content being deposited from the PASS repository -* Generating any metadata required by the packaging specification -* Generating any metadata required by the downstream repository -* Encapsulating all of the above into a stream of bytes that meets a packaging specification - -The work to implement the Configurable Metadata Framework focuses on the support of pluggable Assemblers within Deposit -Services: different `Assembler` implementations can include metadata required for their repository. - -### Custodial and supplemental resources - -The term _custodial resource_ is used throughout: a custodial resource is content that was uploaded by the end user for -deposit to a downstream repository: their data sets, manuscripts, etc. Non-custodial resources (i.e. _supplemental -resources_) include metadata describing the content, for example, BagIt tag files or DSpace METS XML files. - -#### Abstract Assembler and Archiving Package Stream - -There are two abstract classes to help developers create `Assembler` implementations. The `AbstractAssembler` -and `ArchivingPackageStream`. - -The `AbstractAssembler` contains shared logic for building a list of custodial resources to be deposited. Concrete -implementations accept the list of custodial resources (among other parameters, including the packaging specification) -and produce the `PackageStream`. - -The `ArchivingPackageStream` contains shared logic for assembling multiple files into a single zip, tar, or tar.gz file. - -#### MetadataBuilder and PackageStream.Metadata - -`PackageStream.Metadata` is an interface that provides package-level metadata. The `MetadataBuilder` is a fluent API for -creating physical package-level metadata such as: - -* Packaging specification - a URI identifying the package specification used -* Package size (bytes) and its checksum -* The package name -* Mime type, compression used, and archive format - -The `PackageStream.metadata()` method returns the `PackageStream.Metadata` for a `PackageStream` instance. Because some -metadata is unknown prior to streaming (e.g. the package size), the metadata returned by this method may be incomplete -until after the stream has been read. - -#### ResourceBuilder and PackageStream.Resource - -`PackageStream.Resource` is an interface that provides metadata describing a resource within the -package. `ResourceBuilder` is a fluent API for creating physical metadata describing each resource (i.e. file) within -the package: - -* File size (bytes) -* Filename, including its path relative to the package root -* Checksum and mime type - -The `PackageStream.resources()` method answers an `Iterator` over each `Resource` in the `PackageStream`. - -#### Package Provider - -`PackageProvider` is an interface that is invoked by Deposit Services when a `PackageStream` is streamed to a repository -via a `Transport`. - -`PackageProvider` represents a streaming lifecycle interface that has three methods: `start(...)`, `packagePath(...)`, -and `finish(...)`. The `start(...)` method is invoked after the custodial resources have been assembled, but before -streaming has started. The `packagePath(...)` method is invoked prior to streaming each custodial resource. -The `finish(...)` method is invoked after all the custodial resources have been streamed, and provides an opportunity -for the `PackageProvider` to add supplemental resources to the package being streamed. - -For example, a BagIt `PackageProvider` would insure that each custodial resource is pathed under `/data` -when implementing `packagePath(...)`. After the the custodial resources are streamed, the BagIt `PackageProvider` would -assemble and stream all of the BagIt metadata: bagit.txt and any other tag files. - -## Transport - -Responsible for transferring the bytes of a package (i.e. a `PackageStream`) to an endpoint. The Transport API is -designed to support any transport protocol. Each downstream repository in `repositories.json` must be configured with -a `Transport` implementation. - -The `Assembler` and the `PackageProvider` create the package, and the `Transport` is the "how" of how a package is -transferred to a downstream repository. Choosing the `Transport` to be used depends on the support of the downstream -repository for things like FTP, SWORD, or other protocols. - -For example, a BagIt `Assembler` and `PackageProvider` would produce BagIt packages. Those packages may be transported -to downstream repositories using FTP, SWORDv2, or a custom Transport implementation. The `Transport` to be used is a -matter of configuration in `repositories.json`. - -### FTP - -Supports the transport of the package stream using FTP. - -#### SWORDv2 - -Supports the transport of the package stream -using [SWORD protocol version 2](http://swordapp.org/sword-v2/sword-v2-specifications/). - -## Runtime Configuration - -Deposit Services is configured at runtime by a configuration file referenced by the system -property `pass.deposit.repository.configuration` or the environment variable `PASS_DEPOSIT_REPOSITORY_CONFIGURATION`. By -default (i.e. if the system property or environment variable are not present) the classpath -resource `/repositories.json` is used. \ No newline at end of file diff --git a/pass-deposit-services/README.md b/pass-deposit-services/README.md deleted file mode 100644 index b2cd9267..00000000 --- a/pass-deposit-services/README.md +++ /dev/null @@ -1,210 +0,0 @@ -# PASS Deposit Services - -Deposit Services are responsible for the transfer of custodial content and metadata from end users to repositories. End -users transfer custody of their content to PASS by performing a submission through the HTML user interface, and Deposit -Services subsequently transfers the custody of content to downstream repositories. - -Deposit Services is deployed as "back-end" infrastructure. It has no user-facing elements. In particular, Deposit -Services is unaware of the internal/external duality of resource URIs. This means that when looking at URIs in Deposit -Services' logging output, some adjustment may be necessary for a developer or systems operator to retrieve the resource -from their location in the network topology. - -## Configuration - -The primary mechanism for configuring Deposit Services is through environment variables. This aligns with the patterns -used in development and production infrastructure which rely on Docker and its approach to runtime configuration. - -### Production Configuration Variables - -| Environment Variable | Default Value |Description| -|-----------------------------------------|-----------------------------------------|-----------| -| `DSPACE_HOST` | |the IP address or host name of the server running the SWORD protocol version 2 endpoint -| `DSPACE_PORT` | |the TCP port exposing the SWORD protocol version 2 endpoint -| `FTP_HOST` | |the IP address or host name of the NIH FTP server -| `FTP_PORT` | |the TCP control port of the NIH FTP server -| `PASS_DEPOSIT_JOBS_CONCURRENCY` | 2 |the number of Scheduled jobs that may be run concurrently. -| `PASS_DEPOSIT_JOBS_DEFAULT_INTERVAL_MS` | 600000 |the amount of time, in milliseconds, that Scheduled jobs run. -| `PASS_DEPOSIT_QUEUE_SUBMISSION_NAME` | submission |the name of the JMS queue that has messages pertaining to `Submission` resources (used by the `JmsSubmissionProcessor`) -| `PASS_DEPOSIT_QUEUE_DEPOSIT_NAME` | deposit |the name of the JMS queue that has messages pertaining to `Deposit` resources (used by the `JmsDepositProcessor`) -| `PASS_DEPOSIT_REPOSITORY_CONFIGURATION` | classpath:/repositories.json |points to a properties file containing the configuration for the transport of custodial content to remote repositories. Values must be [Spring Resource URIs][1]. See below for customizing the repository configuration values. -| `PASS_DEPOSIT_WORKERS_CONCURRENCY` | 4 |the number of Deposit Worker threads that can simultaneously run. -| `PASS_CORE_URL` | |the URL used to communicate with the PASS Core API. Normally this variable does not need to be changed (see note below) -| `PASS_CORE_PASSWORD` | |the password used for `Basic` HTTP authentication to the PASS Core API -| `PASS_CORE_USER` | |the username used for `Basic` HTTP authentication to the PASS Core API - -### Repositories Configuration - -The Repository configuration contains the parameters used for connecting and depositing custodial material to downstream -repositories. The format of the configuration file is JSON, defining multiple downstream repositories in a single file. - -Each repository configuration has a top-level key that is used to identify a particular configuration. Importantly, each -top-level key _must_ map to a [`Repository` resource][5] within the PASS repository. This implies that the top-level -keys in `repositories.json` are not arbitrary. In fact, the top level key must be: - -* the value of a `Repository.repositoryKey` field (of a `Repository` resource in the PASS repository) - -Deposit Services comes with a default repository configuration, but a production environment will want to override the -default. Defaults are overridden by creating a copy of the default configuration, editing it to suit, and -setting `PASS_DEPOSIT_REPOSITORY_CONFIGURATION` to point to the new location. - -> Acceptable values for `PASS_DEPOSIT_REPOSITORY_CONFIGURATION` must be a form of [Spring Resource URI][1]. - -A possible repository configuration is replicated below: - -```json -{ - "JScholarship": { - "deposit-config": { - "processing": { - "beanName": "org.eclipse.pass.deposit.messaging.status.DefaultDepositStatusProcessor" - }, - "mapping": { - "http://dspace.org/state/archived": "accepted", - "http://dspace.org/state/withdrawn": "rejected", - "default-mapping": "submitted" - } - }, - "assembler": { - "specification": "http://purl.org/net/sword/package/METSDSpaceSIP" - }, - "transport-config": { - "auth-realms": [ - { - "mech": "basic", - "username": "user", - "password": "pass", - "url": "https://jscholarship.library.jhu.edu/" - }, - { - "mech": "basic", - "username": "user", - "password": "pass", - "url": "https://dspace-prod.mse.jhu.edu:8080/" - }, - { - "mech": "basic", - "username": "dspace-admin@oapass.org", - "password": "foobar", - "url": "http://${dspace.host}:${dspace.port}/swordv2" - } - ], - "protocol-binding": { - "protocol": "SWORDv2", - "username": "dspace-admin@oapass.org", - "password": "foobar", - "server-fqdn": "${dspace.host}", - "server-port": "${dspace.port}", - "service-doc": "http://${dspace.host}:${dspace.port}/swordv2/servicedocument", - "default-collection": "http://${dspace.host}:${dspace.port}/swordv2/collection/123456789/2", - "on-behalf-of": null, - "deposit-receipt": true, - "user-agent": "pass-deposit/x.y.z" - } - } - }, - "PubMed Central": { - "deposit-config": { - "processing": { - }, - "mapping": { - "INFO": "accepted", - "ERROR": "rejected", - "WARN": "rejected", - "default-mapping": "submitted" - } - }, - "assembler": { - "specification": "nihms-native-2017-07" - }, - "transport-config": { - "protocol-binding": { - "protocol": "ftp", - "username": "nihmsftpuser", - "password": "nihmsftppass", - "server-fqdn": "${ftp.host}", - "server-port": "${ftp.port}", - "data-type": "binary", - "transfer-mode": "stream", - "use-pasv": true, - "default-directory": "/logs/upload/%s" - } - } - } -} -``` - -#### Customizing Repository Configuration Elements - -The repository configuration above will not be suitable for production. A production deployment needs to provide -updated authentication credentials and insure the correct value for the default SWORD collection URL -- `default-collection`. Each `transport-config` section should be reviewed for correctness, paying special attention -to `protocol-binding` and `auth-realm` blocks: update `username` and `password` elements, and insure correct values for -URLs. - -Values may be parameterized by any property or environment variable. - -To create your own configuration, copy and paste the default configuration into an empty file and modify the JSON as -described above. The configuration _must_ be referenced by the `pass.deposit.repository.configuration` property, or is -environment equivalent `PASS_DEPOSIT_REPOSITORY_CONFIGURATION`. Allowed values are any [Spring Resource path][1] ( -e.g. `classpath:/`, `classpath*:`, `file:`, `http://`, `https://`). For example, if your configuration is stored as a -file in `/etc/deposit-services.json`, then you would set the environment -variable `PASS_DEPOSIT_REPOSITORY_CONFIGURATION=file:/etc/deposit-services.json` prior to starting Deposit Services. -Likewise, if you kept the configuration accessible at a URL, you could -use `PASS_DEPOSIT_REPOSITORY_CONFIGURATION=http://example.org/deposit-services.json`. - -## Failure Handling - -A "failed" `Deposit` or `Submission` has `Deposit.DepositStatus = FAILED` -or `Submission.AggregateDepositStatus = FAILED`. When a resource has been marked `FAILED`, Deposit Services will ignore -any messages relating to the resource. Failed `Deposit` resources will be retried as part of the -`DepositStatusUpdaterJob` job. Once all `Deposit` resource are successful, the failed -`Submission.AggregateDepositStatus` will be updated. - -A resource will be considered as failed when errors occur during the processing of `Submission` and `Deposit` resources. -Some errors may be caused by transient network issues, or a server being rebooted. In the case of such failures, -Deposit Services will retry for n number of days after the `Submission` is created. The number of days -is set in an application property named `pass.status.update.window.days`. - -`Submission` resources are failed when: - -1. Failure to build the Deposit Services model for a Submission -1. There are no files attached to the Submission -1. Any file attached to the Submission is missing a location URI (the URI used to retrieve the bytes of the file). -1. An error occurs saving the state of the `Submission` in the repository (arguably a transient error) - -See `SubmissionProcessor` for details. Right now, when a `Submission` is failed, manual intervention may be required. -Deposit Services does retry the failed `Deposit` resources of the `Submission`. However, some of the failure scenarios -above would have to be resolved by the user. It is possible the end-user will need to re-create the submission in -the user interface, and resubmit it. - -`Deposit` resources are failed when: - -1. An error occurs building a package -1. An error occurs streaming a package to a `Repository` (arguably transient) -1. An error occurs polling (arguably transient) or parsing the status of a `Deposit` -1. An error occurs saving the state of a `Deposit` in the repository (again, arguably transient) - -See `DepositTask` for details. Deposits fail for transient reasons; a server being down, an interruption in network -communication, or invalid credentials for the downstream repository are just a few examples. As stated, DS will retry -failed `Deposit` resources for n number of days after the creation of the associated `Submission`. The number of days -is set in an application property named `pass.status.update.window.days`. - -## Build and Deployment - -Deposit Services' primary artifact is a single self-executing jar. In the PASS infrastructure, -the Deposit Services self-executing jar is deployed inside of a simple Docker container. - -Deposit Services can be built by running: - -* `mvn clean install` - -The main Deposit Services deployment artifact is found in `deposit-core/target/pass-deposit-service-exec.jar`. It -is this jarfile that is included in the Docker image for Deposit Services, and posted on the GitHub Release page. - -[1]: https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/core.html#resources-implementations - -[2]: https://docs.spring.io/spring/docs/5.0.7.RELEASE/javadoc-api/org/springframework/util/ErrorHandler.html - -[3]: https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.UncaughtExceptionHandler.html - -[4]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/RejectedExecutionHandler.html diff --git a/pass-deposit-services/pass-model.png b/pass-deposit-services/pass-model.png deleted file mode 100644 index 35ae35b65534f190f5da105fd5d13595999444fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23852 zcmeFZWmJ`2*FOpfQi`NoC8U(zgmfd_-E11^kl1vmAV_yecf%$&-HmjIbR#Vwa4x*> z=Xu}rALD#D<9t1i!SLd`R?S#*%{Axz@kK#S{5i%O3~kNj^7Zs7UxH6uCc-zJWheB>Ik3Z%le z_9mokU{){_IX?y|DJieL@h5I25wU-}1HbW+n>jk#aWgVHJ3E7&KY(rRO&OWFxVRXZ zSQuGY7=RWG4z4zi1}+RX4ix_k@}F@;OdO2t&Fvh`ZEZ*&$2Bmtb#mk*Cx4vizyJPO zr=$6&|C!0g;a{=<0vR8_FfxOg82>vq(3SV`Ew_@1gRPa*aWC-T2x5?ef3h{h#gS?afU9`W~m@Xa2YS|9wpTE-b+iR|ZEtQQ zY2#>O4@~xN@Bb|D|GCA#WAQRRvg?1b?;qLxeG3SOAA^_izk=q+2pTV=L_iQkkQ5P8 zaX~yx!%S5*X?Otn581s2D=CQSh|1cmB^JbmW|^xPk}$?4Vl4Hs9%iVCWqHcYZQ9A@ zhfU$c`AW3u_c#MD;uaOR#?yY$RqE}`~P*YfcA_PXhV zd->ok|M8V;MsvoUZu+JxC7K`t61EQlGARP$|Nr>^nGcG1J1?D3(7}3ELA6_2w<|MM z_o#EaZsD2@nHLvYw+|eH4DpiK5`>5cZR&=ds#Ye{rvfJh6R|lWu@hn z)pC=oyphrRGMnYJ%0lHExQ(!rlT$OXwuNgTz2K5CAuk~O&L(EX-sT|*hitS?kXHP7y4QzSW^PMr>a@}T(aTjIf zm^zCoTHDQmIB>Z}rQxmc3%-pc|E=e*m{#Qp*{$mHb8|P*>HfG5dI`nZ;URat^MM2m z#*B{(A;2YqNsOj2oQk9*?JGVVEjQot5;hlcAJ$A*$njrq?DfY`xeEt9qe1td(RCko zU;9GUBu?U*Ge=YjNny9P*d5F6J=}_1GDhN6#w9C2M!Lmq17B{o^Pq(wK!pT+1bvZv zE_WxkZ<8+xxgB>dxg53*O3TZy)}txIjH9ih6|1y(dSA|}+4u{VAyY}j>qeYSn;esy&CW9-X5dO!W#)YIDTdB=2<+Hhpw zk7)X!K!x@68oV~}c$vXGh|6~uc4p@Zfk4(hua>qKIxgyORJjIo*$WuNiJerk=RYCm zi_1k}jEe!BOA#}de+8_XiCRgl8#mEx!hW##>+6Ynmy@;BwB#H}0jw|_Mq%Gze$y8^ z#r}LW4gnfPM^jcz35fZfc?v8@PX9ZX4yKim+eA3Wa$+b>Sy`%3xX*A3$7o$zlB@+B zhxiq@DuxU|Arf4|?QO(IFW@00OHWlUX$kJ!+P7xOHk8a}nSjD@IG`uFaU>^v1M*2@Z0)SAKha|{7@s?mIZ!7wn80`?9{whG zw-^4rg2Ys$NCsG4{E0p&&K&u$<_)|JJiq&rXdqZHO_r`KgW0GD9EOoGl}3BJIg-ZX z$&5qjubJ>dp-dJ95JTEGgadK{Pk5r3K4?~y`7VF$_)tw**&+9E&r+-2&VUEgH`! zHqoP1Gkg!77Pe4ck)|#8ofSoV9|6f(Rsh&Rev!tz_Y|uNWt|b?ane2PetAIiok#VO z0q9_87WxLiwu-vd7!WSG3?ZCaQ-HxqbQT4wxW}K+coQ_ImFrY(I@+^N+mYy4{3D}fmP02cx;iH|JbF-c^9P|lZ=y%&Bd%pPPIb~~Wn zQdQ@)5oX@IkwgepEJ1X%6M#nX8udlLg719S1G&F~_wAX`cxx74NXRh0v}7S(VT6@h zwrJR85E*rVxsS#(Q`^DOM$a^(4MCab_Ys)w;3_w5DZR@IVi)=0RIciVb(^*%CN#5l z&wU&5kFs4WiGX@@dt#aBgHAYt=+P^~h;AHTCFp}Ro53cGaLu7YxV777R5+-UDQ;vC z+bA&EEc{F~a_aXRJm{FKI@Sd}6h}|kjN&yE$71xjiRmCq_E>swVQ+7*I8P?2Dv1-4 zMkttQ+N~v|rcJS!pG%ipL_8~+$j4t-RT1_(1sfWrt%r3+dq92~W#fUeEI6=#$CKsJ`0vzu_?Aw|I;H82#%#CEjV>L9D)o-hpF=zQ!owlkJZ zn39}qKf|dm_ECR(B<;RHG5bw!jD}+b#!F!D=7fP%sG&G-g}cBQdmT}W0gwPoQ10Rq zdxd(ru4TH{&F=ikdT;Ooh7?^$8zy7ZDzWGJSokNE&Qc#)6oL-fZos^TzI%0gH!IpF zh)IV9r~ayK>}&w~nR!T}tC*Hx%$(!J?0IueVbxb<>;whlm;wjLLG%61zOJX|oq|J4 zB9vY@p$$BM&>Tiv83sm(TV;hRBK5hd`9e0(OJWA4+18wlAMWo!&8Gu&eAXi^c%L~{ zEs(TfRwrU#UsXB)r{8gPV+Nhm9f9s!D9!|y4wyhF`}~R@HulP zxw^KEL?&!PmAVb>IEG@eCiXj-5T z%~1zkCm6#Nbe#tKkb8fBd;D$uB<}zlebITv^S;gZ$v(yLD*|0aD2`!1gOK8^sQI&( zaB3k_tV)c7EIW9Jz4|&0g?L2M%twOrqiKc#3k+Lc=OgJhtMTgZMLbqlyRV^JQJ$lx z;KwsUf>c`d8B`H>9PkR5g4NNXikyRe(`U2g33?Fky9){`xm1mM$3?(xu#c3rPLnKO;1-Bad=~@x&&=bL@Z<`==efHqERkF=CKGAkQnEm`6eXCchegoYfLMd;0DD@Rm6PEkKe^xYe!w~uw z8kO;}gXAPxf5ETVuJKg)BT;!gmbGcoO)t*pSVjXD0}#5hhWMHxh&YO7hZCxZ4g0+m z0NKcoQ6Oeq_{nr#Ga*;pFOOUnLFfCz>z6-U-UQw{t)9|G2RJ&baB-sxY`;D^r8+CB z9uVzB0`G(9WpeBKqrOOop7v9zZ|m}@_awE&(kK_n=9~6t_E7c(K`4c!8wNul8zV*4 zblDYQmgUXUAA)UKt+KC{C8^Rj?oPgWAIRiXrQL2&3G6;6WT#hdWtcfRYTPdyx}|Jt z1KZDxBR1&GU&I01J&D!zbfb)MBUA*N^P~%pZ(?`s3pRVtM?(;^njB)50SHCVayy>- z;3Fd61$ByM^(WWP;1|xddx?DEo$kMX2J@vvoy0R}=ZR<6QYce3 z?`{=U;1{L45=lcaU{Jj~9GkG}h-sH2$%O68)98$31sh}K4o`%FQ@%6yXwCk{2!?d2 zbD&5DLGS}g4`rj~yG{AeULW^Sd>fj)z9{!zO8H^QLb@fB|g)86(#yT%p*SS)q+WF1Y+3MK> zj`)bVrG>?SPCiIp;I1a0Ka)l_T-Wo!=T;BdcJTz<)a8uhLIs`ssTQ=NW0(v{YQ_gTuykj_>1+q*vZWA~N)i@m8q!VjOm zI!~#pyTYM|1F3ZtSVyx)-}tuXs@^`@DhKNy)Ot{*Yuej#?>o!OpILfFpa!yM!zV?h zrL`@rYC;^6G~}ddQgt*IN|GslkXU@@e%elOs4xTzUjJ}^oA$%rDt6<*Y(qL?d^17s z$a=YHu9~XMrS)d2eDRuN*`?F{a?W(A@^GQfJweC*3y1xNg#3usD&=kmRffkn*C+3r zi40zMmGrBzZ(ftP#}D_m+q2X|e$hmg57!wFpSK?eavL5VPEXBQdAPqi`m;Ax+`OIP zz1+-y{zEwJNj}H1>!^E^bJIHU(eH%TKPJc0dNk{w`Y{GcF>? z9cSaPgQPQ#1>Eptr+=wwSA;>i-ARJ8sxS$Om4<{K4ys2ltRH9cYm6&iu=%x`qptKkz$L3oxO2pJJmsM>(9#lCC3U8?MmLOrOI#Kf7b8eD|bgj z*L3Ag<4Z=CO^eJ9tACzgakkYd!aa?n{#cZA#T_*oMR4^rbD)mby(2$L>^3?V|N1J5 z#{KT*qQzS9SL;c*t#L%)1roe(80{nB3CoN7RbebH$~vtET4v-NxQbq?1Eam;H@@9%A$Y(OEfc zE7k=Baf|{^#4A_sPgs%piX}SHVm++mxrNf&9!(W;mY}fQ zGIJZ{J^SkJeYNBa7rh1Px)|6=n>_%IokGy2i_=1*)4u+&cg(n`Aomi?dO_b(Rm1Zg z#E0AVIdqIGqbt1|9I6D_fM&9(Up8!3g>yF4$|P4!WZeb@J!MQpip9${?@#>0T>fSe=Cz%vP} zddU`Ev&uL``DCoAZfk_YX7SahvDi2Y#N8SoQlQn$#oDV~f53ngHQTM-eO9CcTs5-# z5*EQV@sbn*>~~uCvaL12Zqo>O)PgLVJBNFy>kD49WXyZl zmsX>=d^&XnUrjEs??CLDemv~eJRCpVwSKhycECSjT}^PW=GfY2 zAq8pg?5GL*xLfm_wvYyN_Yt_AO*HcyH&y>Iq-d4bQ@{wio>Z1^Xgn8|X`N;Z#SRXD z;Fkne%?9S-#MKlum6eS&$4}&<90*Oz2{Qz!w_++?%83(e*V|?Cuo-k9Z)-d!=AH~U zGoNRcc;h>s9!S$Xn5VKVH3I9+YdpUG=zZIGDNN zk6SV;Qi@o0-A+sJA}>=GoS&VV|$1s+^Es9J57xaE12 zSk=o7<^>+EN7ETt4{E-y=4^Fa|J47*KKWqnzf7QAPY$ZPt5vc}GFY^2Jha)I3{q4J zjKe8{;185pD@e`-OjqtClutM9gbB*YEk?tR2Zbipyx(az9e7FXI;;Z1W`Nhvinh~I zhe41tN-bx~F07)Ood;<0U1oF~!U<8_S8kWLr!8pGr)OF&Yh^N&F*m;^wH*Zy48+kb z*+_&Zrg`6AWBCmHz|Rx4xx#0Z$$VdPDP=%{kMU9951UeMTFjfz6ONBcwQWw7{gJ;W z!H@qT?bxF?u;F(bD*tMl+g>3MvN~HVh~Aiy`QbDJ*(P6hX7kH!tDHwEg!Mu3r^$-~ zAR?mB2m8^=%%MYrgRd2G`_L2(s)cgSeGi-7Acok*V;ynSA;rN1rQMx35zcaLUp?T3 zO@CG#Z?E9>Z_$Ur+%pQ>rv7QVuu_i<%-RL1O9O1ru>I=M2F{ks?shpfhbBWZ5~yOu zwdg01ke*(nk|UFe+2JrIlA zDXXMDZRsAHH$}|`xBLtu^hnA4JX1h_i*vY85KkxWO>f^~%UsK{ts23%+3kH;JG02f z?p`%oCN@_Tp3|^jyRO)uN8qVlz6n(*!Xj)qJ!F<>;j%kwx;InLZlPL`W}n|2sHPdY zlnaJFgHz9fPg_n5_pxmc>li);&hHh;{D))Z4^1fo|39;qj_gJuAOWDq7kk!_A8U=1JI?b^4t~vwrm9?^Zqj|ZKTVphV z`;%`UuI9=KR}2e`mltdZ)FWUo7m_*jMzTv42d|rC3vV7SZ6D$rya1DRKa}*rQ=5KQ z`u(ly)&i6BmIrB_%WOHviq|`ubAMZ9X|IasTn?Xc7{69dyA1E-sGFJWUW}(~W^*@` zjmrgo0*MxkzG(S6&#ga_Dj_fBqM!8*3hdbsYl;86`qhNI^n;N&VR zFFn1aoA;!dV?hw8e@~rXd~Zo%YahZas z#JF=)j%!vl_riIuh5yO9=J(Nn2qpRh@*M$K=Xiqh^yP;Sc1^|{dsi>5CbGavg*TZTP$sxLhNtpyB~-zwftZ70-HV6cxq81l zK+xb^nG{>+k%aK9hToJhp4_FZi^1-#A6Hza6I4gbq-B!7!gO1itU{*h*i>3%_3ACX zE~_&d+`Ui2^y;r*Jp<}#u!(NZq}eR{l{}us;8rh&z7r)bcE;nQ!H8yZqw$2`=M=XN zTSF(Uzq=W4Xyx^2LkTCQTnP$hY1MT;2hwR%c*FL)`g0Rmi}dt3^SE0}7o#U&jBpsr zjPb*~J<7|IUL;hDyJZvWMp->~fr(S4L9NA#i7KL+QO)*}7VyK%8EGt&2Vvi5E*!dX$6w&x%~qH#m8I(3l*?w< z+vmxp?LC|cJXDuI&}vgWle#g;yt)yhB&^-Vz0ws>u;TKA=cRgcSA=n}=_Pp!SPokCA1RSEeqeN>iXfH5}woOBK+8{~P_^;}{ALTJ+BgJi2z0$rHllRBo54TA-7j*qE z!Hs0rvUn)=rrzlNeU2HWRDFx;2bjCl15NW)FQ;WIJrXwG4=&KdZ?qmPrEq%(No(>H z4zm>apqnmp*)pkE7f-|~I^V)nsH+1!na?fl zyKb^y$qlE!+-99H8d~!4Z@JBqn++U0A`h%3)onb;Dq57^zgEI<$?x`mq*wck7nDB?2UB|Be*1g_T0mLoHMkS`xyzB3r}UUI$7>eB%= zp~2oR^kukX@2_=-E%`}z`;Qq8l#QTnB0msd%VToal75iT!Y+iGsYgHukZIhdtA3kt z6uj23;~shl)--sbo&KpIe-qYfd>DDOI*Z$686)D#7D zTMw<)r>gdEM{RBy=f~psDb6)BN1u5@cRo-~9%IrmM(1EZbBoUu_4=0cM~T4gY?#CS zrQ}NWTZIvrv?}9;qYNp1Z}HemN|>XL?2+lYFJrzCPvtq20-yZ;qveGB!AtS`Rnw^m zmpGMlvuM2gxUwBjiVcCTa*5($Ma$AOCfFPL#Wr_ya=!c{@aI=&^TSQ~gFRf-s%UHi z{Cdgqn~9zE?w*H&+%G-Evl>}V?T2b*>^Bq(*Ut>ck!PIVo7&0pKWIBGm|gvus`9E` zHqulMsT*g8pnaeZntO|ogc6yXAsaD}we^A$#?54p$l6v~!6mG>RaftFYRu<(l zR{BBpmy{^VOhSqm8qN1?FV4Q7(jP6R4ijY5Zf;VZ@y|popTEu=#qj*JQ!Si9mg%Xd zp&9k=uxM(#6bM&H3fSRG>IrN}M^&{jN-09f_tAz=s?0+bh#0LCreG_pKQj?kU$?j3 z@3+z><}ZX264~Cat;l#O_oR0oRjYD;@h9KUUfGh|r1R+xD1@|tQYqid~P zYm8M(^IRx4-=yc(>VE8nou07$^nM3JlqSw>?4<+jQ{Ulv<#N%xr^=)p^lBR z5;h={I0TY1^V`v$tgO9*L?o|O#v~E9V_7eLu=nFA+D)y_z{CnzPh7Kp3vgiAA4Bnm$+*S*B^gD5OA4gtQAx+`a-VvWCRWU9 zQ8Y$n!et0k?yn}Ud(DiGz`~=SBi6aWi!#B|aIU94xVfk94GVs71H82>9R!29YOkg) zJ|}(9XAqCnb-c#UsrZMfs;%vanvzj8Pc`FwjRjHIcem0+?PSlfZ{B>~ioWs$XjAMT z4~?E!9~Vzv0lsPSCPGv|6JE?_Z?L* ziANFj`5A*oTJ%>{3WT&YXV9lR#n%>tRQxCCRCUv{8YS;Q&*z{rjS}~o3F0^7E#Gq& zU~kjsoLa1GTgH;Bzp3Bs|2QCj771(bEWP*xC(q^5SGy zUCRZ-71N5|-JW{7b>Yf(Z=@GKH9~HB&3DtWe%J<+=O&%r=gp0A@68`~+ury2+5&mh zH_@V_H8B*>E*x=}7r=(*AI6GD+DUS7yVt#(@9_lFkEH|u9V5G*_I=!ZjCODBuz-7hb_79;)%i!diB`hkT7;i z^&u{e&O`b~t7<&-a2}LI*O9dgZ>0Pdy*DlQ$zezbiaPik70wh+5N~Jzf;bUhaNK4d z8P3f){^3v9PaTf0zc;67zD+GY=a>~W5L4`fbXxD!G9O@3^-2i6o~k5BtF!ijf9Dr{ zsMY(`zJT>W$CM*$P_OSotgEtt{yK+20g8ByUzBCNx9732f3X~71M$d-m|t1uGa!kv zDOG;Pm}8{!n=cAT_cR`s&~u3i86U24U+7H~man!;VZ18*t(%rxc2hn=7w~nDR{ia< z%zeZN5O&mdCO;rYqssJ|JbWjbT}OS`5>8|)w=eF8WJ)*QjD)n08tPa5R8k=I!au*- zXBlI_nxd_pA?YDhtK5A(y&}x-ko=esK3Bf8B-FKA@BD0IFwMu2c1i17p9u!paYW21 zp^_=cnz($?U8%9G3mjUtC^9ShD}=aPZ0KD-&cu2!{lPa(-jYP9TL!U)Mnp`MLv|A} z%6SWrFIi%PMG7dFk}q3|iF}~`EH^7^1I3wMb8{+t?)D2z19^KrblT1Qs(jjet_n1ocgjaN=JcX^1iX$a@Y`40(#p3P z(lii7A@0UrwM9}wTmqTY+8{MQG`hUmT6I~x2V#Eal=QuWA4XerGw~&M|3>_FEmU{4 zV%Xt7I-CzVC)ci}fMtE2m-mD8jVV@{5<=%R2zO5ok{Z(amWK~*Uf3x7p|>s@z`|Hm z6|_C19eUMP(;er0tT<11qciWbD={sv4x~C^2c?@jeg=^O8Bb!za>9JX^vkv#vJ*8^J@W~XDw*U zS0wjSnRV$^Kr!dTpR)x#3bo#fu<_z`yRbTfn~@$)M#>W8xg6zvsh=WA44xTZg~Mk> zF`lEqspo49Z9!VpWociu=z*T2#}i?Pud`daQynpvhv)3J4{&Vng;0q%v?Gs)YT326 zW+o@=nW(v6(U;YkMt>?B3yYEGp9_>w49Ov-p^OZVXn;gt?v$ENwQ8YYC z#0Ztboq7f97ttjW#?9~fe0i$S^+63+4U{@xAjVfm9ePylV0ttd)Cr#U<)z?MLZ>l> z{ylRq(K?hw>- zA^cB_=^m$&&N|yw!fM8Pc=#3XrZkl;d0E8&#(LW3MYXxWE?r(De7R4ISc?=?r>)c6g$dB)#FX zJDbmcL9_kib^jfbn<*Fu!dNXz)IaPF7-|7yl>_0uL-HCn-J)?43j1hkaMm~p2_{G~N;K2LRR87_2cZ03o{NQ_~9kyFrCQXKSuJx0mW{`ttIGJsb zA!z1IuGG`Uw~0%8F2O9J-d!ag*h;~6!ovRUL= z=-bifR!e2k-Qp@=yY9f%q}}O!cU@dYp@^3aqn;tENY|(xvbYaPgmKGO z5O6pv*0cOgO98aS=%B};z$FUS=0n3FHSd%r-4C*eJ>Do{LRAKKmHw2~17Spg=YiZ) zW~!E^J%^Yt>0LgY>UdSzIekTw2p-RMd_z$QS z0BN%J0ZfrzFcNO&T`%~fux5)NV4`M&`POphGb&wo4@dcLt-PY`oUG6!oX0aAUlV3V zGonGG?1&9PQPkM*5M;|;jBfC$DRJO>t~kY_{eEfP(TE<=QOFa-g_lhWj+_EmRXLJR z56I`{yTDmvK)~_&j8a@EWJ8`iv`|cvd732Z*H_V>hd^TTi*16pbOQyj$ca8eRi z?g8DDa05{}j?aq!lnHeoa37E>1?q#M*22r|4zieFimswJ9lAD{M;I}o@By(lG1`lY zna%eIa_Yae0P&e>MdJeLLT01?)g#g@)6?_VW+|&AuOi4{<{o+Ir_!rP z;!BUp4+jSnw|ebS*g)2iOpx9L2gt;l8G+ul6Y0JKwhVpto0Djf7ut?17cY2!3H}`a zY$}QV=d!N#0tivVmT9|pLnC;hIK&GQQaxbu_Ia4XK^8+)VrwsWt@yjc{@&i3;ScZM z`S>`RKz0{@L-QvkfE->M2@+0aSo9n*6vwd<`A;txqb`hEyoquujj{P$DLdU(G?c?P zKizF0rc7o4zQ$lqo6`x#%@RAv$_ecNONGLJ4OE16%*E}E>>BlaHLqEEf&S|!owCTT z7MIVA z6at(&R!8K@0EFW^T&@A^G~Fn@a7aLKy$XeHw2QKX!&$Crn$z@U8jo|(43ZRWh>s&F zM1pEuRw&R;`JaNXAeE<39NfOOuy$~$=_@VtSy3};h)}L$)A_H1Yul!io?~#s25ufv z=akWMt|aO>%8SksLdXt>J}8rdpQL~Cv8Rj?Ez17nK`{8xh5r}Ej zV$R;Y_NCcTpD)YS$_>R&A7sMLbwD0376McTRURZt;un>{U@&taD`;}06sO*t7}o5R z+(-#cjUD_7iS4JX4Aanl3H60^HTrMS=}6|ksSa?5UL7sX$N(jKx9NQDRaj>%Qb>jj zTZXn5yo4r@SO_*CSyHQRAU}=YTaN4usJPD}3@BM(h;nQ?p02Z9f#=JmHFo0by!URg zFCtiH8(Vh%>Xnj8U+bic!I=-#rvx*|Is%q=t7 z-mm_89QGX){O}eokv8l&`&|gO>b|tt;BXbR5>5*jNg1%l(WVe+Ki!WPn8|#}iNgV? zmB?0#3CMpf&v9cnvTgft$TGh7%o8WvKp#YW**uy4>J!76z@MKl>O>}TY0Fi(sthd} z^eoF?n>_3@SbpZCc?}Q}DO*Pjmk^ULu%aoi-P*6VG^TqBRO^`?V*H_t7ZkXQHh9(G z5{BD39R>CjG|6wj+~OJ(sMRThl+K<0YP19vaq|AB)J_+;aT-ZI*58Le+v}4iyka3j z&Jf@x*NrjlKG9^W_d`O>YWh;dwRT+M7s&p69PF)%P_W|aWG_8qjSexD%)!#~Azg4(l?X>Il9Pf>9WSEC1#N1Gbuk=fa_T)+ z=}~rg&ZxZ;Q_ho_qyLnbpd&1X-1$4%Z4#f7<{n^8*)W-ds4o=fK{wI{eZ^o{+kz`& z6MI%PZ^ro!C~T}lBv@#)0TQR`^IEy@(+_7WnZJa;nq%KDe&#~fu2^1qTVtmhb}V^9 zvMP?P|T*M4?;OF!D!Bvd*PH06e^bG<>f`V z10hr#OlEV>Rj0~PU6n-iz_dh-Oi%hR!#&{n%InBO@-KJfg)IBk;u%62G*yU?MSjMh zwM!pCJ#8khtH*k-1P1MCxw@hfVMEfFhK4>JTGq{d0P;2ZAjON) zP@99PR>PYEa^vs#Aaq~L z(#Zp}^C*>QRcdGyihlw&b$pxS!c<*LSy|Z$Q2Zp{jg}}@Kl!p&()xoS2p_Z1=k|-e z9zxBlB|k`)#Osh~GVFj#bH+EGTUls;cyKy$cLvBwjreEse(s4!5H;MzYulV$9my_# zsC#$z=laaER>)d0g}&H&Q%WfImPZC5YcW9@GjJvhfL1hg(p<(tyk%7 zLI~twG=Kt|I<$@E2`ZMy!0F{6V{4OZfAqV`jG)-B(W)#dowBB#cU&CM*QL9{4~Bzr%#W@(xcrj_Mn-7aYDdHfgqw`{vRgT3G^Q<>+txYU$y?pof7 zJYc~?(wW&*UinJGD1Lz+%Zylz`y#C|c-?@~k?Zo78;gD-=BZq6)jH!y`sn_1CK{ne zg;;mdc#=5MB%E3!z#jBkapGb58fJ|JQwZJX0=xRddIS+V{;5k6QCP&GiN#q!QBhI< zV?_|mWbozdMCZN2e7E(U@O_6qvS62im#LH08k#6<9pt9&#cHLeYGpdRr=bLNFae<8 zVtKk$n{OfM_YjaOKC10L`=7k8j))->*LVu~=a6X)`ow{u4DO=JXl`FBeveE$x z|S?q zDlw>hJ)K;8n`b?J{d6$g`c%ukJhdx|9*?Iyhx%$hGlw+9dDDpsL=`8f4m}~ZoHdE3 zn*&D|Eii4WvEF28-ct?Uj3r%8#zB60MqQE!-jXVOL<+TkXfy#-5Zmo*aZ$iqBIcgA zm}62n;ruV3i=sWkGB(MX#%a}tD!DdsecX(M5qjy^i>Sj$Z=O+`u-;U$MoWSY zmjxRwj~IVb7pGV<4p>mJy(7ayeE7p8%OEDL_;C$B5_Sl)uWhoGmKhIi4-2_gJ+fU> z$L8yqaX+*3s?WH80ViD{ZKksE7x4t`$+2EYoVvR+l~%54o1;0cg*Dg!EJct7J=NT> z)!;hEIP}}3D|Xw-z!Nnj#<=H$@g@`hKv#fC@MK`m;|cncV|5>gm@2hWXQ$VGFZ76O z5kx}6-sDG=qE!+hDkn$mIfsg7&*0G-cmC5^0vl1Z!F%pB6}kUwK?5Eze446KS!^k8 zI6uw&N4ZDNA7Z~U?hUbD!Ais@>Nt_|#nn#14hSTB3MHVd#(AF2` zLvBDv&aQZL*7349>~oW0ZbWKe)bK7kp4&Jw`d?5FZ3u$mQB0{7QTfL1H=ygpYuv}K zXmLK|Mz%E`(1Khg4H~pnmpDIr7bom+e%|<4WB>+4I)?l{@w{A9t;aKL zmBh(=pLGJ;J79+88zJsT@+(OdER}c-ujK|s8omWeapNQP77MeQ2q;?PVu!aJSO_9K zw(2MS&KMpT|F*WIZ$8Hbx9ub}UpGYTt$Z^n!Q(PC@X)dr8QEwE3{vm~0NI~RNMeWI zKgA2*z4^V1`sI<2UFmIBF_F|)Cn|Um>P_b?16_dVnjHODA2Cn3l0J`L2qV-z&a=$U z-Efh|cGk1;D18A1k2FI9R+e#N*R+-yL;B{fca02730M-KQ(BKYrJLM!Lfgt8BBtj> zOp5rp8WlX!0Z)&~uys{k2tY&ApF-lt*4@~^YhIP`bya@8p~|A#NI-_06Nqe&f+(N{ zCSh!C{M;l}?hhP*{?dAUY#;wl^6qgo*V=FEs#^CV*^CUf7XE*?9TW{&Pwd+qSJq

Er8^3kxV9782tBYfUN}EUO6SR6ESL$!FY{teoThK|Dadik%n|A} zjevsIc+fo3g@F8#{5$m(Ap>0&2MssC{ISY3E79T?zyRDmvCsYvK!yv@5W>VmjnP~D zgh`Y{jn$0{LiJJ;tL~9_UwVzk9?(gj(fBNq{UU)T_n*!E`cV*Xc7T3%s(@|P@)}_o+vzlrqWKGGQ}~1g zob7O#h-8+*==i^jqT925F-2|PkS;zC0=N^4BE?rIaFrZK9n>+kKgpLuI8O!*=0bQ z^K~PjjC-^&e^nfWT-D0^#lDr1o(oSle$!=FU?fn;Ox6%^{&^URUqt;oJ9b|bV8wWz zzUwvowh8BM$ypl#w%3}9oc~`^NHKstw34yc50#+MRlXEZjS?5rEZ%3p3vVHxlF$C9 zjn$*BFWWW#U~ z8U1Qds!51d<0bjvZ^hW$Q&NI*<<>fVxr5NY9L)hGQt3TCJwi>Lo!V&kN0ncwG8v?FC}>ia=bHj*^mQ_TO3p525Ea*9X!v&kj- zPqB#V??UOy%yg@aB@^Tn8WC;pN0~9y2C)d!_FA8B(<{EHN;Va z;rmhV42!$ZfKog|;Bfm_I?V5wCN{K8xdy1Oo(%ug(#IT6u>k@}DqroKHgnC9ACaUj zhkjN{3*pCYXcyiAad&`kIwp>ml=ZLaFu+lWy$z3-$0~07o(dGP>lvTazWFqqTs!C& z58W)!Icl0Ofn6QURSVH0fywSOtW25>G!d2lyLQTewv+eyspSq;8+^06qg6V6ugPpTj5%{^030=ha$>Za4;^B_hr48-(@|BC4dj>DETP!;Q(8Gb<1)k=R zyt^|rE_u^6^qm%_Wh!})>o55B&2_YcP9J{7lGtDO8X%7p3)w;jO_q^e6RTyz{{bWX zhhouxfrkLFQLcFcU+qb^)KJ$*+cXq;CL+x9d+=(jW6t{c>wnxoz$rn-{n1#4%3$dz zs;t$X&~(2)t1@UkL8{GkKMsV$7Mn~*(0lAj6hm^1Vtqz+|vg$sM!*mHPm4PfPn>_{4EleBnygdh7fb4;H;h_v3+%$$y^Sf9I)=6 zBmmhc%p+}Q9w>oDR+SrRY2d#Dq50apbl9^=(Oqmm>L%wcBC;j;2ZI=A899Zq8_J6J z*P$Vev`3nnno^fdVlnyfxzYYS^<%wE34w7fTZiX>`>WxcojKfzu5fA^NgEB<$UvS|rbD&GZY#qM_+}7{rdDdTF z5m;g*BjN(Y`ReQI5759JaRn7bbWC*?iIQk&@4*a0{LJFq;8&ojA?6aiRkN+YCw*sDXTywmu zeBKARdR+;ESHDApjIkvI5W~nW!geR}-x?_E%o@r}^11xdKfajJy8`ej!O3UcHAXV$ zey^}4FcHO?#{BkXVX>jXjPJ*jxTDhH+^H3|8D_aK$;|A72Db%@@6()|lb+X|mB5b){9{x4hJ7;3c_(v^C`VQpG9w zke{z}!;=!7g@OW^6k89eL_4J1CXzl7*{Wt=eMZmwuI~#TRbGYDu2nRV@r3p_Dgczn z6t>UCm{yvj3fwvh(SF6iRdNbZkOUJD7tzM6zb_P?#S*vu@m+|A-Flw2 ze?vElaxRJhxUGW_`R~?qU*t$K`|^9Yn;cK}sx@@Hqz46=2o|w*F^N zd&j_>{&zo00XHHgfl+UHr306;jzHq5`OoR#^6!)Nx}(|3b-~V`{>YD4t`_81Cj$wu zW`s$-k?`n=gb3u+?^oBL!H#A;$`=i;B8$etB)}eg4MZfOGpTZ9m=G6mIR3)qB<=99 z`NGV|Jojk>fO1>mfSUyut(@ts{%fXA z$=gEIb?fV2A-UplE<)Q~IU%kNVTaFw+^fazuUU*Q`oO4G=<>YHVonxJXp9$=_pH z13w`nYdN`n{FVOKM%cdt0tf)&-(L_B*}~GYS4-)KtWqeNMEAxnxd z2t|oOh_Wx0C1XTJ_J&B=vXc^7!`OFYiDZqkGmOd>X2=r7ANTK&?&ta3_w(HE?pObJ z^Ww}ozjMy-e3$EcUDs7`&1+q0fb_!@^#TMko{+ z`IvCFgeAnpuy(F`Vfu1zCd%vyO%0U?DnnAkp$p_e{-+?)#JJt_P#6c4il}e{4(*cM3j_Z4ou<}c=HQHFvCB(|$9pyal|6mBGsEatrsG&g*HE-U|~^y2BpMb`lfBbLnO#CX@u-37=_o zvqg0A2OwU1cYdnP#5x62BV$|>Qv3@NvtSrrWY4yodUbyak~pkGG?J0K&WV44Eil}> z^hC?Eehbp8hML`LWSNVTdAbP{FOs9&S1F`fpJ$;mlk8?w=$;lIB9SyX>)j$YSQIG} zQG-V;p@q(_I|}BBf%&UjY3$7%z!BtP#=S6ugt7edQJ7y+{?wuU;2tSNS+UrO=7Dda z&WatqHw!OY^PaV`-~w#*R45p=@l^xOOP}nfmI!S3hR^*GsA1 zZoNNW6E4F#3CQlZ%7?ZqFvSk)IJ@?vENsfW7}#23=X$!QL-{JnV}v<59geBpz+%8G z#1v40Ex)Mu?1-QqaLiBZ7BXbZ4$sz zBlxru)$>+xS)Xt5XTLGnu6;U&>Qr4DUay+3A&Lyu0;!gt(RS02LC1mFR;-8m*uK=+XjM z!iH?R{{;U>8_jDVFc8zZfO|lqs<-{x2i@Qt*P5l5a}geM6-^!sjcluJQnzCfmS83m z-|t@FwsdEe)Tix+@mVL1%mN+~&z#Q+&qzk&3TxV^?gqy-V!nl6#^F;k?i{xxH7W#p z(|Sr1MT|(lysyAWAvS@ZB_kFm87M_)mw#F4!g^*ee?GtAiAlDarwuW z&&4f#opS;hxMoy~&r#R~LKFw<-7sI@Jt0BGCH7+LLO4HmGTz$V>1VOD8m$z}&_2ZF?}Vj}HU+L3K&$@x!2fD=J?}Gb*oo1ZMDJ8EJU9vq zkV)C~^hKuLvR%%wOJMq0baw0~@=IYg{yIPMHB_)xjGhWT% zjVrozztQZ-+vbi$CnGe7Cf^XIampwgN_4%PAoC;Ds&hInzb0abN z!<6I)w^&HZ(?AX!dcb)BcgV92`J+d-8jNBqw2wq=f$u!hb;PB=B5>6t#2n#BhQ!8N zXqnYvXOkO2UlA!PC_KLORX?MFL`vtIFTF()6+WBxm0l`3gv2hOq-=m1)_m$MX4_3&7^Q)o0i*EP}lY!SVt1_gP0=H zD4J~@4h26g9SoN`kn`<13p3<3%MP`SE_`%BX`E9z8-VBKU>JN3o>1CtNqY%ZSC%=) z$t)%eS7XqPh_nnwy_D_kKKamiEP!RmbXu>nWL*-k1~u=`&VuH~Nwv|RvH8_Qe0EmZ zbfN1_y&r#JL_cxSy-l({ik0NhKYouccXBcTv%-v3=AMZ+xgaYRY()1>Oic#mYzql=q9=RH4Ha zd?58po1W2z9oO5BgGTY&+{E1AzVy84vJouNq5I2U%O%0Ap!Z3GE{?F(HArJ(M>>A4 zvzBrg9;nKCIx43&b5KM?WY;D|?a(9Re`(OpQ+Zj4mF*jvcDPMvWX&I)IKSS8x0N!V*%SAH!1xQ$cNt|!#M)NSHmMQQ1+<}U*Dkn}^5p~Qaz4%~)Yjh4j>92Cszm04 z5d=4>95#QKE$BIX5ce8xZ|C4pvz$}ZF;wF`)$#g3%EPa;S7-oiW_jYveU`_ORRD{@ zg3)WqUjK`Xf+witAN&H=Z9hjVK}Ss~t*>Ba)C;CFE{_Om1HZ|Lbb%nO~ovF3k( zP5%x#fW6p|oVIsX*Gso2&xUR{rEoE3X5;Z_LtuAyaQIp45vBG<(y~rJ&OsU)+3_;N zG$aFj!2TJd+4lNSY};K5yxvYl!4Ro;cc^>@7l=Q&jG<3*dyHd9dw-T#Ha`L! z#6~O_ly1`_qmxT4J=dl)=EW!71sJOc-IglFdw(yI2FDG23_t4vwu`-}pP0_I>!y$` z+I#o#>GaFoYhQGB&I%wy)&I%KbK2L~$6kADBVFpY*W=0U3xi0jy$AP)b*DP+p=Vzp z6-_)|njWdN@0&kBT6UIr1%b2Z6Wway*>qHIbXVg$ZycHvXE+zzrEn1hpq*m`eHAZ+ zbcj=K5NJ*Y;Q39QZ2o|Vib*CgzqQr*tq9iPBH|ez8jbdMxh^O+K+MOUVfcf=%;J2$@vrwL!yevt=fI(hEMmzuj;I>C@R+0FJ~ zAwGUtis6gxp(0pNl00n0&dx5kxa2BIj#ywdrEdQ&v$Aqc$nT0{&x-qzrrl*X$1A?% zo{k~JF7*elU(Vyq)Z9D&-H+_PN>ZK(d#wkskO=`UkJ;jEcef^= z;%)>!!Oap`^PH1myKN>4;eT3sE2tr2Xd>llH>4M^5ra zk7_NxeM}}!wZ|8g)zm0RX~x|O*N8w#T-CqZG{7)aZvpMxC&v}fOcSN|Pk?q1paR=t`P1bDsJZiRu-W#y1Z3#ymRz6oY7goC;0f}+ zfxxOPnehO{a_Z%q;>lTAc8j0i`emR83so56|2-wE*Z%NC_4RChH(`U^`)-X-S%|=a zjIZ<9=}zoPg(8cF01x!SUt{_|C4Sp=f@~ZIGWOF7U&ceQ+X9Z|y!0I&}lvhy&r z>UYSuKGg@jX+%p1^{qZ#i$S;T`L9F!O%MU{bi~(m30i@~hYDwR98;xcJ^d!$OS$2z z4ekiE@%|Ypg1Ec8>Hq%u=ac&Tkw7Wv@2#<$H2;hHf%awH7R@6*j*jL%JSD)ve2 Date: Mon, 18 Nov 2024 15:36:02 -0500 Subject: [PATCH 3/7] Remove supporting doc artifact --- .../docs/submission-state.png | Bin 7009 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pass-notification-service/docs/submission-state.png diff --git a/pass-notification-service/docs/submission-state.png b/pass-notification-service/docs/submission-state.png deleted file mode 100644 index e4888e4bbcd7554cd8b24fba6e088e4b89ab383a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7009 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 Date: Tue, 19 Nov 2024 15:40:32 -0500 Subject: [PATCH 4/7] Add Guides and License section --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2a942215..0a2a7ec5 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,16 @@ standardized format within PASS. Deposit Services is responsible for the managin submissions to downstream repositories such as PubMed Central and institutional repositories. Notification Services provide alerts and updates to relevant stakeholders based on submission workflows and events. -You can find further documentation and details about the [Data Loaders](https://docs.eclipse-pass.org/developer-documentation/data-loaders), -[Deposit Services](https://docs.eclipse-pass.org/developer-documentation/deposit-service), and [Notification Services](https://docs.eclipse-pass.org/developer-documentation/notification-service) -on the [full documentation site](https://docs.eclipse-pass.org). A full list of all the Eclipse PASS projects can also -be found in the PASS Main repository [README](https://github.com/eclipse-pass/main/blob/main/README.md). +A full list of all the Eclipse PASS projects can be found in the PASS Main repository [README](https://github.com/eclipse-pass/main). +# Guides + +* [Data Loaders](https://docs.eclipse-pass.org/developer-documentation/data-loaders) +* [Deposit Services](https://docs.eclipse-pass.org/developer-documentation/deposit-service) +* [Notification Services](https://docs.eclipse-pass.org/developer-documentation/notification-service) +* [PASS Documentation](https://docs.eclipse-pass.org/) + +# License + +PASS Core is Open Source software released under the [Apache 2.0 license](LICENSE). From 4680fe289d65e61a307df055c917a9be225d999b Mon Sep 17 00:00:00 2001 From: tsande16 Date: Tue, 19 Nov 2024 16:05:57 -0500 Subject: [PATCH 5/7] Add status badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a2a7ec5..af3f4eea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# PASS Support +# PASS Support ![Pass Support](https://github.com/eclipse-pass/pass-support/actions/workflows/snapshot.yml/badge.svg) PASS Support contains ancillary components that assist in the submission process and is composed of the Data Loaders, Notification Services, and Deposit Services. The Data Loaders handle data ingestion from external systems like PubMed From 8a3ed2a8fc519a673edb2ecca21733b4c64842fa Mon Sep 17 00:00:00 2001 From: tsande16 Date: Tue, 19 Nov 2024 16:12:08 -0500 Subject: [PATCH 6/7] Fix text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af3f4eea..67dfbe01 100644 --- a/README.md +++ b/README.md @@ -18,5 +18,5 @@ A full list of all the Eclipse PASS projects can be found in the PASS Main repos # License -PASS Core is Open Source software released under the [Apache 2.0 license](LICENSE). +PASS Support is Open Source software released under the [Apache 2.0 license](LICENSE). From 779e7be9438a01bf0a04299b9c27fb2e8c2c9e94 Mon Sep 17 00:00:00 2001 From: Timothy Sanders Date: Wed, 20 Nov 2024 08:33:50 -0500 Subject: [PATCH 7/7] Modify grant management system --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 67dfbe01..139a4b17 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ PASS Support contains ancillary components that assist in the submission process and is composed of the Data Loaders, Notification Services, and Deposit Services. The Data Loaders handle data ingestion from external systems like PubMed -Central, NIH, FIBI (JHU Grant Management System), transforming grant, journal, and manuscript submission data into a +Central, NIH, Grant Management Systems, transforming grant, journal, and manuscript submission data into a standardized format within PASS. Deposit Services is responsible for the managing, packaging, and transfer of these submissions to downstream repositories such as PubMed Central and institutional repositories. Notification Services provide alerts and updates to relevant stakeholders based on submission workflows and events.