Skip to content

Conversation

@camperko
Copy link
Member

@camperko camperko commented Jul 4, 2025

Description

Refactor services and repositories to work with pagination and return pages.

Implements NAE-2122

Dependencies

No new dependencies were introduced

Third party dependencies

No new dependencies were introduced

Blocking Pull requests

There are no dependencies on other PR

How Has Been This Tested?

Tested manually in application.

Name Tested on
OS Linux Mint 21
Runtime Java 21.0.7
Dependency Manager maven 3.9.9
Framework version Spring Boot 3.4.4
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @...
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides
    • Migration Guides

Summary by CodeRabbit

  • New Features

    • Introduced pagination support for roles, users, authorities, groups, and related queries across the application, enhancing scalability and performance.
    • Added configuration options for backend and frontend pagination sizes.
    • Improved documentation and added detailed API comments for enhanced clarity.
    • Added locale-aware transformation methods for PetriNet references.
    • Enhanced import flexibility with overloaded import methods.
    • Added cache eviction methods for PetriNets.
  • Bug Fixes

    • Corrected pagination metadata in API responses for case and user endpoints.
  • Refactor

    • Simplified and unified retrieval methods to consistently use pagination.
    • Replaced collection-based queries with paginated versions throughout services and repositories.
    • Removed deprecated and unused methods for cleaner APIs.
    • Improved predicate building for user searches scoped by realm.
    • Updated role deletion logic to use paginated user queries for scalability.
    • Refined authority creation logic to use name-based lookup.
    • Consolidated user repository methods to operate on single collections with pagination.
    • Enhanced group and authority services to support paged queries.
    • Updated startup runners and service layers to use paginated queries.
    • Changed default and anonymous role existence checks to single-entity lookups.
    • Modified user and group creation methods to use paginated queries.
    • Removed deprecated methods and streamlined service interfaces.
  • Chores

    • Updated tests to align with new paginated method signatures.
    • Enhanced serialization support for domain classes.
    • Improved internal map instantiations for filter metadata.
    • Commented out dynamic field update in preference item XML.

camperko added 8 commits June 13, 2025 12:07
- Refactor repositories and services to support pagination
- Updated repository and service layer methods to utilize pagination where applicable, improving scalability and performance.
- Replaced unpaged results with pageable implementations across multiple data queries and ensured method signatures reflect these changes.
- Refactor pagination support across repositories and services
- Updated methods to support `Pageable` for paginated data retrieval and processing.
- Replaced bulk-loading calls with paginated queries to improve scalability and performance.
- Refactor co-member search logic for better pagination support
- Replaced outdated co-member retrieval methods with a more efficient approach using predicates for filtering.
- Removed unused methods and redundant code from GroupService and GroupServiceImpl, simplifying the logic.
- Fixed pagination response for WorkflowController where pageSize and pageNumber were flipped
- Fix serialization issue with Case Icon object
- Add comprehensive documentation and pagination to repositories
- Enhanced Javadoc documentation across repositories and services for clarity.
- Added methods supporting pagination in key repositories like UserRepository, AuthorityRepository, ProcessRoleRepository, and GroupRepository.
- Removed unused methods in ElasticPetriNetService and related interfaces for cleaner implementation.
@camperko camperko self-assigned this Jul 4, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 4, 2025

## Walkthrough

This change introduces comprehensive pagination support across user, group, authority, PetriNet, and process role services and repositories. Many methods that previously returned lists or sets now return paginated `Page` results and accept `Pageable` parameters. New configuration properties for pagination are added. Several repository and service interfaces are refactored, and related tests and usages are updated accordingly. Some obsolete or redundant methods are removed, and documentation is improved throughout.

## Changes

| Files/Groups                                                                                          | Change Summary |
|-----------------------------------------------------------------------------------------------------|----------------|
| `.gitignore`                                                                                        | Added `/storage/` to ignore root-level storage directory. |
| `application-engine/.../auth/service/RegistrationService.java`, `.../UserController.java`, `.../impersonation/service/ImpersonationAuthorizationService.java` | Updated user/authority retrieval methods to use paged queries (`Pageable`), replacing list-based logic. |
| `application-engine/.../elastic/domain/ElasticPetriNetRepository.java`, `.../service/ElasticPetriNetService.java`, `.../service/interfaces/IElasticPetriNetService.java` | Removed methods related to URI node ID; added Javadoc; removed `findAllByUriNodeId`. |
| `application-engine/.../importer/service/Importer.java`                                             | Simplified role fetching: replaced list-based retrieval with single-object fetch by import ID. |
| `application-engine/.../petrinet/config/ProcessBeansConfiguration.java`                             | ProcessRoleService bean now injects `RealmService` and `PaginationProperties`. |
| `application-engine/.../petrinet/domain/repositories/PetriNetRepository.java`                       | Removed/added methods for paginated queries; added Javadoc; removed unused queries. |
| `application-engine/.../petrinet/domain/roles/ProcessRoleRepository.java`                           | Major refactor: added pagination, new query methods, Javadoc, and improved composite ID handling. |
| `application-engine/.../petrinet/service/PetriNetService.java`                                      | Methods now support pagination (`Page`/`Pageable`), especially for references and identifier-based queries. |
| `application-engine/.../petrinet/service/ProcessRoleService.java`                                   | Methods now accept/return paged results; deletion logic paginates over realms/users; constructor updated. |
| `application-engine/.../petrinet/service/interfaces/IPetriNetService.java`                          | Added static transform methods, overloads, pagination, cache control, and documentation. |
| `application-engine/.../petrinet/web/PetriNetController.java`                                       | Controller now returns paged results directly from service, preserving pagination metadata. |
| `application-engine/.../startup/runner/AnonymousRoleRunner.java`, `.../DefaultRoleRunner.java`      | Simplified existence checks for roles: switched from set-based to single-object queries. |
| `application-engine/.../startup/runner/DefaultFiltersRunner.java`                                   | Replaced `Map.of` with mutable `HashMap` for filter metadata. |
| `application-engine/.../startup/runner/FunctionsCacheRunner.java`                                   | Explicitly uses `Pageable.unpaged()` for PetriNet retrieval. |
| `application-engine/.../startup/runner/SuperCreatorRunner.java`                                     | Loads all process roles/authorities via paginated loops; injects `PaginationProperties`. |
| `application-engine/.../workflow/service/CaseSearchService.java`                                    | Uses `Pageable.unpaged()` for PetriNet retrieval; added TODO comment. |
| `application-engine/.../workflow/service/ConfigurableMenuService.java`                              | Uses paginated call for global roles retrieval. |
| `application-engine/.../workflow/service/WorkflowService.java`, `.../service/interfaces/IWorkflowService.java` | Removed `decrypt(Case)` method from service and interface. |
| `application-engine/.../workflow/web/WorkflowController.java`                                       | Updated OpenAPI summaries to clarify pagination; fixed metadata construction order. |
| `application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml`              | Commented out action code for updating a field based on URI node ID. |
| `application-engine/src/test/groovy/com/netgrif/application/engine/action/AssignActionTest.groovy`, `.../auth/UserServiceTest.groovy`, `.../petrinet/domain/FunctionsTest.groovy`, `.../petrinet/domain/PetriNetTest.groovy`, `.../service/ProcessRoleServiceTest.java` | Updated tests to use paginated service/repository methods and assertions. |
| `nae-object-library/.../domain/Icon.java`                                                           | Made `Icon` class `Serializable` and added `serialVersionUID`. |
| `nae-spring-core-adapter/.../service/ProcessRoleService.java`                                       | Updated interface methods to use paginated results (`Page`, `Pageable`). |
| `nae-spring-core-adapter/.../utils/PaginationProperties.java`                                       | Added new configuration class for backend/frontend page sizes. |
| `nae-user-ce/.../auth/service/AuthorityServiceImpl.java`                                            | Methods now support pagination; removed redundant permission/role methods. |
| `nae-user-ce/.../auth/service/GroupServiceImpl.java`                                                | Added pagination to group queries; updated logic for default user group; removed unused methods. |
| `nae-user-ce/.../auth/service/UserServiceImpl.java`                                                 | All user queries now paginated and realm-scoped; removed deprecated imports; updated predicate logic. |
| `nae-user-common/.../auth/repository/AuthorityRepository.java`                                      | Methods now return `Optional` and `Page`, removed list-based and prefix search methods, added Javadoc. |
| `nae-user-common/.../auth/repository/GroupRepository.java`                                          | Methods now return paginated results; added Javadoc; updated parameters. |
| `nae-user-common/.../auth/repository/UserRepository.java`                                           | Replaced default methods with explicit paginated, collection-scoped queries; added Javadoc. |
| `nae-user-common/.../auth/service/AuthorityService.java`                                            | Interface now supports pagination, removed permission/role-specific methods, added Javadoc. |
| `nae-user-common/.../auth/service/GroupService.java`                                                | Methods updated for pagination; removed co-member retrieval; added Javadoc. |
| `nae-user-common/.../auth/service/UserService.java`                                                 | Methods updated for pagination and realm scoping; removed overloaded/legacy methods. |
| `nae-user-common/.../auth/web/requestbodies/UserSearchRequestBody.java`                             | Added `realmId` field and JavaDoc comments for all fields. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant Repository

    Client->>Controller: Request paginated resource (e.g., users, roles)
    Controller->>Service: getAll(Pageable pageable)
    Service->>Repository: findAll(Pageable pageable)
    Repository-->>Service: Page<Entity>
    Service-->>Controller: Page<Entity>
    Controller-->>Client: Page<Entity> (with pagination metadata)

Possibly related PRs

  • netgrif/application-engine#318: Removes usage of URI service and UriNode entities, similar to this PR's removal of URI node ID queries and references.

Suggested labels

Large


<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between cb7a59f854feec7b331ba25ad8e39426b7de693d and c1af45df3e830c9f8148bb26dcd51e42d04572c0.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java` (4 hunks)
* `application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy
* application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary>

* GitHub Check: Build

