From ad0c7635b302d919328970832d445c324c23c91a Mon Sep 17 00:00:00 2001
From: Romuald Caplier <romuald.caplier@camptocamp.com>
Date: Fri, 24 May 2024 15:34:11 +0200
Subject: [PATCH] feat(datahub): finish organization-page

---
 .../src/e2e/organization-page.cy.ts           | 125 ++++++++++++++++++
 apps/datahub-e2e/src/e2e/organizations.cy.ts  |   9 +-
 .../organization-details.component.css        |  15 +++
 .../organization-details.component.html       |  24 +++-
 .../organization-details.component.spec.ts    |   4 -
 .../organization-details.component.ts         |  53 +++++---
 .../organization-header.component.css         |   0
 .../organization-header.component.html        |   2 +
 .../organization-header.component.spec.ts     |   0
 .../organization-header.component.ts          |   0
 .../organization-page.component.ts            |   2 +-
 .../domain/src/lib/model/user/user.model.ts   |   2 +-
 .../catalog/src/lib/my-org/my-org.service.ts  |   4 +-
 .../related-record-card.component.html        |   2 +-
 .../related-record-card.component.ts          |  23 +++-
 .../docker-entrypoint-initdb.d/dump           | Bin 460488 -> 460652 bytes
 16 files changed, 234 insertions(+), 31 deletions(-)
 create mode 100644 apps/datahub-e2e/src/e2e/organization-page.cy.ts
 rename apps/datahub/src/app/organization/{header-organization => organization-header}/organization-header.component.css (100%)
 rename apps/datahub/src/app/organization/{header-organization => organization-header}/organization-header.component.html (95%)
 rename apps/datahub/src/app/organization/{header-organization => organization-header}/organization-header.component.spec.ts (100%)
 rename apps/datahub/src/app/organization/{header-organization => organization-header}/organization-header.component.ts (100%)

