@sneat/space-services 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.js +8 -0
- package/esm2022/index.js.map +1 -0
- package/esm2022/lib/components/with-space-input.directive.js +37 -0
- package/esm2022/lib/components/with-space-input.directive.js.map +1 -0
- package/esm2022/lib/services/space-context.service.js +26 -0
- package/esm2022/lib/services/space-context.service.js.map +1 -0
- package/esm2022/lib/services/space-item.service.js +132 -0
- package/esm2022/lib/services/space-item.service.js.map +1 -0
- package/esm2022/lib/services/space-module.service.js +35 -0
- package/esm2022/lib/services/space-module.service.js.map +1 -0
- package/esm2022/lib/services/space-nav.service.js +97 -0
- package/esm2022/lib/services/space-nav.service.js.map +1 -0
- package/esm2022/lib/services/space-service.module.js +15 -0
- package/esm2022/lib/services/space-service.module.js.map +1 -0
- package/esm2022/lib/services/space.service.js +209 -0
- package/esm2022/lib/services/space.service.js.map +1 -0
- package/esm2022/sneat-space-services.js +5 -0
- package/esm2022/sneat-space-services.js.map +1 -0
- package/{src/index.ts → index.d.ts} +0 -1
- package/lib/components/with-space-input.directive.d.ts +20 -0
- package/lib/services/space-context.service.d.ts +9 -0
- package/lib/services/space-item.service.d.ts +43 -0
- package/lib/services/space-module.service.d.ts +10 -0
- package/lib/services/space-nav.service.d.ts +32 -0
- package/lib/services/space-service.module.d.ts +6 -0
- package/lib/services/space.service.d.ts +33 -0
- package/package.json +14 -2
- package/sneat-space-services.d.ts +5 -0
- package/tsconfig.lib.prod.tsbuildinfo +1 -0
- package/eslint.config.js +0 -7
- package/ng-package.json +0 -7
- package/project.json +0 -38
- package/src/lib/components/with-space-input.directive.spec.ts +0 -41
- package/src/lib/components/with-space-input.directive.ts +0 -40
- package/src/lib/services/space-context.service.spec.ts +0 -16
- package/src/lib/services/space-context.service.ts +0 -45
- package/src/lib/services/space-item.service.spec.ts +0 -179
- package/src/lib/services/space-item.service.ts +0 -308
- package/src/lib/services/space-module.service.spec.ts +0 -48
- package/src/lib/services/space-module.service.ts +0 -69
- package/src/lib/services/space-nav-service.service.spec.ts +0 -32
- package/src/lib/services/space-nav.service.ts +0 -175
- package/src/lib/services/space-service.module.spec.ts +0 -46
- package/src/lib/services/space-service.module.ts +0 -7
- package/src/lib/services/space.service.spec.ts +0 -44
- package/src/lib/services/space.service.ts +0 -291
- package/src/test-setup.ts +0 -3
- package/tsconfig.json +0 -13
- package/tsconfig.lib.json +0 -19
- package/tsconfig.lib.prod.json +0 -7
- package/tsconfig.spec.json +0 -31
- package/vite.config.mts +0 -10
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import { Injector } from '@angular/core';
|
|
3
|
-
import { Firestore, collection } from '@angular/fire/firestore';
|
|
4
|
-
import { SpaceModuleService } from './space-module.service';
|
|
5
|
-
|
|
6
|
-
// Mock collection function
|
|
7
|
-
vi.mock('@angular/fire/firestore', async () => {
|
|
8
|
-
const actual = await vi.importActual('@angular/fire/firestore');
|
|
9
|
-
return {
|
|
10
|
-
...actual,
|
|
11
|
-
collection: vi.fn(() => ({ id: 'mock-collection' })),
|
|
12
|
-
};
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
class TestSpaceModuleService extends SpaceModuleService<{ title: string }> {
|
|
16
|
-
constructor(injector: Injector, afs: Firestore) {
|
|
17
|
-
super(injector, 'test-module', afs);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe('SpaceModuleService', () => {
|
|
22
|
-
let service: TestSpaceModuleService;
|
|
23
|
-
let mockFirestore: Firestore;
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
mockFirestore = {
|
|
27
|
-
type: 'Firestore',
|
|
28
|
-
toJSON: () => ({}),
|
|
29
|
-
} as unknown as Firestore;
|
|
30
|
-
|
|
31
|
-
vi.mocked(collection).mockReturnValue({ id: 'spaces' } as unknown);
|
|
32
|
-
|
|
33
|
-
const injector = TestBed.inject(Injector);
|
|
34
|
-
service = new TestSpaceModuleService(injector, mockFirestore);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should be created', () => {
|
|
38
|
-
expect(service).toBeTruthy();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should have correct moduleID', () => {
|
|
42
|
-
expect(service.moduleID).toBe('test-module');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should have correct collectionName', () => {
|
|
46
|
-
expect(service.collectionName).toBe('ext');
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { Injector, runInInjectionContext } from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
collection,
|
|
4
|
-
CollectionReference,
|
|
5
|
-
Firestore as AngularFirestore,
|
|
6
|
-
} from '@angular/fire/firestore';
|
|
7
|
-
import { SneatApiService } from '@sneat/api';
|
|
8
|
-
import { IIdAndBrief, IIdAndOptionalDbo } from '@sneat/core';
|
|
9
|
-
import { Observable } from 'rxjs';
|
|
10
|
-
import { map } from 'rxjs/operators';
|
|
11
|
-
import { ModuleSpaceItemService } from './space-item.service';
|
|
12
|
-
|
|
13
|
-
// import firebase from "firebase/compat";
|
|
14
|
-
// import Item = firebase.analytics.Item;
|
|
15
|
-
|
|
16
|
-
export abstract class SpaceModuleService<Dbo> extends ModuleSpaceItemService<
|
|
17
|
-
Dbo,
|
|
18
|
-
Dbo
|
|
19
|
-
> {
|
|
20
|
-
// protected readonly sfs: SneatFirestoreService<Brief, Dto>;
|
|
21
|
-
protected constructor(
|
|
22
|
-
injector: Injector,
|
|
23
|
-
moduleID: string,
|
|
24
|
-
afs: AngularFirestore,
|
|
25
|
-
) {
|
|
26
|
-
// this.sfs = new SneatFirestoreService<Brief, Dto>(collectionName, afs);
|
|
27
|
-
super(
|
|
28
|
-
injector,
|
|
29
|
-
moduleID,
|
|
30
|
-
'ext',
|
|
31
|
-
afs,
|
|
32
|
-
undefined as unknown as SneatApiService,
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
watchSpaceModuleRecord(spaceID: string): Observable<IIdAndOptionalDbo<Dbo>> {
|
|
37
|
-
return runInInjectionContext(this.injector, () => {
|
|
38
|
-
const collectionRef = collection(
|
|
39
|
-
this.spacesCollection,
|
|
40
|
-
spaceID,
|
|
41
|
-
'ext',
|
|
42
|
-
) as CollectionReference<Dbo>;
|
|
43
|
-
// if (this.moduleID === 'trackus') {
|
|
44
|
-
// return throwError(() => new Error('test error'));
|
|
45
|
-
// }
|
|
46
|
-
return this.sfs
|
|
47
|
-
.watchByID<Dbo>(collectionRef, this.moduleID)
|
|
48
|
-
.pipe
|
|
49
|
-
// tap((o) => console.log(`${logPrefix} =>`, o)),
|
|
50
|
-
();
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
watchBriefs<ItemBrief>(
|
|
55
|
-
spaceID: string,
|
|
56
|
-
getBriefs: (dto?: Dbo) => Readonly<Record<string, ItemBrief>>,
|
|
57
|
-
): Observable<IIdAndBrief<ItemBrief>[]> {
|
|
58
|
-
const o = this.watchSpaceModuleRecord(spaceID);
|
|
59
|
-
return o.pipe(
|
|
60
|
-
map((teamModule) => {
|
|
61
|
-
const briefs = getBriefs(teamModule?.dbo || undefined);
|
|
62
|
-
const items: IIdAndBrief<ItemBrief>[] = briefs
|
|
63
|
-
? Object.keys(briefs).map((id) => ({ id, brief: briefs[id] }))
|
|
64
|
-
: [];
|
|
65
|
-
return items;
|
|
66
|
-
}),
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import { provideRouter } from '@angular/router';
|
|
3
|
-
import { SpaceNavService } from './space-nav.service';
|
|
4
|
-
import { ErrorLogger } from '@sneat/core';
|
|
5
|
-
import { AnalyticsService } from '@sneat/core';
|
|
6
|
-
import { NavController } from '@ionic/angular';
|
|
7
|
-
|
|
8
|
-
describe('SpaceNavService', () => {
|
|
9
|
-
beforeEach(() =>
|
|
10
|
-
TestBed.configureTestingModule({
|
|
11
|
-
providers: [
|
|
12
|
-
SpaceNavService,
|
|
13
|
-
provideRouter([]),
|
|
14
|
-
{ provide: ErrorLogger, useValue: { logError: vi.fn() } },
|
|
15
|
-
{ provide: AnalyticsService, useValue: { logEvent: vi.fn() } },
|
|
16
|
-
{
|
|
17
|
-
provide: NavController,
|
|
18
|
-
useValue: {
|
|
19
|
-
navigateRoot: vi.fn().mockResolvedValue(true),
|
|
20
|
-
navigateForward: vi.fn().mockResolvedValue(true),
|
|
21
|
-
navigateBack: vi.fn().mockResolvedValue(true),
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
}),
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
it('should be created', () => {
|
|
29
|
-
const service: SpaceNavService = TestBed.inject(SpaceNavService);
|
|
30
|
-
expect(service).toBeTruthy();
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { Params } from '@angular/router';
|
|
3
|
-
import { NavController } from '@ionic/angular';
|
|
4
|
-
import { AnalyticsService, IAnalyticsService, IIdAndBrief, ISpaceRef } from '@sneat/core';
|
|
5
|
-
import { IMemberBrief } from '@sneat/contactus-core';
|
|
6
|
-
|
|
7
|
-
type NavigationOptions = NonNullable<
|
|
8
|
-
Parameters<NavController['navigateRoot']>[1]
|
|
9
|
-
>;
|
|
10
|
-
import { IRecord } from '@sneat/data';
|
|
11
|
-
import { ISpaceDbo } from '@sneat/dto';
|
|
12
|
-
import { ErrorLogger, IErrorLogger } from '@sneat/core';
|
|
13
|
-
import { ISpaceContext } from '@sneat/space-models';
|
|
14
|
-
|
|
15
|
-
export type ScrumPageTab = 'team' | 'my' | 'risks' | 'qna';
|
|
16
|
-
|
|
17
|
-
@Injectable({
|
|
18
|
-
providedIn: 'root',
|
|
19
|
-
})
|
|
20
|
-
export class SpaceNavService {
|
|
21
|
-
private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);
|
|
22
|
-
private readonly navController = inject(NavController);
|
|
23
|
-
private readonly analyticsService =
|
|
24
|
-
inject<IAnalyticsService>(AnalyticsService);
|
|
25
|
-
|
|
26
|
-
public navigateToSpaces(animationDirection?: 'forward' | 'back'): void {
|
|
27
|
-
this.analyticsService.logEvent('navigateToTeams');
|
|
28
|
-
this.navController
|
|
29
|
-
.navigateRoot('spaces', { animationDirection })
|
|
30
|
-
.catch((err) =>
|
|
31
|
-
this.errorLogger.logError(err, 'Failed to navigate to teams page'),
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public navigateToLogin(options?: {
|
|
36
|
-
returnTo?: string;
|
|
37
|
-
queryParams?: Params;
|
|
38
|
-
// fragment?: string;
|
|
39
|
-
}): void {
|
|
40
|
-
|
|
41
|
-
// Do not log `returnTo` as it might holds sensitive info
|
|
42
|
-
this.analyticsService.logEvent('navigateToLogin');
|
|
43
|
-
|
|
44
|
-
const navOptions: NavigationOptions = {
|
|
45
|
-
queryParams: options?.queryParams,
|
|
46
|
-
animationDirection: 'back',
|
|
47
|
-
};
|
|
48
|
-
if (options?.returnTo) {
|
|
49
|
-
navOptions.fragment = options.returnTo;
|
|
50
|
-
}
|
|
51
|
-
this.navController
|
|
52
|
-
.navigateRoot('login', navOptions)
|
|
53
|
-
.catch((err) =>
|
|
54
|
-
this.errorLogger.logError(err, 'Failed to navigate to login page'),
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public navigateToUserProfile(): void {
|
|
59
|
-
this.analyticsService.logEvent('navigateToUserProfile');
|
|
60
|
-
this.navController
|
|
61
|
-
.navigateRoot('user-profile')
|
|
62
|
-
.catch((err) =>
|
|
63
|
-
this.errorLogger.logError(err, 'Failed to naviage to user profile'),
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public navigateToSpace(
|
|
68
|
-
space: ISpaceContext,
|
|
69
|
-
animationDirection?: 'forward' | 'back',
|
|
70
|
-
): Promise<boolean> {
|
|
71
|
-
this.analyticsService.logEvent('navigateToSpace', { spaceID: space.id });
|
|
72
|
-
const url = `space/${space.type || space.brief?.type}/${space.id}`;
|
|
73
|
-
return new Promise<boolean>((resolve, reject) => {
|
|
74
|
-
this.navController
|
|
75
|
-
.navigateRoot(url, {
|
|
76
|
-
state: { space },
|
|
77
|
-
animationDirection,
|
|
78
|
-
})
|
|
79
|
-
.then(resolve)
|
|
80
|
-
.catch((err) => {
|
|
81
|
-
this.errorLogger.logError(
|
|
82
|
-
err,
|
|
83
|
-
'Failed to navigate to team overview page with URL: ' + url,
|
|
84
|
-
);
|
|
85
|
-
reject(err);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public navigateToMember(
|
|
91
|
-
space: ISpaceContext,
|
|
92
|
-
memberInfo: IIdAndBrief<IMemberBrief>,
|
|
93
|
-
): void {
|
|
94
|
-
const id = `${space.id}:${memberInfo.id}`;
|
|
95
|
-
this.navForward(
|
|
96
|
-
this.navController,
|
|
97
|
-
'member',
|
|
98
|
-
{
|
|
99
|
-
queryParams: { id },
|
|
100
|
-
state: { space, memberInfo },
|
|
101
|
-
},
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
public navigateToAddMetric = (
|
|
106
|
-
navController: NavController,
|
|
107
|
-
team: IRecord<ISpaceDbo>,
|
|
108
|
-
): void =>
|
|
109
|
-
this.navToSpacePage(
|
|
110
|
-
navController,
|
|
111
|
-
team,
|
|
112
|
-
'add-metric',
|
|
113
|
-
'navigateToAddMetric',
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
public navigateBackToSpacePage(
|
|
117
|
-
space: ISpaceContext,
|
|
118
|
-
page: string,
|
|
119
|
-
navOptions: NavigationOptions = {},
|
|
120
|
-
): Promise<boolean> {
|
|
121
|
-
navOptions.animationDirection = 'back';
|
|
122
|
-
return this.navigateToSpacePage(space, page, navOptions);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public navigateForwardToSpacePage(
|
|
126
|
-
space: ISpaceContext,
|
|
127
|
-
page: string,
|
|
128
|
-
navOptions: NavigationOptions = {},
|
|
129
|
-
): Promise<boolean> {
|
|
130
|
-
navOptions.animationDirection = 'forward';
|
|
131
|
-
return this.navigateToSpacePage(space, page, navOptions);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private navigateToSpacePage(
|
|
135
|
-
space: ISpaceContext,
|
|
136
|
-
page: string,
|
|
137
|
-
navOptions: NavigationOptions,
|
|
138
|
-
): Promise<boolean> {
|
|
139
|
-
const url = `space/${space?.type}/${space?.id}/${page}`;
|
|
140
|
-
const state = navOptions.state || {};
|
|
141
|
-
navOptions = { ...navOptions, state: { space, ...state } };
|
|
142
|
-
return this.navController.navigateForward(url, navOptions);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private navForward(
|
|
146
|
-
navController: NavController,
|
|
147
|
-
url: string,
|
|
148
|
-
navOptions: NavigationOptions,
|
|
149
|
-
// _analyticsEvent: { name: string; params?: Record<string, unknown> },
|
|
150
|
-
): void {
|
|
151
|
-
navController = navController || this.navController;
|
|
152
|
-
// this.analyticsService.logEvent(analyticsEvent.name, analyticsEvent.params);
|
|
153
|
-
navController
|
|
154
|
-
.navigateForward(url, navOptions)
|
|
155
|
-
.catch((err) =>
|
|
156
|
-
this.errorLogger.logError(err, 'Failed to navigate to: ' + url),
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private navToSpacePage = (
|
|
161
|
-
navController: NavController,
|
|
162
|
-
space: ISpaceRef,
|
|
163
|
-
url: string,
|
|
164
|
-
eventName: string,
|
|
165
|
-
params?: Record<string, unknown>,
|
|
166
|
-
): void => {
|
|
167
|
-
params = { ...params, space: space.id };
|
|
168
|
-
this.analyticsService.logEvent(eventName, params);
|
|
169
|
-
this.navForward(
|
|
170
|
-
navController,
|
|
171
|
-
url,
|
|
172
|
-
{ queryParams: params, state: { space } },
|
|
173
|
-
);
|
|
174
|
-
};
|
|
175
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import { Firestore } from '@angular/fire/firestore';
|
|
3
|
-
import { SneatApiService } from '@sneat/api';
|
|
4
|
-
import { SneatAuthStateService, SneatUserService } from '@sneat/auth-core';
|
|
5
|
-
import { ErrorLogger } from '@sneat/core';
|
|
6
|
-
import { of } from 'rxjs';
|
|
7
|
-
import { SpaceServiceModule } from './space-service.module';
|
|
8
|
-
import { SpaceService } from './space.service';
|
|
9
|
-
|
|
10
|
-
describe('SpaceServiceModule', () => {
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
TestBed.configureTestingModule({
|
|
13
|
-
imports: [SpaceServiceModule],
|
|
14
|
-
providers: [
|
|
15
|
-
{
|
|
16
|
-
provide: ErrorLogger,
|
|
17
|
-
useValue: { logError: vi.fn(), logErrorHandler: () => vi.fn() },
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
provide: Firestore,
|
|
21
|
-
useValue: { type: 'Firestore', toJSON: () => ({}) },
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
provide: SneatUserService,
|
|
25
|
-
useValue: { userState: of({ record: undefined }) },
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
provide: SneatApiService,
|
|
29
|
-
useValue: { post: vi.fn(), get: vi.fn() },
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
provide: SneatAuthStateService,
|
|
33
|
-
useValue: {
|
|
34
|
-
authStatus: of('notAuthenticated'),
|
|
35
|
-
authState: of({ status: 'notAuthenticated' }),
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should provide SpaceService', () => {
|
|
43
|
-
const service = TestBed.inject(SpaceService);
|
|
44
|
-
expect(service).toBeTruthy();
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { TestBed } from '@angular/core/testing';
|
|
2
|
-
import { Firestore } from '@angular/fire/firestore';
|
|
3
|
-
import { SneatApiService } from '@sneat/api';
|
|
4
|
-
import { SneatAuthStateService, SneatUserService } from '@sneat/auth-core';
|
|
5
|
-
import { ErrorLogger } from '@sneat/core';
|
|
6
|
-
import { of } from 'rxjs';
|
|
7
|
-
import { SpaceService } from './space.service';
|
|
8
|
-
|
|
9
|
-
describe('SpaceService', () => {
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
TestBed.configureTestingModule({
|
|
12
|
-
providers: [
|
|
13
|
-
SpaceService,
|
|
14
|
-
{
|
|
15
|
-
provide: ErrorLogger,
|
|
16
|
-
useValue: { logError: vi.fn(), logErrorHandler: () => vi.fn() },
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
provide: Firestore,
|
|
20
|
-
useValue: { type: 'Firestore', toJSON: () => ({}) },
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
provide: SneatUserService,
|
|
24
|
-
useValue: { userState: of({ record: undefined }) },
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
provide: SneatApiService,
|
|
28
|
-
useValue: { post: vi.fn(), get: vi.fn() },
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
provide: SneatAuthStateService,
|
|
32
|
-
useValue: {
|
|
33
|
-
authStatus: of('notAuthenticated'),
|
|
34
|
-
authState: of({ status: 'notAuthenticated' }),
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should be created', () => {
|
|
42
|
-
expect(TestBed.inject(SpaceService)).toBeTruthy();
|
|
43
|
-
});
|
|
44
|
-
});
|