</details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKNxU3bABsvkCiQBHbGlcABpIcVwvOkgAIgBtADkAQQBRMAAmAEYMjIBdSABJZm5otgxcSABlXApsMWx/ekx6VIAzNvgGeHZrNCJ4DGp4fCxByCIbKwBhUNj7bAFmdRp6OUhsREpGNBLKAGt8dGRbSAxHAW2AZgyr8Lb8Bk3pfix/NrQxfApBontKCRdF4tPwkbj4RDqb49ZAEBbccEUSrcfqDYajdAYej+XCNLAo0jY6TeXCIDQwWAkFAlMrsdFYNC0Wj+RBbWGUlCs4IRKgMfYxbBY7YpdLZXIaIyJI7kADukCU3DISgw3Wk4UGDC82FovwiCAotDAKKR8i88AEVB+asgMsoVMGtUU9RiaGQxsq+DaetQDFgmFI5LgdvQ/jORwEXke+11nh8oKCIWQ33lYKVZFVSaw+FwlL4tjJbhCuplrp4lAeFDY9GYmGwaB88hl6gQWBzVLQCLNDHpkDIgIoo3KmgpVJoiHEGD+W1x3BQKq1SnoABlBtgAB6QACyDsg2WOeqp+EVVAnU9k45IzHCACk0BI0LushoAAwaADs+7bfkF4jY4U3d5kJAVwaAAnGBn4cgqaYqvINZDKQFDhCCVS8LqABC+DZsBGgACx4ZBVJtFQbAyt8+yQFIFCQqMEoGEGOA5smTAYJ0lYurQubpqORxfrw+AiGIADkyDjrI0QTNg8BKGa5CIOELG0PUqzoP8XhtGA/iAiQMrhCy+BeFI9AsW0XakjazYHhEzikJUFqYL6yFYugTIxGO5lwlR8BtPIX5tCQ1CNCQImQG0gpiCMQxmrgsjkskeAsNQMSyWEGwYOoTn0A6JBECekURImNrBnUDLOSirLJY89ZeLFkDJEy6iRdVsgKYo7ZReeqAEAZon1LA+5VKMzjTJG2qYvQVQYLIFG2qGzz0HCvqiBRX4sbU5p4JF5LTN8LLgliurYNwtBJcgs1UjWSgREcShSJGx7yo8jh0uIozhM8fBEFJSjyeNkDLLlPZfdJ0h0Qxsa+P4Cbjug8DMLCRxkH6KqjhyJAdF0PSwX9451A0oaejwqJDK9WDI7Qsl/OMX6TDM/wUICDAvITX4dqUXQ9mQAzkHR+jGOAUBKvwXpoAlxBkMoKlMKw7BcLw/DCKI4hSDI8hMEoVCqOoWg6HzJhQO4yCoJgjGEKQ5AnjE0tDlwVByg4TguJA6zq8oWuaNouhgIY/OmAYGgDOIRAYN8JAcAYsSRwYFh1YU4sW0l9AOzWTuE76/rSG4HLp5O7ZMsgD6yvK8D+F8TsorgNAUFgAAGAD047fP0JB1zX11WTXAeNcHodt500SBggBcNaTc648pyAAOLqO38A96GX7sCXVI143VCkG3OqlwQTvUFZA7YdEd3C/vYIQlCLjklK/BtnwzCKN5HOkwjvZrkgp4oPPVJ1NESZ8Nb7AzrBkuiQOi5hLDJC8FXekL8vxKE1M4GBJ8SBrkRCpZMngIxdF7BURqmcDBSh5hHKOBgIBgCMGzLs9IwBc0GC3RAFAGB1xrIMOuQg7xoDrtLOu5BcC5W8nXShT9Ip11oeQQReBYANwBECOuNgcrvzyqMKoMimYaHYfecOkdYjRwgXHc2ksYjJ2cPINOyNSCICzhdEgTF6A1xZDY1IqDl60GgPgfkGAAAUABKNuJZkD3x1J0NyRxniqQJDEBMTtBgXkZCfB8ZoYZRMbJSN4NirSAknBsLY1ELI5lftwFx10PFkmqIqbonRuwNnCKtaq7ca4fRUQzIEGhOhYkgV4dCsgahJWSFiJxhSlEYAACJJXQujXuYY5QagXMCSANcrDNxUAPQUETaA+LbjZZ6FQ/o4jxAXeZizSDAAAKo5L0G3GJNA4mEwfDXFc45TnnM7iOM43hfDJkvNwGKjBKR8htKWI6J0VKLT+RRBpOSyRIFSCUGKGzXgdyOSQNughBLDgYuoSW+V8BUWyZQF+moAp8AICUv6KDBk9mBS8fwLCMDIHCuYugg8qRVN8HCRAgE8W5JDpASMuc+D+FdJCYO7Jv42LxDEe8WoeLzI+ogF5DFIxTlwElIcAL6XHUTu3fwaCrJMB/CfBxlQSVkHpZCLJEL8UBxsTtCo7AfEaEhAALxIPCq5AV6CE0tdRR18AXUbOZVsX5Gdh5CE2MaqC1AHw4gyfWP6SruZ/DhGRCgM1LIPjWaCBwUC/DUFzHqE2D5IQ0ipIkzQ4C6pQKxaMWBUFRBeEQc/ZBqDvjoL4JgrsODIgwiMFAa+OcLHty/MKkmQUkxenJa2mIGDFidqXuIF451/qMlAa8tgtj5lGoGS4txHj4UjsCqGGl2g6VpQHUy4hOjSF+yEd2UmNDJx0Ibow5hJ62EcK4SwHhNj+FtEEZ2YRoxRGPvEaLHMddbQCDrmcygtrHQ+EoOojhWio4x2SPoiWlsk6OBTqYr057LH0Q5Ou2Aih5m2Q6fFJiPwF2IDdbXGDFA4MDgQxQPxpZAmPxCcG3OkBSNyjA6RmjMIQxivWiQIyoUBzMA7oJ6EMUmmM2ReSKwWkRibBquqSoezq5uQ5CyEkJ8a5yZo901RoC2m0A6fCreSsarMo2JqqWbUdg+GQMZyR8mzPNLUZZ6zSLlmgNWc3dZ3jfHt38rgX06A4wmbwQXA5ETAtZpJDU1JCgMBUQ8hyXGAUZO3M88Jl4cIEnv2dhMo94rq66hntTfT0h9pBvnbVQ2PHSAxarqK+UUbQTialVJlgqlbNiF5WV5MmLNYSRK0TUgyXED4EaEzcI5KuzqBqhlrLNXjVHFKzDCsp9ECNdARWyB0Cm1wjgfWxtkVx0FKnZ69ts7sHzp7aQyA/bGW1qpAe3ELJ+B8HgQ2oZt3J1ImnY9rBDAu3xaKqGEBDnz2vHW2gDoSsutw1KJeF62KvSLzfuOXUJGyM1w7dg+Rh2a0kFSLgmKwAHm4GAFRoT6hZB6D0BMGxlHCvxfo4wBtrJ5mMeYwZaIbGJTaN7TegDd7IoPu5vQl9tL333k/cwb9fCfh/tvfSYD8vRH8/EEw2giVWGpAN10Kw6T4CJBsfI8EkId6xQ0WgFDOi0MYYTipYxqd8OfasXOKuHwmbzLN66Q3lv1o29wHb8+jv2PICRg5GI6xGQ6iybee8xuocAIqF9gP5ZPj2lJCQdSf11ABJsaR2gpSGI5/Mj9BgPxLin3txfWQIVPAUHt+2AJmBiZ/BrqHgnDAI8/Cj23F7LxxhD8N1sZw0WQQIM175P0lQZ4oJoFidzM+uhz8YbAGPDvviyD7smaYNgTnDP4MeGBDmid2Ms10moPxJyFFoG3EOco/QHKUCq+A0RjIWA1VDtRBvJZAttet9lMQQ9zcR8rdx9nZ5By97B1oslCgr9kxzg4xvIwxKgHhBRaA79K9icZIbESAOkn9UCiA39NkvB5tQQmZJAXQFAZYdkVsT0IDSCxwYtfBJ9e8osWwk0OQBgpAsBcZdR0CHNeAJN1NEB1tAdnAYh795k/MfAukTkx82oaD1VQR74jIr4jgCNYcLoV0h1iNiCk455R0/tkwlVsFLhZBRgFpKQg0s9tkVVR4gVTo/ovwaUcU40WYOQa5VDOlZANDrctD39/oLCwFdFK0zsbszCqQFDgdm00FwceAnsoc+De0twLDdCcU6AuB7l35gAd84DI8bF2cQj1DNClA39PFn9Do6iSA39wtxhsoKAg8V5yjR9rdbcz4j8XBLla5td70xEFcmEldndVd1df1/12YZcgMJj9cw8ug65jcldej4CBjW9HckN7wa5L1JdyEDAxjZcViGEpi30ZjuFeF5jzjliQMW4S81imEcklM65tjKjcBFMWlndXc4j0N45DFsNHY8M2t8Fa9PsCipAeDQR/J/AUY88a5Cg+io8/imZN5UwhRsYQRkD/AG0VJ79kBiJBsvxB9YD0SbFMTkU+chVyRUJQDKlmo0siIegvA7FFQfjaSa4tNRIbEq5oiN1MAQ4PCYgmx8ka4AABJcNAJ1E/P6GUqjfAJsJoPknwsifgKiH4VyLAEklQwYWgcIqUeo9ZakyoXhcLEEYIo0igsIlohoporJRoCIs0600MLgplV5DHVtZAQkrVOEBZHY3ADU1Ei03kzKSADPB8JgBDCKGtSATxEo8cMMnaeMneeVbxUTGLegvw/Q15Y9QYQnCw5AZMo0lBMMistcKUGUDUm0/M5FbMkENsEuXlfAAYKHIsrABlDOQg15BBAXT/ewAyEveQaCLfBFSkt4i0w/NvTZZyQfNcUQBKNjPJUjPATEJAu1XkUeSU/qYMn4lFPgcMkM3kuiNDKtVIi7OtJfJBQmUHNtTIyHaHWjXIzcfIxs2gYo0nKHZ0v4SzE0yIzxC0s4GxdorAQc7fKks88zEY+ZR4jAOXJ9K419VhW4r9e4zXBYqhUmXXJ9V44faRHzFub4sfGk8zA4tAI4qAD8jdL8n8rIyAenYAC06ou0tQh0t01o9Zf8jYR02gCC+kgXac4fCMuCucBC6XahS4xXG4j9O4n9bCxC/C8RQiw3Yiz4si/o34yi53Gi6oQU7YZQhi+ZX8yifAaSf4XAcSkizxNE2CkissHk8zISqCmAmcxypTeC4zaS8Y5459a49ChSzCpSgRFSlY9S9Yj42RbSjEvSjhI4iXa9U4xC5C8RVC6YkKtXLC8KvykRSK2AzS2RTo7oxAOuQoOKiikiqiwE93EErDBYcEk+Ajf3UqwveZSqmClyki+PewDHM0YJNYeQfM3UXALUkk4owCgSkCkMsC3Aa0xcmori00nixoqg/i7itol5HaCgPaJw34TTKyX0pEE+Cki0tudylsoI+nEYwPDqpdesPMy8Qo5oUVRsYMUYdbeaRAqyL06sUshzbsks2xdzaszxKqy08CqsoUGs1UiG7q8iqGha+sxcxs9al/KmQStubss9RlQgk7K8pBG85Iq7VIh8ltMHB7Z8udGnV7KAeRPQpQiw4ovi6ara80uaq0vuaTfPLojq1EyG3kt7Rm164UqvYoliti0KDi0IoCs0jG5ojm8LMkmTdq4PQWxGnS4W5KshChfK0YdKyYtCjAZXThRSjXPKxYnXFYjHfFIaPCmKpmCqvYaiB2yKJnaEJ1ekWk2q44+qgxRq73CE1qojaxDdGuCjbnWjPqzjIa9uRHWpOMIMuLBTSi5at/eVFTNTBbOQlqFASofxVzAA9c1Sc1IgCSLZG2VSMteJaO+QdA0pZINoIU1aRlLTTkYuiUyycanbCgL6IcRALgYdXYUtMbEWeuooYZAuZyO5ALCMILDANZeFY0UequIGkIM68w+iy8E9elFUfG+4f/KuMa+rPrF0aOkTG8iEVGPeL8O2t2kmAUHJdABoZqHgCENkNkC8iBIm87XiW8oHe8idSmp88ynIt7D7ENJI/q4OQ9ZmEB9I6m8BumxdYBFdIgiOqO6jHnFi6YV0EgdnEyOeX6QoRjakY8ebJ+7G3QvevGvsySn7IKcXEhPWs4g2pC2SoK02jCnKsKrXDh1SluE6quYq524odIigP2iXAOzDLVYOlqv3MOyEgJB+HyPjVU1SBZAcJmVkGwUcy5f0q3CTCU9LRvAKD+aNUcgbGTE2ERmIGufR6IFFRWMQbOmQ3Oo61aFzSLJaZoOMFjF4GsAQ3UB8CuwQONERqengd4eADca6oCbqFaDkNiGGEvLHHZVWg7EkXUMtBzLw5zK6YbKIeQXxlwsuw67+ax9YGmSMAQSJkoVtaJzYXUW0rELpCR1tGgvSMEBtboLJPiHOzYPFIzDOxppEbQh4HwVU5PU0MrDfXcraSAXa/ag6ScLx7OA60ecYVeDczkwodKcQesP1EgJxukou89BaQwsFUKZMQud5SA6uGxw09p2QTpiZqI91G5X3ZaGrXHDkWunTcgYal5qzTi953AbQ1AL5GKQNFlGE4tdmdR3w4x/rCm9+XUcJ+pyGUc1WbJUJ4ubefq9ZkgMAVFJWUKGxaLEyvNbYHMQtUbccMAeprYZoBEAcT4WAH++I6tU9EmlMO8ptCmpB/7Gm57VBwjPta56B/lphmwxB+7UVlB7tNBuHDB44lK/W62/yvXTK+SlXC2h4wRlY7kl/GxT9ViOeOuVTR4aQRAcZTARAW1ToL6IZaR1DPRBq+RnDExRRkNf3EnHRu1s53k8rE2JQNpRqDEHZm13R+1gKOlZ1ueRoekWOtRnoK5ucTUbUUcLU1PKNqKFMRUXEjMYo+ResZgUNm0o5NEUmG148GOuFsCuUCc5UDMHMwYNFF0ZABtBUsN09esUYIgSEK6PHDFrJUYUGZZ3aBrA69Z/O7xulWoZSZiOpfbbR21vR0c0Nougp7jcqUVINXu5tomEiMg3JFHIUyOgcI6c897I4bMfNOwqHZiUYeDUKSMOUIwpdeHIwQmhIxM/llI4Bu7KmpVpiiB2i/IuVqkPd78syoNrd6IWkkCxDxAM5ucx3cIWcwYtvcIZIDh1IUQmyp7RAXMcIM55IBMulGwQUC2bDryoEcIRjWk8IQoFRJ4UzODDfVjyASeG97gWk8LQAJMIEPN30Pt3zNUPxOMPcOsPrAQzMPj98PCPiOrBSPyPIBKPqP0O6PKAGOeqlNmOcleP2OVyuO32ePzNwh+OFtBPrOtOAovBK2HOa2SZIp63KBaM3L+d3NY27WHXE3RgXWU3SYfK0quGTazbZjcqBHtWCqArTW6FcALWXXrW0PAunXgvk23X9KNW2GIuAq9XgqDXQrLa4vcKEu9ckveENiTdTadVY9oRpBrXFO5Pj93W3dPXA7vXmqzF/XlH1aV4cO9jj8+rE8UYQXRqXTzhWXRXf4jGj5MBKhklxbFAZ7mgGoslf9tAS6Yys8WDB7246kUFx2/gSTGTylH5WUF3t6q9QWuloA1sSAAB9YZdGUWKBAANXrGCEVoGee/CyLq/Mwfu7adoA6fGchd4o2ukiB9LBxBPRdGcjcKHG4yXzAILseYHeJYruG5DLbnWCiZBlwWCT4EwIeZwLFNuYINB+J0fzeeVHEDJ76VoC+/xUin+6xqXjJ/CHZ+onyiohogwHh9Ejhn/2cHkKejR/7IYmUPB46aZ64woC55QCV9576FmwXpmwCgXtF8eieBl9ngOjvSL2x8S2Ji1Vrq9QutfJEyJ/V56CkdeWkMBE8fkFO4JyyQNIV8Z556d4Oc8RYv/PZxJ+Z6d+w6WW16Sz17DOWv5+F88QT8F459GF8SjPB/tPlrWr4tdKB+KheoLIOdiVoGQhPfl/j9T68WT4xCF8ikj614khj+iH19T27vyQJFrfygcARCaZBFR/YBdAYCYANEOtqgADE0RqkrJ5evSukXvpJPEAB5Vx6HtX/Xgfu1TNkAipcc9J0edYQUeABMBWNFKehzIbqZV+TfaveZTcId/AJT4YpUgARWCBcGry8FUzoCfip2XKeB3h+JLIhKRQnfHyJrRdyG3ChgOEkyd93OGIHvrqn2x19DaLLSJO/xhCxFLyAHPlgA1JqCtEiwrRVjOhfKQdHOTNAGrYklqlFpaDPJ7lEFe7vcPgJIH7tKlV6RAW+PNQbIeSRpP8T8ItQvszSoHzIpaIZdiu0nBaO9KAqvMPsrxVq80eBOlPgQZVFqSZ78xRJFKxTEEy1Xmb+f3pQED7B8qCofKQUhE1668m+UfTgc80UFR5lBAgigWt3g4pkGctA2Wl0hr7V8q+lEKvvIO4EjcmuwxBwWLXUEiCaB2g5atnydIbU8+XAmTLYN2KBD+BUAeqIuCcGl04B9IDQc3C0E/FxBYLUIp4KT7eCUBGABvhYKpDN8SAQlBIdHna5BCUhrkegPt0eCHdAEx3OMOZQNIxs2uo3Z/jMm1C/Bw4kAXQIcjmoM8IW0QzGuvyOIjCoAtQnQRDz96k8nerPIoXxVkEa9PBPggXmn1mGjCFkOQtwboNMEyDTB5Q5LFUN8QGA5h8yCQJZXoBz9ZAC/dZCvzRRv4Zh+XKXPF0NqRcsqpXPhuVxwqAZTaJrK3LV02JvpAm5Vfzkh1Ob1CncyGf2t1zkZe4fWPuFRgG1hESdogygvmt0R0ITcmY9AfcjNi74ICjouqfEiUBgHoDKAcEQGtYCGZ51wgBpIFkYhsS3YN2cbM5kAKYiblMhpMAANxTJwgWwKiHGksxOCyymfTitiO6agt7SiQUem9w+4sDfuyKcILKNCKTD38Wo5apPDqb1hCgiAaAHUCbLY8yR1DFLFAjNS6hUI0w0ZCqhCiHCN4Spees4wcy+9dRbcZQhc3xraoqspUeZEv2+RNQvArFNDmcwuRjxrknqEWISwpbNZ1QNInFLqCwK+AOUkWWKJKB0iQBVuBpR6k0IixGl/oOTTHIcijEGM7eLwF2CLiViECvQNcN4UrG0KvtGmDuMVPNkWxUhG6SZX3i2LECZ04+RpLpNiPJwLZGEPFLMg5i4L5RZ++/cgpxReEHMcau9GJM7E3LDkVsmMEpgb3cJGxzIq9ddIhiMBMDPulQQscGAdADglIxI9uOTAkjLBly9AdArc0rDUAh6ioyQYgBUShlT23aRMoME8CVA+xDoI4IiwkjNjV+NBKAdLD2K9jp6bJLAFEhEyfAR+aeCuvIEXwsA1AckG0eZHAll0bEXohnjtA7GYptCfo0sBj3jpwhHxVIEgM2G2CxkWACE6Jp4l4QpoKIb4gANSn8KW6BbMnc1x4SRyWI2dAj01+zpQskJsZsWGKGheAFUHIV3rIXWxflvxoRciQhKon5FgevTQvCC3vihgdx3QSoCCEFF0inYF3IwB0mlFX8BhRTGxLtxiAtDs8QBdoQ3ibwxhEEJ46iFJLxARBZAioX6CCEuB+g3ezvN/vSMxBikkERYtIcmER50J6A+2e/pOHwDDJ0I+YjAVPkywGRMkfwS8JcGLFvjgknJAsECT/qJEgOZNEDo+QyLKt4s75aDlYXgaOYqUzg8cdYwmFQ8phNWPqTQ1E7yTSY9YSMTJ1HL5DIeaCfqVkhEbbU3sdFe7m3y6lHCqx0QfIfaXlEw9phvCN/BcOj5WDqhBlJaWRhWnZDjk3UjaYsKVEqjzx6otgXxSGB/hzBlwo6dcKg4ikmhF0kgONJ5GTSbp4LQaTIMGkHTLBjfY6YtPyLnTDka0iaddINFGivAJos0X9w9GVD3pJ06Gd9LCGPIrphDRYV0kHHQ86M6ZaINR2ADEy387OcSSTI+l5Evpi4agXjPWkEyGe446QJOKZiZ1PEZMhsaMD+nBtOZPY6mSwR0nV56Z90nNMoRhk1w/xgsuEZtJ/F/jeZ9YimSHzV6IBJZao6WdjKZkhiFJUUBWTiLZmjjZA2k2PDnw2rwTLZC0z6fdxg4dTE4xRUMaNIjH4yppjPKma8JgmepfZ4WTxCtOjIcIs83iKGRukdlwdii9wqyl6XtIrivEfMimRzO7FTjRZ0kLWW3EDnFi3JYc+2WRkjlOYiiBst2cbOjGEzZAUebiW/lZ7ezVeXE8iPtMgDeyBJQ4mhtnLSG5yvhqVDhkbUCpRdeGcxZSsa0S7gjzWTtFuLZSUydcgSHuUEk1Vwx+tc4hGaEtAz3ZlioE8ACsd0NrhTygQbcdlJSKaaCj8o6wHVH011BAsgpIUmwbdXqRIoFym3TCbDIhltxjx57GvHd3W7kYbEivfQWxi1EUYfAYZWyPIkRLcR5UGfUBejDtDIk/5KwygB/k0boSwQ5kl+RUM2T913CuyIMVowfmGpiQto8IKSMa5DE1Y1UDVJ1NfoYSx+Xo6BeArgWyBPBvo/IqgHeCfAd43GBiVaJ7DjB0pRATKdlP6C5QcoWQrHopALbv0WI48MQDPXQBEARFRAHsIUkVCyQqQpI3KHZ1+BijW02i+wNGARB6KQQZoZYB/HHDNwZABDT1K2BUlHTT2a9fTjjDBCNoxyZYLot8HhiqR9UOyYRf4CUWjxFobEvADxBVSQxCF5kfbOdWbgSMlJ5IAAOrpYHwpQzujvy4yl8sezwLrKQrbwd47F9+OKCPHDFHU6sK8PfL6BYW2I2SxdepJotvaUVbItnI6IgCX4ygLYMKXbvKk7pwd24B7aAqZJnjBZCQ6CwLJgoHrsAm2RhG8U6GDzSL34vQE+RSN76nVPgA4AXBPPskghGQYaGGL4tEWjxUJwIZyNksdzF0X46EoAooCSg69kswEvAFAIWy4AQJlU/9ryzzzAchWCrMDiQNpoqtJWDMh2W1N+ywci5zg8yqILyEc5cA8C8PtII2GmCROZlJipoOlq2RoVyvM4f/LBkYyIZPnIVGMMM77zw5AKuBkCqdmrBGKL5cFUjXZxAKvA8KYaeZWRXaDaVIFOxVcPgruVahwtfOZYRJVBQyVxcknExSpVKCYFSJJmDSoGIMLdGQfDsoSHIYfRwgS4KqBJEjBVJjpkABlUiqOFtdpVBM+hbAplXKqFFdABVTkiVUqrS0lqrFdctj6SVOVe8rEkSoLmAr+VUcxFZSvCE/EwFhq/VVKt9X2tlhMKlXnCsxXMU5Vpql+oqvDXqr2y6qhFUKpfJMrvVYq7iJKrqF6rA1eghBSGth7nDw1Jq40lGvNUxr6wVq9VTavZX2rfO+KpGtyv+Uuq+Vc0EFRSs7Qiq7BqalGOmp9XirpAHgqvsUN2FYBShFqwtWascXKrY1aqstQmsZU6qU1eq7tZ2t0b9qh1g64XjsOF6jr5VxaidZarjVlrK1mM6tXiq5VwVu5WrSrr8KK5yUSu5tMrkax+GgjR5qBceeZnS7wySAvtAEsiNjhes0RfXX3ANwYjcjg2knXqsJTOiAoQVxvR0HeOxXkixCR85ZY3k/obzxA280sgWmRDMj1JQYgUEvRCwKAMyjYysZ+onwStyQp02/g4AXzuYWV6fTSV0ijwNFGN2ojZPqNlqGiImXgM5nRjY1jMZpoWVGg/ncGyApZuAZUWwHhTDkUF3yPBUdLfm+Tz2OC6SQpsumsyYxXzeMbjP/HJg5ZNiHajOwpxrM/gxy4/KcuMKQlM2rZdtHYvvA/BlulU2vDWmXZlw/o5U2/kug3xphM2jkleOW2c5VtFybnekJ5yRAwhlJpNaIKPGfaSUa4XpPjUvzaBR54U+koPJwtSm80i0lTTcV4AoircymoTOMHKlLrQjjuYFC8PQEslst+InLLgLVjOzMxcUgqZzkbHxAWKoy+2AKNFla1XgseE2bwoUT4ClbxgESX6MkkOiQpfq5WkEH1oyGW9SYg8NhQZN0ZWRVJudMMEhRq1cpessaXwKSMQBVI3p3MLVAcrtEDNNmlrV1snk+AeJqtzcfqi6joh8D0hrKdkHvHZGAESNiZJdOfMMml0jwbszSEGN1AYIQsIO6SSDSry/RSRncb4Gbi2CcT3k4WH6vtiB3hiCJpSd7tIVN6UCYdVm7pXCDCQY7FJkOvEJfIRHSiN6fWAIl6AjYXi/omAUYLIHvjDNyt/ohhsTqDSZpztpdDNI9udSHgvQGQBSGCjGrZg406TI7t4u2w4IKwweI/gmDki/R/t/TP4BtuGbThmWVivbT0ClTOav5diOOT4FVk/aMAwAEPvryJ2hIg00aKnSZVB2yT5kf4kYiX3iS6aXkS/CUT4CqVGEHgTwTMC5GfkLKkNSyuXYEz10SY40BpakfxEKn2BjtagaKBCQ+iaRrGIA84LOCUjTDI9c4xMusBPkTsWtTnTxSCDlRYDf6OAt5XVI+WgcwGEHCVrkVtQyKd4RmfGaGxt3B77Ffkr8Y41L20lQQFbSMi/MQ3hbaMPCutgOAbaRaJQPK2BtYXhZ9kfpZcgGSyvRm2rrBaul4C4NX3XSGNncZ1bysX3WaV9HswGaERY07TdQv0DfVWu33uYpammi/cxpsSzSpwviOfQ2uP3tTLmZ+5/SEVZUQzN9Gqh/bpr32myJBdKz/UfoX2/78a/+z9UrK8DcbsWfGoAxUJAPhYwDBm1wQAa41Iz0DMB+fY7L/3oKIDyB6aV02v1zTQZr0w6TirXGlBC87meWefsE3UGQZQm4g9/rgOkqyDro36ewbE0SapNrqJ6aPSPWMHQQzBtbbgYoMv7xNOsyTaPXrmj0eDOO0uFqnl74yK5uorg9QdR0wbudh4Q2fWHJ3VYsk5m6yTEVgOkGEDdwh4SmBi1Li6VSc0mJbuMHEbyZpMcLMOUyUyGkh6QoFq0zYOaa3dcYozE/qQOH7da3wq9ZwxvXcNouhrYeU+qEZ1waub6kinXCG7lUHKBKtRD+pkYojPcRidESHSUYYodyBI08oUfOalgfNdKJgutnJQtBke9AMgD8D8al0du/+VySHNaF15SSdzOMCSRTHx7dQm/DwvlAx6wsKQ/gb7DMahy1BHWFYYJvOKw0JT0eowLLLWp0phkzRjrAtiJvmST8S8URWme1pJptk9oDYuEu8F9XXyXgyZHDnqsONUBmjpMHtdxDDJOi0A5xzkj8ZRg1xsypI6ddEDABoASwC8T43IVvxtUoe9kpdMNsjArpt+yGyoEEgYXIhlNQpacL9EckEsFQWhlSMkrk2WMXdVBNcdEAIbPG/osobYKUIu1/A7kng6AMFLpJkBHAf0UnYW3fmdZl03AOiCoh91R7+sV45tVQsPnh7J9gveAHPUU2qbApghtcdmkIlLsPUJ8Zg+MDLSEn5wgw73lhv2xFaskFpPFpsIj7wlzTUZUCo8d7Wklj6doEFtGstOOLkwpQuiKkMkW+BJT9oCoLeOdCpTV2S0XsIzFHieIBAj7CYEjL+gPQLS3iKSftt+r8LBFIY32VnPLqV1nIcZHwzdkTN/R89WYL0OadLofQMsNANcOWgMDUaRjAqOjqEx04IobTlEY5sCl1Ce8P4oFN07kiya7ZUoIIQQH/hkl/A7Ty6l4Fk27BBo+x2xgmgYG93KBfdx1Gox1WHKIC/SfgLoPmkm1ZJSRoe8IJcErjbAITfqHsOuaRDLYMAyMe8VE1Mindk9LOBSJyxMIIQMmA5lHs5P6OPDpe2ODEPtjqRHhXllenlteTwECsgGdehqcg0b2/LciqQoxMsacEaDdVTx1Y3SnWNuJgTTMWaj8XmoWqp1lq+mfBaTiIXQhNcI418cihYXRwcJjC4/3HM4WkaeFmAHCYLY8hjjpMfC2WoPWcC3sxFlAsMChxkX/jgJ2gNRfYvoWPFmFhi6BV4ThAKLDufKGhcUtvRIAolmWhca4uqrCLBlTQ6IG0N6zBVELC0kR3YBL88A0se0FDwtL2Ul6eAZ/HlkgBrhmAXgSftEHCB8VCSAULYBycVDbrI12wD6EReLGon8A6JpC51WsshlTLFQcy1FhYBWW0ENlg5iBIcu7AnLLltyyQD55V9fLYqWkz5c5P+Wi1gVnJMFcSlUQ0TaQsi8ZeivEc4rllihq2mSt2XfitQRy85dcv9GcrQ6vK6CAKskA8rxV8dWYIAjcBPDmNDy14ePGZy+LxYsi67PDG5DqV9gQCIxZ0rOUka5VoQRLX2NR5IVNluFdtfx2KBkLuF2yIdbzVhrthpQ+mdMADHKEYOzM1wcyt/lBr0VoanNQmuTUrXUV71snhipzVSGKhx1iK7vuOEFDFeQfUohrIzmg2yLoFWyDbltDjhPBaKgG59eDV3WHrrUptWHHAMorOcpu76/Ot+tE26Vd+zGXNeqss0zj/RqoOeBoDMAJxPYyFVlfrlv70lfFDgZDKgD3WGGj111f4GevLXRVi6yFdRbozGqd1pVvdQRfjVtxhpP1sW76qXWZrZVY63dWYMnXcWIT2V+g+DJBsGV+bucE6z/qBUi23jqtiW+OazWnDMbyvYa1ra0vlqZ1it8g1bd7Vq2A16Np3oDeDVO3Zb2t/dXreBuBZsbAt3G4vstsoWvbNtzNausT43Wq+gdkbSWp1vaWFbmqj27HbTXx2fbTCgdcnaHWp2uULtni/rcpuMHqbO106wTdztdr87Dp9QpCnxlS2I1JVtO3Ld1s6Wa7Zts67wPHNN3uI/tx25AGLtbqC1Mtru8Hfltu2+7YNligpYLbUX01y9747behuPINZvCRAJnVLvRqM7rt3i40JpvCDd9IljkmJfHPprL7FxyW1vYZzr2qLN9iSypbpTl29b8N2m4IdFsdrxbZS2AOtfirz5+ojeCbAqYPslqq7FQz+73dPu13nBi1xSX/aqJ6HgZR1gyvxbIsxzOj4ZjpPgyWj8asH81n+7g7DNdBcAhDykMA5sTzVv759xGzYmX6+zNrOlO2XVFIfn321aD2yGbrzMCzvZ7OJLlfoYe7Xwbr13AI/Ymu/BhHIZTOmI7rs1xyHXpS69MOkil2E0AVigIo+cHkOSoVHZ+NI8MeRR2cHCm7AZyYsiPoaC9si0YMxrpqnEZ3C0tmuDWIBx+0mVx8r0QD05pHsN0wbNYQf929rb+qHuJaRs2IPHLAfBkjr4pTmeK1wuIz3KfV9ziuPDbKkPKtoJGMjWRlLpBla4/FhcrGGebIzKNglF5/XZef7nl60qfKFpIp6LjTZBIM2CdRlBozlA7aDMtonMl9uebDpzMvKNALIEQxMiPGGmfOjKHSz9wT6WSB3v/NFYjqrI6y3pw+DChxha6kzrczoTbBYAZQVABEDEHGCFw8xghmJXyP6irO4mISUJQoANSEwXUA4fJjBtdhX9imeG6SV1h22qnW5eBXmv06coGl6W5k4fqgvU0YKe957NLMM2kIxUskoe4UoyCjQFKdQbso6pM6AhRn8kPZv6OSdDCTHFwfulzMORjT67is9WPVa8CWwoFQ4h4ySkkucAKmF6UZIFgclOc0hLqb7Dgpdr3hZmxUFL0kV+AIA3PZd1lduFkBQD/N7QpgzuiHE4awp86j7SgE2CDSvgKQK22Q2S8qE/A7m7LMK9Fk2cL4vAJYc8KK8FeS7fAIruEA8/wCzjlDOwO3XQWlCaMWX62xbTEC6dYnl4YgdbFk3+dKZYxWpwmHs7ZgEs1nvgWukc/QVnPS61r66MK4WwVBuWp2V5TA3eWkaoL4HUgU3sgbStl5MDGDiDlAaNSYLMOH9hgzXT5FI65NtuI7O7L71LmLDK9AV17l/D9W96wEY+uyeXEVUSII6HXBKgWw64fSFnWzpNm0cMAFsEp6UfnkKNKnFif3C86MJfhlCP1UFMtHfFWROz3ELeu1BHebb+IcbPwKOXcZu9xnHdElyY2aCivCY5Wlphag4MfNH5vyZaIc8leiui6srsABmIZO/D5XTzqhS8+02WbvRg0g+UcAvdwkctJLMjf9OcY/O/oS0PkEbC9C1ZkAn7jMQ5gcACAtgyuyoHFrhBKpN3+OTfMHjm24KiUeG2lPW/xrLaxeNILjF1i3coxn3/yLJo+IJa5n+ZrYI4Ox+d28ufnSb6qYBzAtpvEyRAr5RDh+XNSCEk7RtycUvUgjUnt69JwCMycVcQRGR8xb2+4D9u9OFAOuBJrcudZx3k74ox6z/U9cANFToDVU+UZGFt9/wMU48E44OmjMY1jQJ6E8QaBvPQPSyDXCLgAAJV0LADGvAA9Anidz55+88aAws8FJOnQXqTmMkoMTkgEZ8QVKkkvNAaAK6H2Bpe1y+5EpZukFAVKq8tH9AKjlkUdxpnlAOioi5VSjLsFB7bjG2CDQXdXkre/lThLtQ7JAiJhbgEY1pT0NTbIor6ivn9PmLcEPYf3dlrGCsA8AyWGsLOEy+zM7+HYDz20DA+qRmA837XjXCC9kcxrIxRqMcxdQkie6OWUel2itClJr4irvgM+1agBmDIH7VUuEE+R7VkwvHqmKo2acXo/22AlN7VIIFifPlDerN7BZk9EIknCnpYokd1bKeUjD6tI126K49uZwunid5QAM/KGMOenqdxZ9RHlHANmIuzy5iXcchjXRHuZcx968phmBOaA93ayPcSQfQYKb0t/1PcsiseEH5gtOENS4tfqDOwzM9PajGQ2fWUN93z4/eG1v3IIT9zC1qi1kO6bz+QHzv/OiSqQuhonoRKRNvjF8YKZD6fGknuvrGqAdD+8jK+QSGPVPi8Mx8Q8UQ+z3hrjzrrm5swOW0WabPx+aztl3ER0TD4sBw/BAdk+HwwoKhoA4xOUl2en9plN8oesT+AF4NT07O0MNxvZU28BeTegW/qte9N0W+gvg/pPhCVdKvN4yjf/o6bTVxQ1pAVBeFzR0dmjGI+tMSoJXsjLT5rgSbcfmPtcu5X3IPKOslAUJlNDFYvs+AGb73wW7k+at2GKT1t3epi78NgRsPzT2j77cDusf4/cKM/GoenM8fZnrrgT7KcLzfWc7qEkbuqVBlrHulGqgfp0Jx0WncIfpXuN6WCHAsGgQZXQHhSlhC0WCocGLv9C6g+zWb0WIZ4TAkIAq6XoFZQKtTNEgDSRE2Hf8HtM9nXo6oNoR2Qi6IOWhhSYU+ipByAONhZwT4O9yEJYOQjSGUqhMr0RwUcfyEq9+MdbStx5qAuEqxz6NYAqwqQS4B8kKoTNhrhuwJaF9ouAykAtIN/FUGfgXkW71vh2yTslFYIBZ71MhNGNAKvI/vF5Sz9LsYH1PRxPMHyk83ySH2OxofafwSMlPZI0HlYuRfxtpUfZwHR81/fTyqAjoWDDD9vgEz0Qw9/WeX/UifazxJ8S/QdDjp5AagNA04RCjV+UenVFg6NjgEdGa8csKwJntJKCkksDjwaYBsCKAOwO78a1Inie87xHyVO0VIU0yphNTb5nbJGQYrV8A94UYDUQigLAExd+oCkmW8ogygEYx4UGWWcgKSacA6Q27GoIsJCXK6H8M2QMF3kQMA851Uh6mPkCFgIkJ7SIgFBULSn1ALCLWkBNvMphg8wNODz4IdeX6giRkIYfkcBvAYYEu1LwAPDAsPoDvDQ5mfF4D58fwf/HhJxtHMkZ92AsrzANBmMZ2QBimc/yOB2NbAyd1WTAJgF8CglGDohx+O5kvprQFFlp1fAVnwYZHfSCRXhADcLEgCH/VBFWw9xAgM0kMDV/3gCfERakAJMsLziwCCJFAkFQZMabFrpLgCsBZQw/AlmnBLzBwGmFZlW3wYBGwSyCqFskZuC9MT2NpElEr7MykW0POafTRDJgzuiDl+WdyjhB8XVGBYC7tAYMF0TmDd1D1toYzX2hn5ERjrM5TDECgpDlZwmG5WZTeHq5INHMhWk6IKBjzdFCZdFHYwLOLUJhpwD+FqV+vYhQQBosAnBK0OguAOICXQXV05ZBPavVTcc/EH3r1i3Avw0C+bVzTxg29L1EqCmMWIPiC24LvX81VIIuEZDfATzQukx9dkImC3QVkNGBx9WfRzcVGduEFs8bP+GH86oKwEKARROpCMJdQzokLY4QZQgGo3zBE20DCueH30CMnQwIioAqbiWkCZQMRhbgUvFRFAdv1JERKMD/GdwqMl5edzs82nO/0r8IPOnWtM5qeYMK9gid5GgAN8Fv37IOfNSQmd0sHlFSVKkGJnE5VWLVzTECXPVDJ9qoBxkv9faG/178BRRMIwB/3LVBecrgoeH517gsykY41EdfSOk3/O0NCxvEa1CodLOCoA40CkaELw0MAvIIU4fiM6HTQeyd8INtRfa/kWYNgis16A8mZAOgAl+YZCX4UAwui/9ixICNGB0QnALtY8AwmFhDbQzNChhggccDIC2nCgLRx2nKyDDdGWD0BLMQyI2FJIqWSkBJFVwo4HOCjYAJxzJ1wlp0K8w3MAErNKgQBwz8hPXAWz9lAwtxFZvlcVgh8pWNMNlYhbBBndD8/dQJEwy3JQEn9m3GfySMB5OsIX8GwvXCbDP2VsLrgk2V1kCwPyc4C7DNEX9WBJLPZwOP8bPQcIxQkTL1G+AiAR1DQhJwYiFHpuJDQGBQ0AQKPq4NAdGT6pNQ4oJn5K3CjHvAJeBej40onZgHHw/dOpAv9WZX2hCJUDesCIM+qS5nqQuIkNnToCDHjXQN0ZN8OXpYvMrxHD0cfKVh924R/3WxelYiKI1KbRAO2B0XNJD6xgIrFjjRoRHplkN0QzXQTD2oigAW5i6J0MB8RPV0JUDQfD0PUj8EBSKXcwLAtzSJiBSTzkjS3dBi0iL1HQMU9Z/FT3bc1PIwLwoViEyNVIzIuJXIhmw2yJdx7IueSDp+wk/xXkz/BLVEAXAb5F5k6TZ4BS99eDSV9cgiK6NTQboiSigpqo/ImGj1sVlAcZ4ED6NwB/jFWR+iCGZEOx49MfAThirYAhgMIb4fNGWixAroGWwPvPgC+83vf+DfYWMF7zlBNI/029Bbg7yDaAxI50KB8ILXPxkiNo7Imzd59UykTVO0FLwFY4Yr6KDQkYrYFxURKIGP2AQYiDR2ZqwlCgR8DAwyJHljI66NMiJ5OuHFjJY6eTy4qwltz0j/hI6PrDFYp9HOiWw1WLyMKqdWM/ZbouqmndHo4n1Dpqje6g1pCgC2NVId2DjAr8puQvlPpFjdCLoAyWTcmUJRPAdmchJ2NKB+oRGS7mZIOYafkuxcdAywjoWKUS1vso0VXnidtqHQi/JkIIBFiwusOvD9i+/eXjwYCGdNRS9RLe60soZVGB0CwprMkIIYm5NmivttqZFx9MNmcOjB4+Y2GOCkpHPmOFiNVfSUcEAY/00djV0FZlnZTNVuKatTqL1FEs4hP6ijQ+fFED5BHtIun+piWYPBnhpfdsn5QESX1X7IRA/NDChBAzHWTB7DaBmpjGYqaMkiWYt0IzdZIjmPkjyBEIXyIg4kWyTjIVf41Ti649uTzjPUPAGzIsmS/lRIXYmUHrVVBRB3AtrsUYBFsUvEuIIYy40jCBA6MKuKZdqga2S/ia4gAMbjv4jyS35+AP+OeZAE52OVjXY89QZpBBM2wgShkYog7j3oruMFjYOLYF+jZ4whOASdaVhniN9o3WLbd5/IESMijY4hJbD8nYBIad7A7sPM8HIwn3KdnI1wOzgYSdeS/AqgEsBNV9PUMTIBkgXMOvxeWI/2u8N3bb03kKxJUHBAHQF+EajtyHUFN5sNPVDpMxw/IOchAHDZTxc3XWXg5AqIsQEQd2tbNiUAuAWyEsY4weJ1+hA6bBHid/gUB1LpopFwGGQqgJcBiYf+U3nCBAk7PDpN7EjEHKJAHeJMwwgkpJKJRosDEFTMspKMh8TgI/xN+oTMckFslClRSQnjpFNzVHg2/JFFoB7+GSDCjm4WryCi4vM+kClzFJm3aFevVry2MaJGdjcSQWRABLBDFOCO+ANYHdxZDSARIAuB0vG0giQqgE5iU1Ro0pCXD3eKpUGDzgZgEuA+AIuia83qWiJLgdlH/16ALJEUJdRCIf4EUgRRYcj4gLk+0ATD2AmWmohzJOoNsV2sbZN2TrkpwmQgzQYOGLBzvRiVQQlYK2B9CV2PgBg4KIjOHK9KA7LAQ14BfUmckgo1GKygbFKkAC9kgaJOvAqgJfkSAs0I7Eql9448w7ICY3sCJi+MFoEphSYiswpjmw2/w9iL4xQMAZIE2aNUjM3BaL+VqNPgzdUD6BhgEBNyUUkl1PCFtQ9VO0epMaSS8YABS8WbKcXTV/MNlSOlyha+1TldGZIAqgdk0XGlTi4oIOKlRcUWPcxhE8mPrE1yQABQCAVTsRpSVRKGQa3fsLhBYgSeDocCwghluxh0Rm0vBwgGrViAv9blMjk+U0203E3kuKRFTOpVtWwQJUtqAjEZU4WTlSQk/fAyBUOWJKuVpCcxKSgw7FBPqTZUtVI1SF6CgG1StgMxxzT9UjlRrUa4I1Ke9WMNuHNTulGUmtTU2bRN8gjgB1IyTEkoNHsTSRcJPE0okmJNTSaAT1KcTvUuw2UihvIZQFSg04VPyh3VHmPDSQsSVKjSCGLNIJlAHRokqZ2w7JIPxAgMiNwB1U+nDjTfQTCFoB86D8n7pUvJ0woA602pJvxOLKCJANlUxdMQB1UrYE1TKAfNIJkhUPVMcUmcJeHqjBMOByztxgTlXLT4MRp0gBq0mDVrSr0yKFtTmqe1MdSLYTJLbT10hFFSSkMoKLQF+0tILoBB0kg2HS0/UdMFSJ3CdIxAp0udUJA5019MXT2cQB1TMIvDsBkdJwcIGJkqM9dIPT86ZBPcs6oSRG/SewX9PMEVUrmWkBH0j9LzSYE3VOfTZ7Hu3/TIKUtKAyWMEDLAyqFCDN5ZoMxeVgyW0+12+wkM3JIf5usFVHQzJ9LDJ9So7dqTwzk8AjODTJ00VOnSocCNJkgKMmNIlVFDT2lzVphEzHriNqS/zvSHMwTKLSX00TPfTxM9NOsEAMmTIESREs1ItT5kK1MgzRgFTN9Y1M8yT8SXU36nLMgXRgDD80Y/rS9TtIjhNh89AqLn0gexcqkv9yqCYiNA0OFrmkI9VBfiZsNATq2tjew22JcDQ6A5g7hgAcxwxB1oZRIABeWIFshYgGMQjAowKZJrgmaF7h+hcAF7ldJN4HrGl12ANLB9i1FW7Bec0syGJGoAgq9xOQbAQoDDAroN8UBA7kKKgYA10mqnZpVqBol7jGNMpjRiFAPajHjn5EOCuhYQhpB+BMos2QuyBKRjXL0YNB8D0TDcBBODxPNUulWhGgJEktIXMF2GqhWmPdk3AcmX0AriSAOJWbBpgUHPYBVqTxCZp3uccHCJwgR7I1UIpFgJIAgIH+LwT0UO8PRg4Ulo3HIkAQLC6xD056WwR15NvzGyJsqbJ+A+4ZkLQFrFPVFRydkPHKCDHgBUxUgBXDkDCRgknPXRC+smxHmAusxCFfolte9hxiSU8QNfYK0ymLTDqYiILvCtgajiZTiaaaKki1oiT2zCyBbUMHRmY1lOkj1ok3IlYrNEBC1zUAbExyzknXQMi53IOuE0UcUWQB4TO3DTxWIOs02kfSrCEx1GA5w8iM9yJAWQAayJEw/1ncXI0/1HBN6QD1rgg84OBDyMAMPP/Ei6EcMzZ15d7QKjWZPgVaQxNMQ1VFo/VgWCBCebCS25WTYZQXoGvYAiu4fIAlkGChdE+CfBRnTnwnjqJZAGhizvfkVxM0g/KAFN8UKMmHJ18KEN3FAIrdMzB1sPyGOTtMcJUWChUVpnKjPQJZP9QsgT/TVde8yiIq9zIagJRY+hUplYjRwgX1JEhfHNBF9kAWIEZBlgDABe5aUeYBBBb82gHvyXuHXKcITEeYAly4I9yB2FruM8xoBhTQsk3paff/Ie8s2BcFCYKoCLTE90UrlBCh+olP1PRTMucwUD9cq+MtyjctQM2iNAov2dyYfGSj0j3ciPO9zUjLJz9yAqQTGgwTOczEzyA4A+Ejzo8h6N65msqow5B/8/PKDJGkYqKgMxxVmU6UbSXgtOyxNHpBoBWebdCGQnREgHGR8QvxGDBQwg0yuhC0CpMLYX/evJDAxlRN07zlwtkj6TQaKzT7zgcrUhHzckQORloryJnTeQfAZLHACKgAszl9NGNsGwlQwYwpFyfYswtCka8uvJWR3wz/y6wcwEuGaBTknQtaxEcd4B8M5FdeUK8MwxfSMYggEuAJYNCuDzMKxQi8NpSDIBzHfS4ClQIQLencsz1MUCkdL+8AfZlPwFr4tlNvj2YmsUIwCCgchhIy/VxONRN6ZQne1cc7CCUDKiq3ONympWjEIK9ovLLdyQgD3KYLyCpH0oKl/MEVfUUuSEVYQBAnTgYKyClgqcCpEjEXtjOCpPNLSFi5+EzymnNJXbg88ihRgYScJ8NAQ/rLxzJ4FwkpJ8Ki0UQCcItC7BRSLF6SqM29SgucHuFYfdrQ7h3IMQ0OxC8HYsignEJmENkn3GuF+KdIKPE8FtwVkF+BqNYEtQUoMgqBhg2vcIsojaAbZXhS3tOpEdk4QMMPhdBgdY3pBwgM0H5A8NO8wihZJHshg11ldRMKAN6GGHALN6SAqJMskFBBBLR4HIqbRF8Wkyz0ffM0JQLqPPskmjyiyhPqk8/DlLwL6aRXLxiui7ApPjlInotwL74raLVYdo7WN0iawuuFIKxin3OR8qC6rjHlZi+rgKckaJYrGKVixyLWLKjYDU2KUSyt3chPBX4DqcQyPYp0Iu9SIopZYyNp2nDjw+pX9Vm7QuyHVriqFIHI6kcfOULDlYPR9MaeJEAudQi1KGeKKokLD/D2UJvPkB4XcKTvARgZ3gYhenGKEVBO6UxMoTu2HOwXVVbKLV1TcioPT+CJUR4R6xcaNAvCAvIZvLgiYXbdxBBmTE+D4ibMuantMIFEUswK5S8mjmi1IqUsWiZSmEgtyRy9lLvjaiu3NMI6sR3PpiBimWIyoX0d3PljeEw2PERcnMyI716CkIHx8Y8vsLtiOCxPPtLDCmNgyjDy1MkJ1jDW3QRStUD1xlFkVcI2zIgPNODVkm0ZMluotRV3RpSa4dwygywTdLAg8YwPYOhFI4ipGjijqbgoeDCo8DWnkwQkcX4K3mYGS+ylqEQ2UMxDNLWDB8ovEsjKwXBEP8KPSbQtSgQjZ3V/sPZCI0DcExTj11zp2O7JM1MJI6i5KapVfBiSu8tWHF8lnUUK/LzdND00Z7fKyCFc40L5O2AHyav3MgDsn+VwA3EUJTNw3zYhwRQolN0VpkL+KHiAQpTQMiOAww752rYlTLJgdFdQf4wcw4tFsk3pyUJWCQRcaEeheky/WsqeYCyxUP6stUdit+1gwRF2+QQgp8pUg6SvXP/osCmcuqKbciH3qK3A4EH3ykcXyCTyXMYsKepCzJ10vE1GbCSH9zKT5AlLx/RUoGKhgUllpkwAM0HsgXAfuT1i9SyYuMC9cK40yMjSuriVxCgFiGPLWCqz2kSNillFLSGq2LIZTfvPzRLQ1USIIH8TvEZXxFC8OKHmQckBUy8BPBE5HQIOci4x0Ig5WAPsAm87BD5Q/gKVG5AZTXVAmqhq0eGSVJArwGxi7vRSLAt3KTzV+hqk30O+BfoZMD9M9Q47H+8q9S+OHLxStmLCrpPPmxrVC5UNLFSgkmtU6qMAd22sz1QgGqr9lKwykc0zQb2k0KdmaWA0BYuLQA4YNACYg89V+MkFycQo2lA0AAatuEgA3sdS1lk0Ie8HD8uk7BEjCt4qcEGqpqqvhmqr8brN0AsgXCGfBsgLIGfArgN8GfAAAVgAA2bIG5rnwN8AAAOJcCFES009Rxr4tOGoRrEKZGueJUatFHRqjSzGpPRsaliCSp2E04jyqwAQ7ExowAEflJZvK0RjSdEfDt31Kpi6gpOgfK/Tx1rfgGqpmL9ym8pqoHA0p1PL2C20qHiC8DWgPKINbPI9jAxDV3Q0t5J8Sw1KKv4HgCnfJs1/L34Y8hd1DNYSSbF8ZHoKLhQrcKy7K0sq+RIjwlFkzKRHRKNBdE3ymIyZ0QXeTUVNX5CFyQCmSGCpu4qlKZk/Zodb+SXR8orJlDqCbcI1FZ5DGisDEodC1ALrYPQhh6D4Xc804A5K6zAE0S8zmy54x6tCtENVDf8inrIbdCqE1J61CoKE/wm0iyjCDXFgDQK3COUVL7yqhXOVR+edmN5PEgUN8K6SMwqOrRAw+Oo440IwlVz32elLv8viqzSmV4NdAqqkmYg3O6KcC+aPHKuU4zNJUp06Iz7r5U4myBre62YL9Vt003XYyNVDohXMvax2u8oh0vGwtTLbfAzQqr9Dm2h4SbDTSQNFDbBqelObILPgaxgRBuVDP1etV9TcMqzOAqBZYQ2nqcK2eo2oRfPBqENMGhepnrpNCQxek4GoSkATvalBpwy0GqdLCMCGh92h4DDD5nYaFDSRvf1J46HlIaBGihpmC4RahsAa3VKzJAaoG5A3pUPbThoVTgDKtQQbh4tRpNkNG3etEarM8RtAaL9bKN40t62RsYaChBxrKjFU6Q1MbPayhr7q2Eptz9gtam2snA9a0OChNLao2rliDI7cvSN/c8Jqx8gmogDrhNoOgmtYLw5MNBhnam2LYLWqpRmSAT2YhksjR4fiBn0XgdyhF87EUYLZDxgmOkpSZAInPIa4NIMy1yMZJePaxOAlgHhr+GRGqfVZa+XC0A4mqRgSa3/cQDoJlJH0BrVjYQjPFJ+8g8mlILI0LiRKbSOZuy5CmqppKbOlWEOuDOgDcH88umlGtD0NSMgGWQICOEDwlOjKs0oBC2ApoWaMQYpo5DFuXSrlDLwooEqA1oOhmPZsoOXPOriiPoPu0kUDfLpJ16gcG69aAf5uWTzQrZx1QHEHZHuT2sIXVlDfmoWBBAySEFqeaCU+4zHJyQCTVbNpUegM0y5dVmufAN3RFrKgMikEAyAiWk02Bab+J5oRwa1AI2VUdk9xBdFpSf4wXILMzrKOBHI52EspRcZg3D8XnWjQudkAHxPxQnFI8wvYEoDYxu46WoVEKqTGXwDckPNK+3lbj4NyTdAYBEGBTAjtH4ENlZQviEaBu8QsztcNqlSJa8dw9ZsHKgql6sgsJSuctNy8xcygdU0muMJqag5WGo6bpapGpRrDaxDCGbkmzpX3JhhUYXU4XyT5u2AgcmuBJbQW5uABaegy/MqBTWyAEJaJQW4VDbO0cNr4BI2lFpv4wWl1HjaTWjUV3BXwXaK1q09Z2mNqty33PNq9cGgtVjnMlnFpIYlJqtWKG0gcITz5kBtrToSKaNx793Ynqvbgh6tFo6JzIGxOp1XkR4OuLiXIMVZdNBLttZxaK7ILuQWKedouRlgjkuSLwo8upYkPzaIH8UJdFvCSFclTDNE0oDeELtV8lCdtsgl+QMIsZxDKgnCwe86zRLFZ6H4LxYRfAN2yD1gSSVhJKdJSCxBluOSpvaYgu9stxKwJAGF4wS69tvakoXkQ2VnIQUB+o2RZ4N7B5XeiM/lQQsTR5l7HWR0fa9JaDWlMdsYurQVnilZIcU+AMjzU1S636VXaNSVlHRDrDdvATCT2pjWeFpIQwVKIhHLFTw7bECZRhI3650DRah2kECt9kWFxMnpMvfKDi11gAPVhCMQEXxd9KoX32FM/2T+ueqWUkKrtaaisgRobrGn6uBqV2+uj0bZ1bVWORV2i/XPbDbcOzFqRKedqbb2XVBpP0SMpinnbIVYDoyzVeTOWztga1zug6QOpKDUM2AA1M7b66eztKAsZHegoEw0qHF86bEdztA7KAZYFhLRgTzuC6a4OzvMwznWA25jzKWLtwB4u2DtHJUumzvcwMuntoc6uY8hOi7mKUonM7aVMDqS7heFSpCzT1MrqUwsuyrqi7fqqHEM6cGGKDAbHG3+F5xOVNrqBAOu3g2+rnZbrpq7Hkczozpq8Pxy8M4bIGtIyaOozsUNsOmGyW7q8ZRpK6Quvru8x2uhzu0Cy2nJD1rjaMqooL1PGtqfQ6299UaV7OcrtKAW2q0rbbnohd347kgwTsHrMTP6A8CI60eC+9GGExioBfTLDS9QHusLtiUJ2ypqTDXWyLX7ZO6TtlBTM2fkOdghQ0lrhbRQ65rdYd6sHnm7OlWTWI6DkBJPmR6Gi3RD5F2nTXkNKer0WW97KEax477uab0GwMg+EnLNTQhLC0ZXdCLFYiiQ3LUGCjQ/ivIB3oculpar2mxAk1GMB7oZ6tbJnrIwwDB8DuDGO6pRbq7kHnqWqdtSMCPBLE04JzAb2IgH6gOegTn3oRmrHkswSegTmXQQmOCJ2CzUS5su9kwfXtVJWXRdKlBcAL4IIIES0EolcttR5Jp4sQKQlw11sxwRqdybHaA/Idk/FEMZnDMgk6NcEQkhawgiCYWrwQy4dJZ6ZMNXvAMHumMThAs+r500Ec+ozWYqpQsfkAUbEB7uaVWlSgHaV/8TpQz7seZIvJ76MogFz6dsAzIqachSntZEQ3YvTpYPk2thiBOevjugZyQzfD3EHPT9x20GK0eBdc9zJxKx0mdJkCeaoTGEytVxA/bGN67OcU3rBAqmqW/r5S0cslKVSr0Im7aG/TtW7gAHPo26Fu+WX8db9DxqNtvOy/uv6Ce/hy48W+kwQf7jG49Ra6RKSHsy6Kus/r06pu4Goe70su9tl6g7NLoAGnupSSTIEq8N1JTs8AMRMMnmvOWAGnOqzPMpwB2yCl6ckGXrIY5evbprhYBo7vC6EBnckLY4tAisfKO+/kowHuUnLqYo7+rw1pUI+4qXxQoBmez8EZMTlTIGxuoAd06sBi/uFVSiV/veyFu5vvv6TOpNRyEJBk4VJlvyyKE/7NZXbpPV/+gTih6Iu4lREHQB8ymkG2BivpN6WlNpRYQ6Cd/vVk2BgTgUcVu0zt+kNZBpRMHq+igFr6LBwwYccJgGwZ26b0kxukzT1AQe5ljujWqMBTuygHO7Sq7hKu6Toqrlu7JEMyJY5AB57sybGs7JvWLzytMKJEz6muESG4By6kSDtyRpvV00WsjwrZtalavclzdHKXpFdQMfvYBkcVDQFxyzMdrm1rGeCGbg1UVEqCJYejAHSbOlS4DsZ2tLtmaAEOubkCU1c1vJOZZQnbXO06IAAGkSAUpk39MdSZUjLw4AQUGjtuL10qA8k7KT51y9SCJsSwI/JBV7AXTiopNz6p9xn78oD9q8KApSwwHxNBRjBjEXyyxN1CWILLG4xf7IgcoAYxWSuOc5QTgMZQ8rDA2ABoAPQHl76AZ7KRQNARbwDQj9DVpuD3nCnQtQWKZ4Zjrd9H4YoAYxadrU1f7dEfbrNBLEbXaESPMzhcF+14aO1ALTNig88eIfWc4Qoa4dog3sEDVTwOkPjTcR6oe/JbsHetgCg6aSd1OYAFwoSrlAqrE4MgqBfSNy16sIbgHXbVgokkvkBfQYML1HtT8q9AqrYCPeC1EFkaCJGyM5mS13uFw1BaCedIUG1uCYbQB7Eic5PNzYAA3qN7ptEhXSZ7wHZGQLpuMzUlGSg6gCIcv9EDRCIOBqPuogn3AMi9wkMg0mHJSCfxRlQM0JoF/5FOh7RY7VuKkcVAbNAFg7tECoxgrZLR5kYNgVJGMdN5mWKSE5J668235Um67LWI6iQuh0Jg2AAManozlCsapLOqRjCuHwUyr2jGk08P2q9phdYFNDoiAMbI4t5ZbDXBPE9EMQBBRsuyLrlYJYzTTAdMw18BVuFNGrAvRwQgRR1xLwCPpXks4EkN40MPC3G2AIzMMKTTI0im0xW79unolWCUd/gr+C4ft1MxvX0x7YHaoZcB0QkflWZn5Jkd2dqQi8K/09LPHVFZEOubhlC3KkFE4i7FFBBXJPCEZtVKxUCgR9TBgZMCJLK4QfxItfQlNgBDUxKQEHp1QZQtyZ5SbcjRQccUfURS+hw/XnMfddcb1Q5E9KHUZyzPnVOaxUMoaTG6ADDMH70lCyTzGkoMAGZAmCMoWgE0xLJDqG8SOxKT1/8AiK9Bmh1FjjRWhyulhLg4NVHGCETR6pAshyjTterrcvoulLuUwmqYpyHacB6G+hoA1jDqmkTFD0+htLtyHyBpSUc6TM7AfsHgAYkYv1GMOjE8tS9MQ3UG/+9zAsnBBigc8REBp8dNBkB59r5CKRqnVZRGBzRp0ryVabqeHzkRQ3ELyCfpGcRpCsZGYDPEFjnFIBLPtNLUvAGQqe42AApBLh6QGQowSrDUvSbl+Gkga8mghnyavkXK59qyZd0uECRRkIYsRpDSh5zjaJrJoBtsmXychzZGfADkfwAuRwYB5Hq4FhumEPoNhsqm6CvIaTIaB1AdAmWOjUYnYvQLiP2CtZLqa0bRBuQeOQHJv0fwBI+3ZLowparpplqUaq4y0BJEZWsGANAaW20cxA6e3cn/BkSiqnWidlyTIIx7wmCmWOwB3CmrGvQaingaokeeG902AAIcDpzgeohVeZJFahmATpvK5umhI16a6EeWrRxLpnMGunLwu6c7sHp7Ryen1QnIZmnLJrOXmmudTiI4maAOMfoHExpgGTHAxCtj+ndBmye2nxUnIQcnAHcGcOmuBvihhmZuvAxk5vM0WUCZ97PmbLlBZ2gHZxyASMbOYRZk6YRmzpuWounBMTGdumO7chi0dO7fGc5VXp6N08RSZgNL5CKZ0li5zqZ9/nkAmJzNj61GZxtQBnBVS/r2msOqQeUGBZe/pKmzNMqfSUKpjQc8miZ7yfgHPEWqc5N6p3mkamjgZqeD0YgNqaOUPZ62ZLHIpu2bsmHZqAxMcpAAQs/VnJmxDFnVUninZxhZnwbga3Z+keYB04jycFxfZ6qf9nA5wsrLHBsUOfMEWptISjmiQCtk6mRG22dBVE5kGeWomg2xqFls5oWdHIRZlyZbnPZx/us7vZsucoBtBpMirml9ANIamysJqebgG5yObsV2p4ucEpNp+OdBUBwGgCGTzBeyZBnAHJya6QZZ2/szmU5ATIHnogIeetlnZjADcnfB3/uemfZqeaSHK53BTqma5mTDrnw5oOSbmsxh+fUMt54FRZnsELEchUGbC8GYBhu0tJ1n3pvWcCnaB+geWm/gQmDWnoRWOZ5Tt56rv0dBBfUbaBDRuPpstQKTzOnZzdVQb61bBiecJm352acQXxA5BZ20JJ/4LcVAFrBcm7AZomquUwR9nGBnYp89BBHNBcEa5QvO0udoWKAaeYYWgkhaZGZBDWEY7Aqek+Hgg6wcNzKwPh3wRAX0GhDkkArlTCFHJMAAZBZAN1AVP/xQWo2e4GJxnmbNnzJ8ubemfJ0+PnmFBeWSEdNvVEmbHPUo2fxiUBsmcsKhSHsat6axo6YQBZwEEHZLZkewHHGgrUtrQBSWctouVTaStqibq2yqriHwMRjqHd66IvJSGTyprJyb3akao1p52vEV3YHyvibhI4i+BigFU8ITsxM6eU9qWExDPKIDFm6lDqV7th/buZwYoCIyTwu6lEdZNa4ZByNlaOnpgpKP4PiE/pzQUSZ+Q0snlGCZfQDsxpw4IIZ3KwA+5xK1ckRvfiXxwE7UWY1R6HpCRBEAJHJzA+qDSSXhE+saqLgK+MTQTk+qATvvF06mdvCQF+3+1o7P2nTRy0S0cAxGXqFREqoqt2tIq2rj5DIpvcs6vxedMSk+iKMxvZVeGbjUXfOiVbhjKzW5CwLS/nxJzIQF0MIgcTHls1MiLvBvo/oTYDpDVOsopUmKiw/tnLtOzmMwHmZ0Adc6GeXCt4aNVYaSGWxpObrNlGV1hvUN4KQBOKWERHQYV6qu75fW7lqMQwOXSQY5aAc+KKrLiZeBwpZXg+V4/IFW45vOH1lXlkVZuX2OrxBYohHNQafnPGhpu8bOlrzHsETu2JbAB4l1gCAwkl1TwNiYm6gviGMlh7uyWxE/f1yW0hm0ts8QNZ1f5X5V90rKWHPcUUXN7JFuvkMi+0umQ7u6jXRCn1TV8vkGBOC5GzJYQkyqyR/jfOqVNL6spCjjq6h7lkBTBgwRoMsafXmQWBxFwYUaNHfVaf6s+3+yL76l1jrfxA+Vgc8GM5dQd9qB2krGI6tvUOA5wE4XwCAr75z/qUX/QzOdp7OHFFyKV86Poz25BjdyVYJzIWcw6Ewe0GnCAvJKZY2C2yTvG7x+01ZOZdP5zkww7FGozA16EechIz5yeu5ah5uMIdq/BulSpaBUD1y/gjLT63vLYl/AVJEhA4SaYx4zRhl4BpC1fZMEPMhSD10pSsQSmD37hPYKrUneikt1P7hB2lcBn5ZBQaWF81igHLWhpcgyQ2iZMtcLW1efGcASfVpVa0Wp0wvoTWb+xtZHXtu7/swMq1JW3jW7OSg0Z5A+Dwdkc9Vr2a8b+aDWgI2khEh07kZ19CLOVOhJih3k/V0gYE5TVkIYMAwhigBCarVxJcibbVhWPtXa2x1YRFaCygBdW7InsPdWWq9IYKWJFvEUv4i6Jow/XXFdhTLhuMBz0FAh6mIATb7JQYFzBMULLW4FUzEpeAFw0QbHLChwYmk4riy0iOXgtGVMznCaQJKBbGqh24bxMrUV5GhBTtX0xyYQmqodyxdgXJkCn+4sWnGAPge4XJ4vQXl3i2BHFCVylSkE5DpRMTadBizT0ZMg5QpAFeo6QB6rxetHHxm0hN0lJbMjuTbRzRnZLESxMmKYTx3JH5YrlwGlzEW2O1zuqUV+EF1QZhgrfxYskTtM/4e03/izDdh+ZE7SXGBWr+SwlRIumFH/O/gf4gt/lsBacze+b3H2wBMow6DCgnX0rlqZbaTIU6tIX2xv+XtOgjO0gs29E9RXNcYwRfFeq6Q3BsMkq2SADxfmQmtrOVJEPxrWSjIHNWQnBWmgU2YH9axeQHLMuk/WwwXrGRuiHGKUUeCpQoyRunpDuF8P0pAvAB6Hl59IQyD+2ckfBSLp7l9HnYBQe0UPhdn2BrUqBwJgAUr8Fxr8aHzVLRbyMZY1+pH+3ZdBGBud5llcemNjhjckHzENXdY+cwXGJSeRfhl5GHdRAnHbbjicZbyu3TFiqW56fIogH+NUzWgAEArtx3xTTf+BD3vmvTMYyw1hyBSfD8MQWkYkgPxo7dzRRA+ljEJORFqnvnfoUTvAI4Iiyujm9CIaOZF5FRRR7BQVrnZWU0NP7KDqWUV3YRx4qguEdccEbozYjejT82nXM8IYxwTzIdgmLI2yw1oJXzk1ZOQROWJwStb9+yDdta3qjSYnL+LWzbItLda/iVBkAEGaqBVrKQEaJXyWQHCxhtXUmVAzCAcEBGit6zdoAL0oEuHHOtwGq/1K94bZ/sYp34Ys77tw3YN24kytfHmO96SC72byHvcFxit8PToBB90YG96wuMfeLEq9shycMmt+FGX29Sbvc0YchzfaQYd9jAD32oMg/bSEj9xhxyEu5sTU7TE0h7bm2F9gua3Adtr5CJILoAA+C2spuJ3vmeDcfej8wbVlYjF39k4RYd3hP2SQP/wEA723y/DKV22gDwuY/GxDSA8P2J98+1gPpd7EYrl3t8aZ62RfVA8wPADq5XvgaD0A/1twD83TwPD9IJzp9GdBaznGSDz2TcHVeNceoOBFLA7oO0D7A9QSyQ++dYOn9mzcIPxHchl+3qgka0EP8AYQ/D96DoQ9oOwDu+ZYPuV6Q8eFZDpRxUdFxazEC3ND4A4YO9t8IGY3JwIhkkPdDhexf3xHKfdIPLts2c8RO0/ydIblD1Q/MONDxg5wOIDtg7HWZD6A4Rs392KcsxhkcdjEBKCXpCxA27F7gTk0pkzgymEdqw4HXL5kWQln9g8qbHmUE0w8YOMDvw8sPxD2ocCO9Djg8Mwwj45HgOF6hI6SPm+zI7Tlsj6EVyOf+iGW8OzDoo5UOzDgI/N18D5/YMO9HJw0bJ7SeKckKkpoqZSn8Q5I6nnUj8Ui0tcpuGGSIkoPKf1sCj9A/UOej/w8MoGcDWVwPR6TOQqPHDpR2cOGN8Y8Sm0dyKBkK5C0OFmPJF+Y5nGM7JY/ymqUNY68P/9iw6APujnw76O8tgY5CPODyffCPp9t/ub7dVltcX38j0Q5EOvjmceYP/joI/4sFdsGxTXNdqNG13dds2eAA5Z39ERmQRZGZ5hfWwZo130ZrljmLLwkGeV23D2fYsT59mcY2PvjrY9+PSjgSbsOgupE9amfgYmunHDcMGyRQpdkGaJ2pARjCRRLO7FUfHGT2E+KOxDhE649wgDw+SQYDM1biWzu62GtX5N/WMU2UfZTfAx620LoSpNN8ROaqnI3Ta9WOQXlYNOfak9Yy1Q4S2dW1NMsU0jX+ltKC1734YXfskh61IMQ1KIBUxzrTKvOr84lTQyo3hoKwApjjcxm4LhDIRxvqoreurpYXaM4h05BZ2NL2erW52ozpeQlk5YCBxu8ytzf6cOmw81kngqNZroysfSQ1cUzgs627m1/ObyOt9NpfoH1Vg7ouQ4VidbFEQemPRDrXiECbcVGuq0aOUBfZMj86Mshrog6oM8vvy6YOmgF5FJzxoMS7xzmtBAVybPjVBMrNEHlALaUYsfo04u6c/vbdpblaVJr28gDOF8+BgKR4Zmvv0cXB0MdIckiKxFbT3SkBc1B6KJ++lUbtxEoG/wph+gbHavUedt8CYcEEG/xylmzZ/Ma/JbRJWnq0UqDilSv+pP7NJiKdAXQB+M68xjOiBpyF2Vs9rY3DVjjYVWrT4RppXup/TpQvTMBjc27t7SjdkbMLhevIu9jyjbw3VG9LvwvCVTrtepiiPLoK6aAMc+S6vEJlblXLTg7ssb7ubmI4u9zs5kC6NVABMYvRup1VYujIEWzq7ybbi6a74UKS7MamLwS9ITeDbmJIuWcAbtyiCE6S+YvZL4I+aE+NpFZKwAmdcRHM7NnC9qMZL5FBiXVT8IfVO5N2sIU3omnU7SWpEVWMCHQEHJZNPrS9tpeiPa3C/mQ/L/YrolQkIuUc9g1u9bHRgJ7jDZ7Oe3kxcHUOjpV+osdvHvp5JBwnudcnlgXRY7gN14zo2joRNZwUNtuZFI7t2vgDVHYz2vJ1Na4FilrXqgcXlzP86XZcZ56+gMWQJAVoOayYae4wU29l3btZ64+16w9b6Wx3BHOBiscD1wVCr1iYIk61qt1wBK+lDbcHA2miRaXeafPobQdmCa7b7nlljt/tKen9zlA/Nv7Go7hqzNe9N4VqpTD6YGrwH9GjpyxaCtTl8hOhxE+vpwtOKGkfrzcKd2pdlMTTPnqyQUrwczSu1xqAUbJXgRXaJAgDzNiYAwAIJbFabE8DYkibW1mPUmYNhC/+n4NwVWavSNlPqUGKFmQfQvjkTDa6vLBjw1dmoT4LLsuBaCK6I2rMkjfo2b+jObovazqjZO0n+2jfJvCbx2eJu8t1QchPsLkTcZu5LwVSbWWN9gYhn+x167KtmExi/FvCLradAGDryFTWuXBja6puVBxwe8GvO3m4cGjB1a+cGzBjpR1uXZ6wbs4RZ0W/w2tB89RVOLVtU4SXIhuf2iG+E0DHiHVY16Ze7JEt7vjyQrkTdenIr+/2iuqUWK9B70hVaODHuMFheTNkWs9N1AU8Hwp+7ZTMj0jZyR1ZLDOWSCM9hv611PuDnBsatZYpiRzb3TO2ZgkacLpkSMtnaM1iLdzLXokIhTnZC2QDbs+qJQtPqtGKhaiI0ikEFpRhzcXvBhg+7UkoAqrdxI3dtRZu7Tm+6oQqwq0Ktu7eHiOsFMEqCFO8fPGkpfDXoAiiv7Q+uyPSs8hX+Pa5fnvBCg+XOHieipmg97ED2aDGCrn8/CVlr5aguPaAKQqmOaAW4/8BLqba6LvGz3fQJGlq23dBW17l+HLuaj55HvD+PK+5HnOlcQkzvyOuM2/HsruxFGPOKJ+5fvSYG4+YC24P0GsUfXDxWoAP4b9mbArz4dOfr6QIvYg2Mbm+K073q2DcQvtFzEdqP7SHmXVvIT4eY6n0N74cYefxC24p76L1k/dmR53bqZv9O/hdBPZaKe9bvBCxogvmoxcWdznB5us/aOeb8gyTmChCR57mZHgWf7mWjhR65uGDR8bYeN5+mTASzbIehuEDhUR5cPxHiKFTnJH9Oekf+ZnkTkecjxR+o2lU8haFuNZbu9mtbhBh4iOxNDR8ce+5q+Z0eb5nwfVvvH64V8eS7rh9CJAnrOZCf5HsJ8CcVbnBZUfYn6e6gb2bhJ6yOkn6cULnu79QaDkA51bUp1Q+0sg4Xz+5C9KIMn7pHFIJjq49GAMHmY/SmrlNI+ymXj4FMaeRkGcYiePZg2/INan1B8mP0H6Y7uPWnkmoWOOn1Y+WOCp5Ka0Pc9fp6Ee259qUQmCHtp1G9o5EY8EExj+p8uPCp0Z7fvUpiZ95P9bZ45mf8p8lAOfrj3p4HWvH/p4DkeUG+rdlISMOUdvLV+g9dvDo8quu7Ulz2/Ax8nUiJCAozHUBa5Eh0By6Ct01jN9vY8p6IDuF3OBboKIXzdJCBWM8bivMk8EFnzZ08DhGGRU9udbzx3KcvBLwRYWemwIIlK+yboGQ5kMgf2HlFFxwg5uWWpMdCCne350y0+EzG1oDfA3d4d9dOtAjmrBG944tzfAchzZ2md+AHMTs0wSLjdzDDdhIsMmhFTjXZv3apAVc6s1pjdHmxWxOpiUex8VrYCmp3keV66U5uI8avIetvFjuLQkmB6IAtRRV7p86EBIqkgod5odxYM+KWeGBVX3FmxI2kalAF80s0rW28YYangJzsY79m2iZUL8ENCAcHrBcqbqjACl5DeX81KhrFbALzEgc/NggulJzPzJWxS0vaxvPQ6Uv4townRZ5P+HouahYX5yeckX10yF9RfFARUh2YpNmTc+ebVrU88uDS7y4gwSAKDCBfxwEF5hA1N6t+ReMA6F7y52DmMjxfZ1o7kWhEXt+eHeoX+t6fdkCc6s3Rr7/UUNf5w2169e3XvZSYI1Xwrw5R8p/uC0D2En2H1gcED5bFhXuuvFthoTNtrrENYFQDUAPYXWG9gDAc9+th1AF4UQAXuNTB0g6AD/LR8vYM94FhdwQWpOhOawWquBeat8FAgrgWgAYA4PqD9AhcIInP8hOa0CAQ+4PrIBIBBa0CE5qrgepliXgP999A+GAAQDfA0ADD7aBBazmtwh/IUQDfABAK4CuAsgepgyBOaxkEFqSAK4BQ+Mgbmoo+lAbmrg/6APWDI+sgFHFwhOa2gDaArgXD6uBnwRD5o/GawWtUB+PhD9oBOanD9wgMgWgGfApPt8AyAGAIlr5hSPiAEO4v3jOV/eZCf99oAXuIWH0AgAA== -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=netgrif/application-engine&utm_content=323):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@camperko camperko changed the base branch from master to release/7.0.0-rev4 July 4, 2025 12:05
@coderabbitai coderabbitai bot added the Large label Jul 4, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🔭 Outside diff range comments (2)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java (1)