diff --git a/apps/datahub-e2e/src/e2e/organization-page.cy.ts b/apps/datahub-e2e/src/e2e/organization-page.cy.ts
new file mode 100644
index 0000000000..af3b7783a1
--- /dev/null
+++ b/apps/datahub-e2e/src/e2e/organization-page.cy.ts
@@ -0,0 +1,125 @@
+import 'cypress-real-events'
+
+describe('organizations', () => {
+  beforeEach(() => {
+    cy.visit('organization/Barbie%20Inc.')
+
+    // aliases
+    cy.get('gn-ui-navigation-button').as('backButton')
+    cy.get('[data-cy="organizationHeaderName"]').as('organizationHeaderName')
+    cy.get('[data-cy="organizationHeaderWebsiteLink"]').as(
+      'organizationHeaderWebsiteLink'
+    )
+    cy.get('[data-cy="organizationDescription"]').as('organizationDescription')
+    cy.get('gn-ui-max-lines').contains('Read more').as('readMoreButton')
+    cy.get('[data-cy="organizationLogo"]').as('organizationLogo')
+    cy.get('[data-cy="organizationDatasetCount"]').as(
+      'organizationDatasetCount'
+    )
+    cy.get('[data-cy="organizationEmail"]').as('organizationEmail')
+    cy.get('[data-cy="organizationPageLastPublishedDatasets"]').as(
+      'organizationPageLastPublishedDatasets'
+    )
+    cy.get(
+      '[data-cy="organizationDetailsLastPublishedDatasetsSearchAllButton"]'
+    ).as('organizationDetailsLastPublishedDatasetsSearchAllButton')
+  })
+
+  describe('general display', () => {
+    describe('header', () => {
+      describe('back button', () => {
+        beforeEach(() => {
+          // Simulate that we come from the organizations search page
+          cy.visit('organisations')
+          cy.visit('organization/Barbie%20Inc.')
+        })
+
+        it('back button goes to the previous visited page', () => {
+          cy.get('@backButton').click()
+          cy.url().should('include', '/organisations')
+        })
+      })
+
+      it('should display the organization name', () => {
+        cy.get('@organizationHeaderName').should('contain', 'Barbie Inc.')
+      })
+
+      it('should display the organization website link', () => {
+        cy.get('@organizationHeaderWebsiteLink')
+          .should('be.visible')
+          .should('have.attr', 'href', 'https://www.barbie-inc.com/')
+          .and('have.attr', 'target', '_blank')
+      })
+    })
+
+    describe('details', () => {
+      describe('left column', () => {
+        it('should display the organization description', () => {
+          cy.get('@organizationDescription').should('be.visible')
+        })
+
+        it('click on read more should expand the organization description', () => {
+          let initialDescription
+          let newDescription
+
+          cy.get('@organizationDescription').then((firstDescription) => {
+            initialDescription = firstDescription
+            cy.get('@readMoreButton').trigger('click')
+            cy.get('@organizationDescription').then((secondDescription) => {
+              newDescription = secondDescription
+              expect(newDescription).to.not.equal(initialDescription)
+            })
+          })
+        })
+      })
+
+      describe('right column', () => {
+        it('should display the organization logo', () => {
+          cy.get('@organizationLogo').should('be.visible')
+        })
+
+        it('should display the organization dataset count', () => {
+          cy.get('@organizationDatasetCount').should('be.visible')
+        })
+
+        it('a click on the organization dataset count should open the dataset search page filtered on the organization', () => {
+          cy.get('@organizationDatasetCount').then(($link) => {
+            const url = $link.prop('href')
+            cy.wrap($link).click()
+
+            cy.url().should('eq', url)
+          })
+        })
+
+        it('should display the organization email', () => {
+          cy.get('@organizationEmail')
+            .should('be.visible')
+            .and('have.attr', 'href', 'mailto:contact@barbie-inc.com')
+        })
+      })
+
+      describe('last published datasets', () => {
+        it('should display the last published datasets', () => {
+          cy.get('@organizationPageLastPublishedDatasets').should('be.visible')
+        })
+
+        it('should display the search all button', () => {
+          cy.get(
+            '@organizationDetailsLastPublishedDatasetsSearchAllButton'
+          ).should('be.visible')
+        })
+
+        it('a click on the search all button should open the dataset search page filtered on the organization', () => {
+          cy.get(
+            '@organizationDetailsLastPublishedDatasetsSearchAllButton'
+          ).then(($link) => {
+            const url = $link.prop('href')
+            cy.wrap($link).click()
+
+            cy.url().should('eq', url)
+          })
+        })
+      })
+    })
+  })
+})
diff --git a/apps/datahub-e2e/src/e2e/organizations.cy.ts b/apps/datahub-e2e/src/e2e/organizations.cy.ts
index b39da4ca39..ded2dc026d 100644
--- a/apps/datahub-e2e/src/e2e/organizations.cy.ts
+++ b/apps/datahub-e2e/src/e2e/organizations.cy.ts
@@ -77,14 +77,15 @@ describe('organizations', () => {
   })
 
   describe('list features', () => {
-    it('should search with a filter on the selected org on click', () => {
+    it('should open the organization page', () => {
       cy.get('@organizationsName')
         .eq(10)
         .then(($clickedName) => {
           cy.get('@organizations').eq(10).click()
-          cy.url()
-            .should('include', 'publisher=')
-            .and('include', encodeURIComponent($clickedName.text().trim()))
+          cy.url().should(
+            'contain',
+            `organization/${encodeURIComponent($clickedName.text().trim())}`
+          )
         })
     })
   })
diff --git a/apps/datahub/src/app/organization/organization-details/organization-details.component.css b/apps/datahub/src/app/organization/organization-details/organization-details.component.css
index e69de29bb2..c0d50f2d1c 100644
--- a/apps/datahub/src/app/organization/organization-details/organization-details.component.css
+++ b/apps/datahub/src/app/organization/organization-details/organization-details.component.css
@@ -0,0 +1,15 @@
+.list-page-dot {
+  width: 6px;
+  height: 6px;
+  border-radius: 6px;
+  position: relative;
+}
+
+.list-page-dot:after {
+  content: '';
+  position: absolute;
+  left: -7px;
+  top: -7px;
+  width: 20px;
+  height: 20px;
+}
diff --git a/apps/datahub/src/app/organization/organization-details/organization-details.component.html b/apps/datahub/src/app/organization/organization-details/organization-details.component.html
index 9ef5da0aef..d149ccd760 100644
--- a/apps/datahub/src/app/organization/organization-details/organization-details.component.html
+++ b/apps/datahub/src/app/organization/organization-details/organization-details.component.html
@@ -10,6 +10,7 @@
             <gn-ui-max-lines [maxLines]="2" *ngIf="organization.description">
               <div>
                 <gn-ui-markdown-parser
+                  data-cy="organizationDescription"
                   data-test="organizationDescription"
                   [textContent]="organization.description"
                 ></gn-ui-markdown-parser>
@@ -26,6 +27,7 @@
           class="w-[300px] flex flex-col gap-5"
         >
           <div
+            data-cy="organizationLogo"
             class="bg-white border border-[#d8d8d8] w-full h-[185px] rounded-lg p-[30px] -mt-28"
           >
             <gn-ui-thumbnail
@@ -36,6 +38,7 @@
             </gn-ui-thumbnail>
           </div>
           <a
+            data-cy="organizationDatasetCount"
             [routerLink]="['/', ROUTER_ROUTE_SEARCH]"
             [queryParams]="{ publisher: organization.name }"
           >
@@ -50,6 +53,7 @@
           </a>
 
           <a
+            data-cy="organizationEmail"
             data-test="organizationEmail"
             [href]="'mailto:' + organization.email"
           >
@@ -93,6 +97,7 @@
                   [routerLink]="['/', ROUTER_ROUTE_SEARCH]"
                   [queryParams]="{ publisher: organization.name }"
                   class="gn-ui-btn-primary h-[34px] rounded-lg"
+                  data-cy="organizationDetailsLastPublishedDatasetsSearchAllButton"
                   data-test="organizationDetailsLastPublishedDatasetsSearchAllButton"
                 >
                   Search all
@@ -111,6 +116,7 @@
               >
                 <div
                   class="mb-4 flex flex-wrap gap-9 justify-center sm:justify-start px-[25px]"
+                  data-cy="organizationPageLastPublishedDatasets"
                   data-test="organizationPageLastPublishedDatasets"
                 >
                   <gn-ui-related-record-card
@@ -119,6 +125,20 @@
                     [extraClass]="'w-[300px]'"
                   ></gn-ui-related-record-card>
                 </div>
+                <div
+                  *ngIf="totalPages > 1"
+                  class="flex flex-row justify-center gap-[14px] p-1 mx-auto"
+                  [ngClass]="paginationContainerClass"
+                >
+                  <button
+                    *ngFor="let page of pages"
+                    class="list-page-dot"
+                    (click)="goToPage(page)"
+                    [ngClass]="
+                      currentPage === page ? 'bg-primary' : 'bg-gray-400'
+                    "
+                  ></button>
+                </div>
               </ng-container>
             </ng-container>
 
@@ -132,9 +152,9 @@
             </ng-container>
 
             <ng-template #orgHasNoDataset>
-              <gn-ui-search-results-error
+              <gn-ui-error
                 [type]="ErrorType.ORGANIZATION_HAS_NO_DATASET"
-              ></gn-ui-search-results-error>
+              ></gn-ui-error>
             </ng-template>
           </div>
         </div>
diff --git a/apps/datahub/src/app/organization/organization-details/organization-details.component.spec.ts b/apps/datahub/src/app/organization/organization-details/organization-details.component.spec.ts
index 6e4d6078ac..1fff01d88f 100644
--- a/apps/datahub/src/app/organization/organization-details/organization-details.component.spec.ts
+++ b/apps/datahub/src/app/organization/organization-details/organization-details.component.spec.ts
@@ -52,10 +52,6 @@ class OrganisationsServiceMock {
 }
 
 const anOrganizationWithManyDatasets: Organization = ORGANISATIONS_FIXTURE[0]
-const anOrganizationWithOnlyOneDataset: Organization = {
-  ...ORGANISATIONS_FIXTURE[0],
-  recordCount: 1,
-}
 
 const oneDataset = [DATASET_RECORDS[0]]
 const manyDatasets = DATASET_RECORDS.concat(DATASET_RECORDS[0])
diff --git a/apps/datahub/src/app/organization/organization-details/organization-details.component.ts b/apps/datahub/src/app/organization/organization-details/organization-details.component.ts
index 23ab3fd7a2..ac116a314b 100644
--- a/apps/datahub/src/app/organization/organization-details/organization-details.component.ts
+++ b/apps/datahub/src/app/organization/organization-details/organization-details.component.ts
@@ -4,11 +4,13 @@ import {
   ChangeDetectorRef,
   Component,
   Input,
+  OnChanges,
   OnDestroy,
   OnInit,
+  SimpleChanges,
   ViewChild,
 } from '@angular/core'
-import { AsyncPipe, NgForOf, NgIf } from '@angular/common'
+import { AsyncPipe, NgClass, NgForOf, NgIf } from '@angular/common'
 import {
   CatalogRecord,
   Organization,
@@ -32,7 +34,7 @@ import {
 } from '@geonetwork-ui/ui/elements'
 import { UiSearchModule } from '@geonetwork-ui/ui/search'
 import { SearchFacade } from '@geonetwork-ui/feature/search'
-import { Observable, of, Subscription, switchMap } from 'rxjs'
+import { BehaviorSubject, Observable, of, Subscription, switchMap } from 'rxjs'
 import { UiDatavizModule } from '@geonetwork-ui/ui/dataviz'
 import { RouterLink } from '@angular/router'
 import { ROUTER_ROUTE_SEARCH } from '@geonetwork-ui/feature/router'
@@ -63,15 +65,19 @@ import { UiWidgetsModule } from '@geonetwork-ui/ui/widgets'
     UiDatavizModule,
     RouterLink,
     UiWidgetsModule,
+    NgClass,
   ],
 })
 export class OrganizationDetailsComponent