458-462: filterMetadata is still stored as a raw object graph – serialise it before persisting

The inline TODO highlights that the map should be converted to a string. Persisting a complex object into a text field may later break JSON querying or export/import.
One minimal fix inside createFilterCase:

-            setDataMap.put(FILTER_FIELD_ID, Map.of(
-                    "type", "filter",
-                    "value", filterQuery,
-                    "allowedNets", allowedNets,
-                    "filterMetadata", filterMetadata // TODO this is a map of <String, Object> that needs to be converted to string
-            ));
+            ObjectMapper mapper = new ObjectMapper();
+            setDataMap.put(FILTER_FIELD_ID, Map.of(
+                    "type", "filter",
+                    "value", filterQuery,
+                    "allowedNets", allowedNets,
+                    "filterMetadata", mapper.writeValueAsString(filterMetadata)
+            ));

Inject a singleton ObjectMapper to avoid per-call instantiation and handle the possible JsonProcessingException.

nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java (1)

473-475: Address the TODO: Implement proper pagination for group owner emails

Using Pageable.unpaged() loads all results at once, which could cause performance issues with large datasets. This TODO should be addressed before merging.

Consider implementing a paginated approach or limiting the number of groups that can be searched at once. Would you like me to help implement a solution or open an issue to track this?

🧹 Nitpick comments (10)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java (1)

60-113: Factor-out repetitive HashMap<>(Map.of(...)) boilerplate

The same 3-line pattern for building filterMetadata appears four times. A tiny factory helper or a static method (e.g. private static Map<String,Object> meta(Object… kvPairs)) keeps run() concise and makes later edits less error-prone.

application-engine/src/main/java/com/netgrif/application/engine/startup/runner/FunctionsCacheRunner.java (1)

25-26: Address the TODO comment about unpaged usage.

Using Pageable.unpaged() is appropriate in this startup runner context since you need to cache functions from all PetriNets without pagination limitations. Consider removing the TODO comment if this is the intended behavior.

-        // TODO JOFO: unpaged necessary?
-        petriNetService.getAll(Pageable.unpaged()).forEach(cacheService::cachePetriNetFunctions);
+        petriNetService.getAll(Pageable.unpaged()).forEach(cacheService::cachePetriNetFunctions);
application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java (2)

271-272: Properly adapted to paginated interface with valid TODO consideration.

The change correctly adapts to the new paginated PetriNetService interface while maintaining the existing functionality. The TODO comment raises a valid point about whether unpaged retrieval is necessary in this full-text search context. Consider evaluating if pagination would be beneficial here, especially for systems with large numbers of PetriNets, though unpaged may be justified for comprehensive search scenarios.