-  implements OnInit, AfterViewInit, OnDestroy
+  implements OnInit, AfterViewInit, OnDestroy, OnChanges
 {
   protected readonly Error = Error
   protected readonly ErrorType = ErrorType
+  protected readonly ROUTER_ROUTE_SEARCH = ROUTER_ROUTE_SEARCH
 
-  @Input() organization: Organization
+  protected get pages() {
+    return new Array(this.totalPages).fill(0).map((_, i) => i + 1)
+  }
 
   lastPublishedDatasets$: Observable<CatalogRecord[]> = of([])
 
@@ -84,6 +90,11 @@ export class OrganizationDetailsComponent
   isFirstPage = this.currentPage === 1
   isLastPage = false
 
+  organizationHasChanged$ = new BehaviorSubject<void>(undefined)
+
+  @Input() organization: Organization
+  @Input() paginationContainerClass = 'w-full bottom-0 top-auto'
+
   @ViewChild(BlockListComponent) list: BlockListComponent
 
   constructor(
@@ -95,19 +106,29 @@ export class OrganizationDetailsComponent
   ngOnInit(): void {
     this.searchFacade.setPageSize(3)
 
-    this.lastPublishedDatasets$ = this.organizationsService
-      .getFiltersForOrgs([this.organization])
-      .pipe(
-        switchMap((filters) => {
-          return this.searchFacade
-            .setFilters(filters)
-            .setSortBy(['desc', 'changeDate']).results$
-        })
-      )
+    this.lastPublishedDatasets$ = this.organizationHasChanged$.pipe(
+      switchMap(() => {
+        return this.organizationsService
+          .getFiltersForOrgs([this.organization])
+          .pipe(
+            switchMap((filters) => {
+              return this.searchFacade
+                .setFilters(filters)
+                .setSortBy(['desc', 'changeDate']).results$
+            })
+          )
+      })
+    )
 
     this.manageSubscriptions()
   }
 
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes['organization']) {
+      this.organizationHasChanged$.next()
+    }
+  }
+
   ngAfterViewInit() {
     // this is required to show the pagination correctly
     this.changeDetector.detectChanges()
@@ -129,6 +150,10 @@ export class OrganizationDetailsComponent
     }
   }
 
+  goToPage(page: number) {
+    this.searchFacade.paginate(page)
+  }
+
   private manageSubscriptions() {
     this.subscriptions$.add(
       this.searchFacade.isLoading$.subscribe(
@@ -161,6 +186,4 @@ export class OrganizationDetailsComponent
       )
     )
   }
-
-  protected readonly ROUTER_ROUTE_SEARCH = ROUTER_ROUTE_SEARCH
 }
diff --git a/apps/datahub/src/app/organization/header-organization/organization-header.component.css b/apps/datahub/src/app/organization/organization-header/organization-header.component.css
similarity index 100%
rename from apps/datahub/src/app/organization/header-organization/organization-header.component.css
rename to apps/datahub/src/app/organization/organization-header/organization-header.component.css
diff --git a/apps/datahub/src/app/organization/header-organization/organization-header.component.html b/apps/datahub/src/app/organization/organization-header/organization-header.component.html
similarity index 95%
rename from apps/datahub/src/app/organization/header-organization/organization-header.component.html
rename to apps/datahub/src/app/organization/organization-header/organization-header.component.html
index 9c16ff9bc0..cd68f67fbd 100644
--- a/apps/datahub/src/app/organization/header-organization/organization-header.component.html
+++ b/apps/datahub/src/app/organization/organization-header/organization-header.component.html
@@ -22,6 +22,7 @@
       </div>
     </div>
     <div
+      data-cy="organizationHeaderName"
       class="font-title text-[28px] max-w-screen-sm line-clamp-4 ml-4"
       [style.color]="foregroundColor"
     >
@@ -41,6 +42,7 @@
       <ng-container *ngIf="organization.website">
         <p>&bull;</p>
         <a
+          data-cy="organizationHeaderWebsiteLink"
           class="flex flex-row items-center gap-1"
           href="{{ organization.website.href }}"
           target="_blank"
diff --git a/apps/datahub/src/app/organization/header-organization/organization-header.component.spec.ts b/apps/datahub/src/app/organization/organization-header/organization-header.component.spec.ts
similarity index 100%
rename from apps/datahub/src/app/organization/header-organization/organization-header.component.spec.ts
rename to apps/datahub/src/app/organization/organization-header/organization-header.component.spec.ts
diff --git a/apps/datahub/src/app/organization/header-organization/organization-header.component.ts b/apps/datahub/src/app/organization/organization-header/organization-header.component.ts
similarity index 100%
rename from apps/datahub/src/app/organization/header-organization/organization-header.component.ts
rename to apps/datahub/src/app/organization/organization-header/organization-header.component.ts
diff --git a/apps/datahub/src/app/organization/organization-page/organization-page.component.ts b/apps/datahub/src/app/organization/organization-page/organization-page.component.ts
index a1dc77c981..99cc91b16b 100644
--- a/apps/datahub/src/app/organization/organization-page/organization-page.component.ts
+++ b/apps/datahub/src/app/organization/organization-page/organization-page.component.ts
@@ -1,7 +1,7 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'
 import { RouterFacade } from '@geonetwork-ui/feature/router'
 import { AsyncPipe, NgIf } from '@angular/common'
-import { OrganizationHeaderComponent } from '../header-organization/organization-header.component'
+import { OrganizationHeaderComponent } from '../organization-header/organization-header.component'
 import { OrganizationDetailsComponent } from '../organization-details/organization-details.component'
 import { combineLatest, Observable, of, switchMap } from 'rxjs'
 import { filter } from 'rxjs/operators'
diff --git a/libs/common/domain/src/lib/model/user/user.model.ts b/libs/common/domain/src/lib/model/user/user.model.ts
index fefd657049..591fc7bf18 100644
--- a/libs/common/domain/src/lib/model/user/user.model.ts
+++ b/libs/common/domain/src/lib/model/user/user.model.ts
@@ -5,6 +5,6 @@ export interface UserModel {
   name: string
   surname: string
   email: string
-  organization: string
+  organisation: string
   profileIcon?: string
 }
diff --git a/libs/feature/catalog/src/lib/my-org/my-org.service.ts b/libs/feature/catalog/src/lib/my-org/my-org.service.ts
index 324884f5a7..8840cc3bba 100644
--- a/libs/feature/catalog/src/lib/my-org/my-org.service.ts
+++ b/libs/feature/catalog/src/lib/my-org/my-org.service.ts
@@ -27,12 +27,12 @@ export class MyOrgService {
       this.orgService.organisations$,
     ]).pipe(
       map(([user, allUsers, orgs]) => {
-        const orgName = user.organization
+        const orgName = user.organisation
         const org = orgs.find((org) => org.name === orgName)
         const logoUrl = org?.logoUrl?.toString()
         const recordCount = org?.recordCount
         const userList = allUsers.filter(
-          (user) => user.organization === orgName
+          (user) => user.organisation === orgName
         )
         const userCount = userList.length
         return {
diff --git a/libs/ui/elements/src/lib/related-record-card/related-record-card.component.html b/libs/ui/elements/src/lib/related-record-card/related-record-card.component.html
index 932c405b23..85fb920c14 100644
--- a/libs/ui/elements/src/lib/related-record-card/related-record-card.component.html
+++ b/libs/ui/elements/src/lib/related-record-card/related-record-card.component.html
@@ -1,5 +1,5 @@
 <a
-  class="w-72 h-96 overflow-hidden rounded-lg bg-white cursor-pointer block hover:-translate-y-2 duration-[180ms]"
+  [class]="classList"
   [routerLink]="['/dataset', record.uniqueIdentifier]"
   target="_blank"
 >
diff --git a/libs/ui/elements/src/lib/related-record-card/related-record-card.component.ts b/libs/ui/elements/src/lib/related-record-card/related-record-card.component.ts
index f883b3c31b..c166ea575d 100644
--- a/libs/ui/elements/src/lib/related-record-card/related-record-card.component.ts
+++ b/libs/ui/elements/src/lib/related-record-card/related-record-card.component.ts
@@ -1,4 +1,4 @@
-import { Component, ChangeDetectionStrategy, Input } from '@angular/core'
+import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
 import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
 
 @Component({
@@ -8,5 +8,26 @@ import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
 export class RelatedRecordCardComponent {
+  private readonly baseClasses: string
+
   @Input() record: CatalogRecord
+  @Input() extraClass = ''
+
+  constructor() {
+    this.baseClasses = [
+      'w-72',
+      'h-96',
+      'overflow-hidden',
+      'rounded-lg',
+      'bg-white',
+      'cursor-pointer',
+      'block',
+      'hover:-translate-y-2 ',
+      'duration-[180ms]',
+    ].join(' ')
+  }
+
+  get classList() {
+    return `${this.baseClasses} ${this.extraClass}`
+  }
 }
diff --git a/support-services/docker-entrypoint-initdb.d/dump b/support-services/docker-entrypoint-initdb.d/dump
index 0a433c68ec163548b3136110c93fbcc891a0406e..a163457194378dbd2b49441095f6050896fe75bc 100644
GIT binary patch
delta 677
zcmV;W0$TmZjU4Qb93fCgL`_fu4gdrQ0RaI30000O000002mk;801f~E000buA+;d^
zhN^%50RRAaoLy4OZrd;rJj-9Pw_Ga5PI_uDc3?Rv-~@rwB9~k!awQR=NP?s!_>=q(
zz4^zwlpI(nAdriF%+3szud;x;%01R9MD!@33+O}k@sgQzJpL)(ey3pk7RyUG)|82!
z8;sZTYF_4AUn_U>O5m;2I2&6ovp4j;5(s~<U8$7-iSSMU)+o#x)J|gfWP<x>*TD^J
zxYSsQ6Xe_L`y6kTZIwq6l{IiUpK7|f#)PVG3eziZjlmX8oKl<id@{VAGDyh|_O||N
z2=K(a7*gww1Pjc#Y?UFyJWm^Pnb0sW>5=Qak=0sakJ>snLgcdZywu2Q+x4vS6XSpF
zq1f!<X}g>AzRMmuLmPP;p*sKdaNu2n7?k+bovF$5%C5ObHd0`snZP!OVh(ekJ)cj}
zTW3jh(NS<dA#qF+_DYlY)7W#dpO1ad9=I<R!Y?DNcXpBoDgdWbkl_M^Z5=m95TrFK
zQ-icx2Z#-ipiFRNI~*-hg&GY`2!VgW&L&+F5}Yx%AM@WpMX*&xKO9Ka(}m!?m7O5B
zJytrsAR&>N{%8%}5RtUu3-rR4__dbS5(fi(B=i$PGqyuGwx!jy1+aB?KtDbzH}ayO
zSMkU)(iXXh>vBZQl@W}Dl1Yy*_so&+S7TVRtBKKtAGf!|FtGn-$jJ}3SS$wq0V4|_
z42K1*0fz;w0*3{x1BV5y1cwEz1-AvP2A)|@PvL>$k;*YlhoSQ$G(Dfj{qc76R4k>)
z1xxj*J8JUKQb4IKM2@Y{Se=S(?F8L8VGc6FrKf4jF>WZvvZ=>Cz-#~Ozk53DcDsM<
L+NXh+@&yOhKI=VU

delta 511
zcmV<b0RaB&jvUC193fCgL`_fu4gdrQ0RaI300002000005&!@I00;m8000AlA+;d^
zhN^#B0RRAaoK28RZi6rohS%m4-gSkQM-PxhAxR|?MWj_W*%&+!E5=5CkTY?I?zmWO
zNLwUiM*lza%_E*81EP#IRNPq5z_2r*4Z59>4A1^6xqOCT_@db>96T<qrV{MGJ)hcC
zh<|4>bquW=0h6-X3|&CCya0T5x!?t6fUkcZpd<%$2hlJv4^mKV)ygza@_czDhY@)>
zU#Gk|+Hwtr<x1kL?<)VN0s>XMC9>sONeMMbJ4)-i?<B281-$5Rs;b`vgAdeM6H<46
z;Q|n4HJAQinuZQB3p6l<X`mv$vvS3t1)-W|K*Y>xnhPM6axE$KIPo@1)+s)0chg|G
z7ii<8??`Kl%l=#AjJkk$^5P+!to+SOwW1oxFajy=BW#@|Q_K<_`_5|BD8F>#e9(8`
zXACQ(T=?6MWyd6)mc645)j0?JAqx^x_NOIjeAlV`mwzKs6#W1uiME`FsjLBqsjLEr
zsjLHssjLKtsjLOJsjLQ`Sx=Ag0r^PfNcoUydW5Fu)3`t0j-HC86uDrjK6OV;9$E@0
zwS~yB6&kBkv8|n;8z;;`M!57eZ8^pb#aK4=xCeOcfBkn)huv=X59^etewUU82iBYh
B;s^i$