271-272: Consider pagination benefits for full-text search performance.

The current implementation using Pageable.unpaged().getContent() maintains existing behavior while adapting to the new paginated API. However, the TODO comment raises a valid concern.

For full-text search operations, especially when dealing with large numbers of PetriNets, implementing proper pagination could significantly improve performance and memory usage. Consider:

  1. Performance: Loading all PetriNets at once may cause memory pressure in large deployments
  2. Scalability: Pagination would allow the search to scale better as the number of nets grows
  3. User Experience: Could enable progressive loading/searching

Consider evaluating whether pagination would be beneficial here:

-// TODO JOFO: unpaged necessary?
-petriNets = petriNetService.getAll(Pageable.unpaged()).getContent();
+// Consider implementing pagination for better performance with large datasets
+petriNets = petriNetService.getAll(PageRequest.of(0, maxPetriNetsForSearch)).getContent();
application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java (1)

64-76: Good pagination adaptation with minor optimization opportunity

The changes correctly adapt to the paginated user service API. However, consider optimizing the stream operation on line 74:

-userService.saveUsers(users.stream().map(u -> (IUser) u).collect(Collectors.toList()));
+userService.saveUsers(users.getContent().stream().map(u -> (IUser) u).collect(Collectors.toList()));

This avoids potential redundant iteration and makes the intent clearer by working directly with the page content.

nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/PaginationProperties.java (1)

11-13: Consider separating @configuration and @ConfigurationProperties concerns.

While this works, it's generally better practice to keep @ConfigurationProperties classes separate from @Configuration classes for better separation of concerns and testability.

Consider this approach:

-@Data
-@Configuration
-@ConfigurationProperties(prefix = "netgrif.pagination")
-public class PaginationProperties {
+@Data
+@ConfigurationProperties(prefix = "netgrif.pagination")
+public class PaginationProperties {

Then create a separate configuration class or enable this via @EnableConfigurationProperties(PaginationProperties.class) in an existing configuration class.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java (1)

13-26: Fix Javadoc inconsistency in return type description.

The Javadoc comment describes the return type as "a set of Group entities" but the actual return type is Page<Group>.

-     * @return a set of {@link Group} entities associated with the specified owner ID
+     * @return a {@link Page} of {@link Group} entities associated with the specified owner ID
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)

116-116: Consider performance implications of the collection conversion chain.

The current implementation creates multiple intermediate collections: PageStreamListSet. This is inefficient for large datasets.

-        superUser.setAuthorities(Set.copyOf(authorityService.findAll(Pageable.unpaged()).stream().toList()));
+        superUser.setAuthorities(new HashSet<>(authorityService.findAll(Pageable.unpaged()).getContent()));
application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java (1)

357-399: Consider simplifying the aggregation pagination logic

The current implementation manually handles pagination in MongoDB aggregation. While functional, this could be simplified using Spring Data MongoDB's aggregation framework features.

Consider extracting this complex aggregation logic into a custom repository implementation or using Spring Data MongoDB's AggregationOperation with built-in pagination support. This would improve maintainability and reduce the complexity of this method.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java (1)

113-113: Fix parameter name to reflect single realm usage.

The parameter name realmIds should be singular realmId to maintain consistency with other methods in this interface that accept a single realm identifier.

-    Page<User> findAllByStateAndExpirationDateBefore(UserState state, LocalDateTime expirationDate, String realmIds, Pageable pageable);
+    Page<User> findAllByStateAndExpirationDateBefore(UserState state, LocalDateTime expirationDate, String realmId, Pageable pageable);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between efdc0c2 and 28da583.

📒 Files selected for processing (44)
  • .gitignore (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java (3 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/elastic/domain/ElasticPetriNetRepository.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticPetriNetService.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/elastic/service/interfaces/IElasticPetriNetService.java (0 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationAuthorizationService.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/importer/service/Importer.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/config/ProcessBeansConfiguration.java (3 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/roles/ProcessRoleRepository.java (3 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java (4 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (14 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/AnonymousRoleRunner.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java (3 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultRoleRunner.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/FunctionsCacheRunner.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (5 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/ConfigurableMenuService.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java (0 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java (0 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java (3 hunks)
  • application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml (1 hunks)
  • application-engine/src/test/groovy/com/netgrif/application/engine/action/AssignActionTest.groovy (2 hunks)
  • application-engine/src/test/groovy/com/netgrif/application/engine/auth/UserServiceTest.groovy (2 hunks)
  • application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/FunctionsTest.groovy (3 hunks)
  • application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy (2 hunks)
  • application-engine/src/test/java/com/netgrif/application/engine/petrinet/service/ProcessRoleServiceTest.java (3 hunks)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/Icon.java (1 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/service/ProcessRoleService.java (2 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/PaginationProperties.java (1 hunks)
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/AuthorityServiceImpl.java (3 hunks)
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java (7 hunks)
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (11 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/AuthorityRepository.java (1 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java (1 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/UserRepository.java (1 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/AuthorityService.java (1 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java (2 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java (2 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UserSearchRequestBody.java (1 hunks)
💤 Files with no reviewable changes (3)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java
  • application-engine/src/main/java/com/netgrif/application/engine/elastic/service/interfaces/IElasticPetriNetService.java
🧰 Additional context used
🧠 Learnings (2)
application-engine/src/main/java/com/netgrif/application/engine/workflow/service/ConfigurableMenuService.java (1)
Learnt from: renczesstefan
PR: netgrif/application-engine#318
File: nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java:60-62
Timestamp: 2025-06-23T13:30:13.096Z
Learning: In MenuItemConstants enum in nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java, the field `attributeId` will be renamed to `value` to make it more generic and appropriate for both dataset attribute identifiers and technical constants like PATH_SEPARATOR.
application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml (1)
Learnt from: renczesstefan
PR: netgrif/application-engine#318
File: nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java:60-62
Timestamp: 2025-06-23T13:30:13.096Z
Learning: In MenuItemConstants enum in nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java, the field `attributeId` will be renamed to `value` to make it more generic and appropriate for both dataset attribute identifiers and technical constants like PATH_SEPARATOR.
🧬 Code Graph Analysis (1)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)
application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (1)
  • ProcessRoleService (38-492)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: task-list-completed
  • GitHub Check: task-list-completed
  • GitHub Check: Build
🔇 Additional comments (62)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultFiltersRunner.java (1)

60-67: Good call switching to a mutable HashMap

createFilter mutates filterMetadata via put, which would blow up with an UnsupportedOperationException when fed an immutable Map.of(...). Wrapping the literal in new HashMap<>(…) fixes that runtime trap.

Also applies to: 70-88

.gitignore (1)

211-211: Good addition to prevent tracking storage artifacts.

Adding /storage/ to .gitignore is appropriate for the pagination implementation which may involve local storage or caching mechanisms.

application-engine/src/main/java/com/netgrif/application/engine/startup/runner/FunctionsCacheRunner.java (1)

10-10: LGTM - Import added for pagination support.

application-engine/src/main/java/com/netgrif/application/engine/workflow/service/ConfigurableMenuService.java (2)

21-21: LGTM - Import added for pagination support.


98-98: Correct usage of unpaged pagination for menu options.

Using Pageable.unpaged() is appropriate here since the method needs to retrieve all global roles to filter them for menu options.

application-engine/src/main/java/com/netgrif/application/engine/startup/runner/AnonymousRoleRunner.java (1)

30-31: Improved efficiency by using single entity lookup.

The change from findAllByImportId() to findByImportId() with null check is more efficient for checking the existence of a single anonymous role rather than retrieving a collection.

application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/PetriNetTest.groovy (2)

21-21: LGTM - Import added for pagination support in tests.


92-92: Test correctly updated for new paginated API.

The test properly adapts to the new API signature by adding Pageable.unpaged() parameter, ensuring all references are retrieved for verification.

application-engine/src/test/groovy/com/netgrif/application/engine/action/AssignActionTest.groovy (2)

25-25: LGTM! Import added for pagination support.

The Pageable import is correctly added to support the updated repository method signatures.


152-153: LGTM! Pagination parameter correctly added to repository calls.

The addition of Pageable.ofSize(1) is appropriate since the test only needs the first matching role. This maintains the existing test logic while adapting to the new paginated repository API.

nae-object-library/src/main/java/com/netgrif/application/engine/objects/petrinet/domain/Icon.java (2)

6-7: LGTM! Serialization imports added.

The imports for Serial and Serializable are correctly added to support serialization.


11-14: LGTM! Proper serialization implementation.

The class correctly implements Serializable with a proper serialVersionUID field annotated with @Serial. This ensures version compatibility for serialization operations.

application-engine/src/test/groovy/com/netgrif/application/engine/petrinet/domain/FunctionsTest.groovy (3)

22-22: LGTM! Import added for pagination support.

The Pageable import is correctly added to support the updated service method signatures.


127-127: LGTM! Pagination parameter correctly added to service call.

The addition of Pageable.unpaged() is appropriate for this test scenario where all matching nets should be retrieved without pagination limits.


145-145: LGTM! Pagination parameter correctly added to service call.

The addition of Pageable.unpaged() is appropriate for this test scenario where all matching nets should be retrieved without pagination limits.

application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationAuthorizationService.java (1)

99-99: LGTM! Pagination parameter correctly added to service call.

The addition of Pageable.unpaged() is appropriate since this method needs to retrieve all authorities matching the given IDs without pagination limits. This maintains the existing behavior while adapting to the new paginated API.

application-engine/src/test/groovy/com/netgrif/application/engine/auth/UserServiceTest.groovy (2)

106-106: LGTM! Pagination parameter correctly added to service call.

The addition of Pageable.unpaged() is appropriate for this test scenario where all matching users should be retrieved without pagination limits.


117-117: LGTM! Pagination parameter correctly added to service call.

The addition of Pageable.unpaged() is appropriate for this test scenario where all matching users should be retrieved without pagination limits.

application-engine/src/main/java/com/netgrif/application/engine/startup/runner/DefaultRoleRunner.java (2)

32-33: LGTM! Improved efficiency with direct entity lookup.

The change from collection-based existence checking to direct single-entity lookup is more efficient and aligns well with the broader pagination refactoring. Using findByImportId() with a null check is cleaner than fetching all matching entities and checking for empty collections.


32-33: LGTM: Improved semantic clarity with single-entity lookup.

The change from findAllByImportId() to findByImportId() and null checking is semantically more appropriate since import IDs should be unique. This aligns well with the broader pagination refactoring effort and eliminates unnecessary collection handling for what should be a single entity lookup.

application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseSearchService.java (2)

26-26: Correct import addition for pagination support.

The import is appropriately added to support the pagination changes in the service method below.


26-26: LGTM: Added necessary import for pagination support.

The import is correctly added to support the new paginated API.

application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java (1)

263-263: LGTM: Clean adaptation to paginated service API

The change correctly adapts to the new paginated AuthorityService.findAll() method while maintaining the original return type and behavior. Using Pageable.unpaged() preserves the "fetch all" semantics, and the stream conversion is efficient.

application-engine/src/main/java/com/netgrif/application/engine/importer/service/Importer.java (1)

1064-1064: Ignore Optional handling suggestion: findByImportId returns ProcessRole

Manual verification shows that ProcessRoleService.findByImportId(String) is declared in the adapter interface to return ProcessRole and its implementation delegates to the repository’s Optional<ProcessRole> via .orElse(null). There is no change to an Optional<ProcessRole> return type at the service level, so the existing calls in Importer.java compile as written.

Likely an incorrect or invalid review comment.

application-engine/src/test/java/com/netgrif/application/engine/petrinet/service/ProcessRoleServiceTest.java (1)

16-17: LGTM: Comprehensive test adaptation for pagination

The test methods are properly updated to work with the new paginated service API:

  • Correct use of Pageable.unpaged() to maintain existing test behavior
  • Proper adaptation of assertions using getTotalElements()
  • Stream operations correctly adapted for Page objects
  • Import statements appropriately added

The test logic and verification intent remain intact while working with the new API.

Also applies to: 58-66, 98-103, 108-113

nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UserSearchRequestBody.java (1)

7-36: Excellent documentation and multi-tenancy enhancement

The additions are well-implemented:

  • New realmId field: Properly supports multi-tenancy by allowing realm-scoped user searches
  • Comprehensive JavaDoc: Clear, professional documentation that explains the purpose and usage of each field
  • Consistent documentation style: All fields are properly documented with their intended behavior

This enhances the API usability and supports the broader pagination and multi-tenancy improvements in the system.

nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/PaginationProperties.java (1)

21-28: LGTM! Well-documented configuration properties.

The default values are reasonable and the documentation clearly explains the purpose of each property. The implementation follows Spring Boot configuration properties patterns correctly.

application-engine/src/main/java/com/netgrif/application/engine/elastic/domain/ElasticPetriNetRepository.java (1)

9-21: Excellent documentation improvements.

The added Javadoc comments significantly improve code readability and maintainability. The documentation clearly explains the purpose and behavior of each method.

application-engine/src/main/java/com/netgrif/application/engine/petrinet/config/ProcessBeansConfiguration.java (2)

4-6: LGTM! Proper dependency imports added.

The new imports for PaginationProperties and RealmService are correctly added to support the updated bean configuration.


32-47: Excellent dependency injection implementation.

The new dependencies are properly injected with consistent @Lazy annotations and correctly passed to the constructor. This follows Spring best practices and maintains consistency with the existing code pattern.

application-engine/src/main/java/com/netgrif/application/engine/petrinet/web/PetriNetController.java (1)

127-136: Excellent pagination implementation improvements.

The changes correctly improve pagination handling by:

  1. Passing Pageable parameters directly to service methods (lines 128, 130, 135)
  2. Returning Page objects directly instead of wrapping in PageImpl
  3. Properly handling the specific case where both identifier and version are provided (lines 132-133)

This approach preserves pagination metadata and is more efficient than the previous implementation.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/AuthorityRepository.java (4)

5-11: LGTM! Proper imports added for pagination support.

The new imports for Page, Pageable, and Optional correctly support the enhanced method signatures and pagination functionality.


13-16: Excellent documentation addition.

The Javadoc comments provide clear context about the repository's purpose and its relationship to the MongoDB database.


20-26: Great improvement using Optional return type.

Changing findByName to return Optional<Authority> instead of Authority is a best practice that makes the API more robust by explicitly handling the case where no matching entity is found.


28-35: Excellent pagination support implementation.

The new findAllBy_idIn method properly implements pagination by:

  1. Accepting a Pageable parameter for pagination configuration
  2. Returning Page<Authority> to preserve pagination metadata
  3. Providing clear documentation about its purpose and parameters

This follows Spring Data pagination best practices perfectly.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/GroupRepository.java (3)

10-10: LGTM! Collection import supports more flexible parameter types.

The change from Set to Collection import aligns with the method signature updates and provides more flexibility for callers.


27-27: Method signature change looks correct.

The addition of Pageable parameter and change to Page<Group> return type is consistent with the pagination implementation pattern.


37-44: Good improvement in method signature flexibility.

The change from Set<String> to Collection<String> parameter type provides more flexibility while maintaining type safety. The pagination support is properly implemented.

application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)

74-81: Fix potential concurrent modification and inefficient collection operations.

The current implementation has several issues:

  1. Direct modification of user.getProcessRoles() collection while iterating
  2. Inefficient repeated addAll() operations
  3. No initial capacity estimation for the collection
-            Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
-            Page<ProcessRole> processRoles;
-            do {
-                processRoles = processRoleService.findAll(pageable);
-                user.getProcessRoles().addAll(processRoles.getContent());
-                pageable = pageable.next();
-            } while (processRoles.hasNext());
+            Set<ProcessRole> allProcessRoles = new HashSet<>();
+            Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
+            Page<ProcessRole> processRoles;
+            do {
+                processRoles = processRoleService.findAll(pageable);
+                allProcessRoles.addAll(processRoles.getContent());
+                pageable = pageable.next();
+            } while (processRoles.hasNext());
+            user.setProcessRoles(allProcessRoles);

Likely an incorrect or invalid review comment.

application-engine/src/main/java/com/netgrif/application/engine/elastic/service/ElasticPetriNetService.java (1)

6-6: LGTM! Service properly decoupled from PetriNet domain logic.

The removal of IPetriNetService dependency and related methods simplifies the service to focus solely on Elasticsearch operations. This is a good architectural decision that reduces coupling.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java (2)

29-29: LGTM! Method signatures properly updated for pagination support.

The changes from Set<String> to Collection<String> parameter types and return types to Page<Group> are consistent with the pagination implementation pattern and provide better flexibility.

Also applies to: 31-31


55-55: Method signature change is consistent with pagination pattern.

The addition of Pageable parameter and change to Page<String> return type follows the established pagination pattern in the codebase.

nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/AuthorityServiceImpl.java (4)

9-10: LGTM! Proper imports for pagination support.

The imports for Page and Pageable are necessary for the pagination implementation.


28-30: Method signature properly updated for pagination.

The change to accept Pageable parameter and return Page<Authority> is consistent with the pagination pattern implemented across the codebase.


34-37: Good simplification of the getOrCreate method.

The method is now cleaner and more focused on its primary purpose of finding or creating authorities by name.


45-47: Pagination implementation looks correct.

The method properly accepts Pageable parameter and the ObjectId conversion logic is appropriate for MongoDB operations.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/AuthorityService.java (1)

4-46: Well-structured pagination implementation

The refactoring to support pagination is clean and follows Spring Data best practices. The added Javadoc documentation is comprehensive and helpful. The removal of permission and role-specific methods suggests a good simplification of the interface.

nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/service/ProcessRoleService.java (1)

9-39: Consistent pagination support across service methods

The pagination implementation is uniformly applied to all relevant query methods. The interface maintains a good balance between paginated and non-paginated methods based on their use cases.

application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/repositories/PetriNetRepository.java (1)

11-59: Clean repository refactoring with proper documentation

The repository interface has been effectively streamlined by removing unused methods and adding pagination support where needed. The comprehensive Javadoc documentation and use of Optional return types follow Spring Data best practices.

application-engine/src/main/java/com/netgrif/application/engine/workflow/web/WorkflowController.java (1)

105-105: Good catch on fixing the PageMetadata constructor parameter order!

The parameter order correction from (pageNumber, pageSize) to (pageSize, pageNumber) is an important bug fix that ensures pagination metadata is correctly represented in API responses.

Also applies to: 116-116, 129-129, 140-140, 168-168

application-engine/src/main/java/com/netgrif/application/engine/petrinet/domain/roles/ProcessRoleRepository.java (1)

16-22: Excellent addition of comprehensive JavaDoc documentation!

The detailed documentation for the repository interface and its methods greatly improves code maintainability and developer experience.

application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (1)

442-472: Well-implemented nested pagination for scalable role deletion!

The refactored deleteRolesOfNet method properly handles large datasets by using nested pagination loops for realms and users, preventing memory issues that could occur with the previous approach.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/repository/UserRepository.java (1)

41-71: Good defensive programming with clear exception messages!

Throwing exceptions for unsupported multi-collection operations with helpful messages directing users to the correct methods prevents misuse of the repository interface.

application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/interfaces/IPetriNetService.java (4)

27-337: Excellent documentation improvements!

The comprehensive Javadoc additions significantly enhance the interface clarity and maintainability. The documentation follows standard conventions and provides clear descriptions for all methods, parameters, return values, and exceptions.


98-111: Good addition of parameterized import method.

The new overloaded importPetriNet method with additional params parameter provides flexibility for passing extra configuration during import while maintaining backward compatibility.


270-337: Well-designed new methods enhance the interface.

The newly added methods provide valuable functionality:

  • Cache management for performance optimization
  • Multiple retrieval options by ObjectId
  • User-context aware deletion for audit trails
  • Dynamic action execution capability
  • Input validation for identifiers
  • Workflow integration through case-to-PetriNet mapping

145-145: Ensure Pagination Changes Are Fully Applied and Consumers Updated

  • No implementations of IPetriNetService were detected via class … implements IPetriNetService—please confirm that all concrete service classes (e.g. PetriNetServiceImpl) have had their method signatures updated to:
    • Page<PetriNet> getByIdentifier(String identifier, Pageable pageable);
    • Page<PetriNet> getAll(Pageable pageable);
    • Page<PetriNetReference> getReferences(…, Pageable pageable);
    • Page<PetriNetReference> getReferencesByIdentifier(String identifier, …, Pageable pageable);
    • Page<PetriNetReference> getReferencesByVersion(Version version, …, Pageable pageable);
  • Controller and assembler calls to getAll, getReferences* are already passing a Pageable and handling Page<T>. There were no direct calls to getByIdentifier found—ensure any internal or downstream consumers of that method are updated to include Pageable and process Page<PetriNet>.
  • Provide a migration guide for API consumers, detailing the signature changes and how to handle Page<T> results.
  • Consider your API versioning strategy if backward compatibility is required.
nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (5)

5-5: Good integration of centralized pagination configuration.

The PaginationProperties provides a clean way to manage pagination settings. The @Lazy annotation on the setter suggests potential circular dependency - ensure this is documented if it's a known constraint.

Also applies to: 60-61, 109-114


149-155: Clean pagination implementation for user retrieval.

The method correctly implements pagination with proper type conversion using the changeType helper. The single realm parameter simplifies the query scope appropriately.


254-262: Excellent implementation of paginated role loading.

The do-while loop pattern for loading all process roles in pages prevents memory issues with large datasets. This approach is consistently applied in both addAllRolesToAdminByUsername and getSystem methods.

Also applies to: 415-423


490-503: Robust implementation of role removal with pagination.

The nested iteration pattern correctly handles multiple realms while preventing memory issues through pagination. The do-while loop ensures all affected users are processed.


623-639: Well-structured predicate building for realm-scoped queries.

The updated buildPredicate method correctly:

  • Filters users by shared group membership for realm scoping
  • Excludes the system user from results
  • Handles optional query parameter gracefully
  • Maintains case-insensitive search across multiple fields

Comment on lines +150 to +152
// String uriNodeId = elasticCaseService.findUriNodeId(useCase)
// def node = uriService.findById(uriNodeId)
// updateMultichoiceWithCurrentNode(moveDestUri, node)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Remove commented code or confirm feature deprecation.

The commented code disables dynamic URI node ID functionality that appears to be systematically deprecated across the codebase. Rather than leaving this dead code commented out, consider either:

  1. Completely removing these lines if the feature is permanently deprecated
  2. Implementing alternative functionality if this capability is still required

Please confirm whether the dynamic URI node updating feature is intentionally deprecated and whether these lines can be safely removed:


🏁 Script executed:

#!/bin/bash
# Description: Verify if URI node ID methods are still used anywhere in the codebase
# Expected: No usage should be found if this feature is fully deprecated

# Search for any remaining usage of URI node ID methods
rg -A 3 "findUriNodeId|findAllByUriNodeId|elasticCaseService\.findUriNodeId"

# Search for any URI service usage in XML files
rg -A 3 "uriService\.findById" --type xml

# Check for any updateMultichoiceWithCurrentNode usage
rg -A 3 "updateMultichoiceWithCurrentNode"

Length of output: 300338


Remove deprecated URI node update snippet
The three commented lines in application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml (around lines 150–152) reference elasticCaseService.findUriNodeId, uriService.findById and updateMultichoiceWithCurrentNode but no active code calls these methods elsewhere. They can be safely removed to eliminate dead code.

• File: application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml
Remove lines:

//	String uriNodeId = elasticCaseService.findUriNodeId(useCase)
//	def node = uriService.findById(uriNodeId)
//	updateMultichoiceWithCurrentNode(moveDestUri, node)
🤖 Prompt for AI Agents
In
application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml
around lines 150 to 152, remove the three commented lines referencing
elasticCaseService.findUriNodeId, uriService.findById, and
updateMultichoiceWithCurrentNode as they are deprecated and not called
elsewhere, eliminating dead code.

🛠️ Refactor suggestion

Clean up commented code or document deprecation timeline.

The commented-out code disables the dynamic update of the move_dest_uri field based on URI node IDs, which aligns with the systematic removal of URI node ID-based methods mentioned in the broader refactoring.

However, leaving commented code in production files is typically not recommended. Consider:

  1. If permanently deprecated: Remove the commented lines entirely
  2. If temporarily disabled: Add a clear comment explaining the timeline and reasoning
  3. If pending migration: Document the migration plan and target completion
-//			String uriNodeId = elasticCaseService.findUriNodeId(useCase)
-//			def node = uriService.findById(uriNodeId)
-//			updateMultichoiceWithCurrentNode(moveDestUri, node)
+// URI node ID functionality deprecated as part of NAE-2122 pagination refactoring
+// Dynamic node updates temporarily disabled pending alternative implementation

Or if permanently removed:

-//			String uriNodeId = elasticCaseService.findUriNodeId(useCase)
-//			def node = uriService.findById(uriNodeId)
-//			updateMultichoiceWithCurrentNode(moveDestUri, node)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// String uriNodeId = elasticCaseService.findUriNodeId(useCase)
// def node = uriService.findById(uriNodeId)
// updateMultichoiceWithCurrentNode(moveDestUri, node)
// URI node ID functionality deprecated as part of NAE-2122 pagination refactoring
// Dynamic node updates temporarily disabled pending alternative implementation
🤖 Prompt for AI Agents
In
application-engine/src/main/resources/petriNets/engine-processes/preference_item.xml
around lines 150 to 152, the commented-out code related to updating
move_dest_uri based on URI node IDs should be either fully removed if this
functionality is permanently deprecated, or if it is temporarily disabled, add a
clear comment explaining why it is disabled and when or under what conditions it
will be re-enabled or removed. If this is part of a migration, document the
migration plan and expected timeline in the comments to maintain clarity.

Comment on lines +104 to +111
Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
Page<ProcessRole> processRoles;
do {
processRoles = processRoleService.findAll(pageable);
superUser.getProcessRoles().addAll(processRoles.getContent());
pageable = pageable.next();
} while (processRoles.hasNext());

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Apply the same fix for concurrent modification issues.

The same issues exist in the setAllProcessRoles method.

-        Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
-        Page<ProcessRole> processRoles;
-        do {
-            processRoles = processRoleService.findAll(pageable);
-            superUser.getProcessRoles().addAll(processRoles.getContent());
-            pageable = pageable.next();
-        } while (processRoles.hasNext());
+        Set<ProcessRole> allProcessRoles = new HashSet<>();
+        Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
+        Page<ProcessRole> processRoles;
+        do {
+            processRoles = processRoleService.findAll(pageable);
+            allProcessRoles.addAll(processRoles.getContent());
+            pageable = pageable.next();
+        } while (processRoles.hasNext());
+        superUser.getProcessRoles().clear();
+        superUser.getProcessRoles().addAll(allProcessRoles);
🤖 Prompt for AI Agents
In
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
around lines 104 to 111, the code adds process roles directly to the superUser's
collection inside a loop, which can cause concurrent modification issues. To fix
this, first collect all process roles in a temporary list during pagination,
then add them to superUser's process roles after the loop completes, avoiding
modification during iteration.

Comment on lines +135 to +147
Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
Page<Group> userGroups;
do {
userGroups = groupRepository.findByOwnerId(user.getStringId(), pageable);

Optional<Group> group = userGroups.stream().filter(g -> g.getIdentifier().equals(user.getUsername())).findFirst();
if (group.isPresent()) {
return group.get();
}

pageable = pageable.next();
} while (userGroups.hasNext());
throw new ResourceNotFoundException(ResourceNotFoundExceptionCode.DEFAULT_USER_GROUP_NOT_FOUND, errorMessage);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider optimizing the pagination loop for better performance

The current implementation iterates through all pages to find a matching group. For users with many groups, this could be inefficient. Consider using a query that directly filters by both owner ID and identifier to avoid pagination altogether.

Replace the pagination loop with a direct query:

-Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
-Page<Group> userGroups;
-do {
-    userGroups = groupRepository.findByOwnerId(user.getStringId(), pageable);
-
-    Optional<Group> group = userGroups.stream().filter(g -> g.getIdentifier().equals(user.getUsername())).findFirst();
-    if (group.isPresent()) {
-        return group.get();
-    }
-
-    pageable = pageable.next();
-} while (userGroups.hasNext());
-throw new ResourceNotFoundException(ResourceNotFoundExceptionCode.DEFAULT_USER_GROUP_NOT_FOUND, errorMessage);
+Optional<Group> group = groupRepository.findByOwnerIdAndIdentifier(user.getStringId(), user.getUsername());
+return group.orElseThrow(() -> new ResourceNotFoundException(ResourceNotFoundExceptionCode.DEFAULT_USER_GROUP_NOT_FOUND, errorMessage));

Note: This would require adding a new method findByOwnerIdAndIdentifier to the GroupRepository.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java
between lines 135 and 147, the current code uses a pagination loop to find a
group by owner ID and identifier, which is inefficient. To fix this, add a new
method findByOwnerIdAndIdentifier in GroupRepository that directly queries for a
group matching both criteria. Replace the pagination loop with a single call to
this new method and handle the optional result accordingly, throwing
ResourceNotFoundException if not found.

})
public ResponseEntity<List<Authority>> getAllAuthorities() {
return ResponseEntity.ok(authorityService.findAll());
return ResponseEntity.ok(authorityService.findAll(Pageable.unpaged()).stream().toList());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here may would be good idea to provide pageable property as request param.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but currently it is not needed, because authority set will never be large enough. This would need more rework through all repos.

public List<ProcessRole> saveAll(Iterable<ProcessRole> entities) {
return StreamSupport.stream(entities.spliterator(), false).map(processRole -> {
if (!processRole.isGlobal() || processRoleRepository.findAllByImportId(processRole.getImportId()).isEmpty()) {
if (!processRole.isGlobal() || processRoleRepository.findByImportId(processRole.getImportId()) == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this returns Optional and then it will never be null. Please consider to replace it with Optional.isEmpty().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry 😄 I just noticed while scrolling down that coderabbitai had the same comment.

// All cases
createCaseFilter("All cases", "assignment", FILTER_VISIBILITY_PUBLIC, "", new ArrayList<String>(),
Map.of(
new HashMap<>(Map.of(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case we can use

new HashMap<>(){{
      put("key1", "value1");
      put("key2", "value2");
}};

Map.of return immutable map, that cannot be modified later. But I think it is OK here, because you are not using this instance later, and its key value pair is copied to HashMap.


public void setAllAuthorities() {
superUser.setAuthorities(Set.copyOf(authorityService.findAll()));
superUser.setAuthorities(Set.copyOf(authorityService.findAll(Pageable.unpaged()).stream().toList()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be an issue, since Set.copyOf returns immutable set, so later when a super user is accessed through this runner, it will return object with authority set, that cannot be updated with new authorities, please consider use of new HashSet

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the object is immediately saved to DB and nothing works with authorities outside this one assign. When queried from DB, the object is returned with mutable set.


// @Deprecated
// List<Field> getData(String caseId);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kindly please, remove unnecessary comments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is deletion of that :)

*/
@Data
@Configuration
@ConfigurationProperties(prefix = "netgrif.pagination")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is other PR opened to refactor configuration properties naming scheme. The new naming scheme is the following: netgrif.<app>.<property-domain>.<property-name>, so in this case it would be netgrif.engine.pagination. Please update it to use new naming convention.

Pageable pageable = PageRequest.of(0, paginationProperties.getBackendPageSize());
Page<ProcessRole> processRoles;
do {
processRoles = processRoleService.findAll(pageable);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we using here do-while with restricted page size instead of unpaged and one call? Could it be a performance issue to use unpaged? If yes, then what is the situation in case when user holds too much roles and then it is saved to database?

tuplle
tuplle previously approved these changes Jul 19, 2025
- Updated tests in `PetriNetTest.groovy` by introducing the `Page<PetriNetReference>` type for the `nets` variable to ensure type safety and clarity.
- Imported `Page` and `PetriNetReference` and adjusted relevant usages in `PetriNetTest.groovy`.
- Refined total result calculation logic in `PetriNetService` by transitioning the `total` value handling to use a `Number` type, avoiding potential null pointer exceptions.
- Adopted safer numeric type conversions ensuring robust and error-free handling of MongoDB aggregation results.
- Maintained backward compatibility while improving code readability and reliability.
@machacjozef machacjozef merged commit 583449f into release/7.0.0-rev4 Jul 20, 2025
7 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Sep 22, 2025
18 tasks
@coderabbitai coderabbitai bot mentioned this pull request Oct 17, 2025
18 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants