@unvired/react-native-unvired-sdk 0.0.14 → 0.0.16
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/BuildNo.txt +1 -1
- package/dist/database/DatabaseManager.d.ts +1 -1
- package/dist/database/DatabaseManager.js +1 -1
- package/dist/database/services/DatabaseNative.d.ts +0 -1
- package/dist/database/services/DatabaseNative.js +35 -66
- package/dist/file-system/FileSystem.d.ts +57 -3
- package/dist/file-system/FileSystem.js +158 -5
- package/dist/file-system/FileSystem.types.d.ts +31 -1
- package/dist/file-system/RNFileEntry.d.ts +55 -0
- package/dist/file-system/RNFileEntry.js +179 -0
- package/dist/file-system/index.d.ts +1 -1
- package/dist/file-system/services/FileSystemNative.d.ts +7 -7
- package/dist/file-system/services/FileSystemNative.js +39 -27
- package/dist/file-system/services/FileSystemWeb.d.ts +4 -4
- package/dist/logger/services/LoggerNative.js +3 -3
- package/dist/logger/services/LoggerWindows.js +3 -3
- package/package.json +20 -12
- package/ts-core/PlatformInterface.ts +109 -0
- package/ts-core/ReactNativeFileEntry.ts +208 -0
- package/{example/USAGE_EXAMPLE.ts → ts-core/ReactNativePlatformAdapter.ts} +10 -9
- package/dist/file-system/BaseFileSystem.d.ts +0 -61
- package/dist/file-system/BaseFileSystem.js +0 -164
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import RNFS from 'react-native-fs';
|
|
2
|
+
export interface IDirectoryReader {
|
|
3
|
+
readEntries(callback: (entries: IFileEntry[]) => void, errorCallback: (error: any) => void): void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface IFileEntry {
|
|
7
|
+
fullPath: string;
|
|
8
|
+
nativeURL: string;
|
|
9
|
+
isDirectory?: boolean;
|
|
10
|
+
remove(callback: () => void, errorCallback: (error: any) => void): void;
|
|
11
|
+
removeRecursively(callback: () => void, errorCallback: (error: any) => void): void;
|
|
12
|
+
createReader(): IDirectoryReader;
|
|
13
|
+
getDirectory?(path: string, options: { create: boolean }, callback: (entry: IFileEntry) => void, errorCallback: (error: any) => void): void;
|
|
14
|
+
getFile?(path: string, options: { create: boolean }, callback: (entry: IFileEntry) => void, errorCallback: (error: any) => void): void;
|
|
15
|
+
file?(callback: (file: File) => void, errorCallback: (error: any) => void): void;
|
|
16
|
+
createWriter?(callback: (writer: any) => void, errorCallback: (error: any) => void): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* DirectoryReader implementation for React Native
|
|
20
|
+
* Wraps RNFS.readDir to match the Cordova DirectoryReader interface
|
|
21
|
+
*/
|
|
22
|
+
export class ReactNativeDirectoryReader implements IDirectoryReader {
|
|
23
|
+
private dirPath: string;
|
|
24
|
+
|
|
25
|
+
constructor(dirPath: string) {
|
|
26
|
+
this.dirPath = dirPath;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
readEntries(
|
|
30
|
+
callback: (entries: IFileEntry[]) => void,
|
|
31
|
+
errorCallback: (error: any) => void
|
|
32
|
+
): void {
|
|
33
|
+
RNFS.readDir(this.dirPath)
|
|
34
|
+
.then(items => {
|
|
35
|
+
const entries = items.map(item =>
|
|
36
|
+
new ReactNativeFileEntry(item.path, item.isDirectory())
|
|
37
|
+
);
|
|
38
|
+
callback(entries);
|
|
39
|
+
})
|
|
40
|
+
.catch(errorCallback);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* FileEntry implementation for React Native
|
|
46
|
+
* Wraps react-native-fs to match the Cordova FileEntry interface
|
|
47
|
+
*/
|
|
48
|
+
export class ReactNativeFileEntry implements IFileEntry {
|
|
49
|
+
fullPath: string;
|
|
50
|
+
nativeURL: string;
|
|
51
|
+
isDirectory?: boolean;
|
|
52
|
+
|
|
53
|
+
constructor(path: string, isDirectory: boolean = false) {
|
|
54
|
+
this.fullPath = path;
|
|
55
|
+
this.nativeURL = `file://${path}`;
|
|
56
|
+
this.isDirectory = isDirectory;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Remove a file or empty directory
|
|
61
|
+
*/
|
|
62
|
+
remove(callback: () => void, errorCallback: (error: any) => void): void {
|
|
63
|
+
RNFS.unlink(this.fullPath)
|
|
64
|
+
.then(() => callback())
|
|
65
|
+
.catch(errorCallback);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Remove a directory and all its contents recursively
|
|
70
|
+
*/
|
|
71
|
+
removeRecursively(callback: () => void, errorCallback: (error: any) => void): void {
|
|
72
|
+
// RNFS.unlink works recursively for directories
|
|
73
|
+
RNFS.unlink(this.fullPath)
|
|
74
|
+
.then(() => callback())
|
|
75
|
+
.catch(errorCallback);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Create a directory reader for reading directory contents
|
|
80
|
+
*/
|
|
81
|
+
createReader(): IDirectoryReader {
|
|
82
|
+
return new ReactNativeDirectoryReader(this.fullPath);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get or create a subdirectory
|
|
87
|
+
*/
|
|
88
|
+
getDirectory(
|
|
89
|
+
path: string,
|
|
90
|
+
options: { create: boolean },
|
|
91
|
+
callback: (entry: IFileEntry) => void,
|
|
92
|
+
errorCallback: (error: any) => void
|
|
93
|
+
): void {
|
|
94
|
+
const dirPath = `${this.fullPath}/${path}`;
|
|
95
|
+
|
|
96
|
+
RNFS.exists(dirPath)
|
|
97
|
+
.then(exists => {
|
|
98
|
+
if (exists) {
|
|
99
|
+
return RNFS.stat(dirPath).then(stats => {
|
|
100
|
+
if (stats.isDirectory()) {
|
|
101
|
+
callback(new ReactNativeFileEntry(dirPath, true));
|
|
102
|
+
} else {
|
|
103
|
+
errorCallback(new Error('Path exists but is not a directory'));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
} else if (options.create) {
|
|
107
|
+
return RNFS.mkdir(dirPath).then(() => {
|
|
108
|
+
callback(new ReactNativeFileEntry(dirPath, true));
|
|
109
|
+
});
|
|
110
|
+
} else {
|
|
111
|
+
errorCallback(new Error('Directory does not exist'));
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
.catch(errorCallback);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get or create a file
|
|
119
|
+
*/
|
|
120
|
+
getFile(
|
|
121
|
+
path: string,
|
|
122
|
+
options: { create: boolean },
|
|
123
|
+
callback: (entry: IFileEntry) => void,
|
|
124
|
+
errorCallback: (error: any) => void
|
|
125
|
+
): void {
|
|
126
|
+
const filePath = `${this.fullPath}/${path}`;
|
|
127
|
+
|
|
128
|
+
RNFS.exists(filePath)
|
|
129
|
+
.then(exists => {
|
|
130
|
+
if (exists) {
|
|
131
|
+
return RNFS.stat(filePath).then(stats => {
|
|
132
|
+
if (!stats.isDirectory()) {
|
|
133
|
+
callback(new ReactNativeFileEntry(filePath, false));
|
|
134
|
+
} else {
|
|
135
|
+
errorCallback(new Error('Path exists but is a directory'));
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
} else if (options.create) {
|
|
139
|
+
// Create empty file
|
|
140
|
+
return RNFS.writeFile(filePath, '', 'utf8').then(() => {
|
|
141
|
+
callback(new ReactNativeFileEntry(filePath, false));
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
errorCallback(new Error('File does not exist'));
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
.catch(errorCallback);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get file metadata
|
|
152
|
+
*/
|
|
153
|
+
file(callback: (file: File) => void, errorCallback: (error: any) => void): void {
|
|
154
|
+
RNFS.stat(this.fullPath)
|
|
155
|
+
.then(stats => {
|
|
156
|
+
// Create a File-like object with metadata
|
|
157
|
+
const fileObject: any = {
|
|
158
|
+
name: this.fullPath.split('/').pop() || '',
|
|
159
|
+
size: stats.size,
|
|
160
|
+
type: '', // RNFS doesn't provide MIME type directly
|
|
161
|
+
lastModified: new Date(stats.mtime).getTime(),
|
|
162
|
+
lastModifiedDate: new Date(stats.mtime),
|
|
163
|
+
path: this.fullPath,
|
|
164
|
+
};
|
|
165
|
+
callback(fileObject as File);
|
|
166
|
+
})
|
|
167
|
+
.catch(errorCallback);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Create a file writer for writing to the file
|
|
172
|
+
*/
|
|
173
|
+
createWriter(callback: (writer: any) => void, errorCallback: (error: any) => void): void {
|
|
174
|
+
// Create a FileWriter-like object
|
|
175
|
+
const writer = {
|
|
176
|
+
filePath: this.fullPath,
|
|
177
|
+
|
|
178
|
+
write: (data: string) => {
|
|
179
|
+
return RNFS.writeFile(this.fullPath, data, 'utf8');
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
append: (data: string) => {
|
|
183
|
+
return RNFS.appendFile(this.fullPath, data, 'utf8');
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
truncate: (size: number) => {
|
|
187
|
+
// Read file, truncate content, and write back
|
|
188
|
+
return RNFS.readFile(this.fullPath, 'utf8')
|
|
189
|
+
.then(content => {
|
|
190
|
+
const truncated = content.substring(0, size);
|
|
191
|
+
return RNFS.writeFile(this.fullPath, truncated, 'utf8');
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
seek: (offset: number) => {
|
|
196
|
+
// Not directly supported in RNFS
|
|
197
|
+
// This would need to be implemented with read/write operations
|
|
198
|
+
return Promise.resolve();
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
callback(writer);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
errorCallback(error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { PlatformInterface, IDeviceInfo, IFileEntry, IDatabaseAdapter, IPushNotificationAdapter, ILoggerAdapter, DatabaseType } from './PlatformInterface';
|
|
2
|
-
import { logger, LogLevel } from '
|
|
2
|
+
import { logger, LogLevel } from '../src/logger';
|
|
3
|
+
import { RNFileEntry } from '../src/file-system/RNFileEntry';
|
|
4
|
+
import { FileSystem } from '../src/file-system/FileSystem';
|
|
3
5
|
export class ReactNativePlatformAdapter implements PlatformInterface {
|
|
4
6
|
|
|
5
7
|
getDeviceInfo(): IDeviceInfo {
|
|
@@ -24,22 +26,20 @@ export class ReactNativePlatformAdapter implements PlatformInterface {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
getDocumentDirectory(): string {
|
|
27
|
-
//
|
|
28
|
-
return
|
|
29
|
+
// Return the document directory path for React Native
|
|
30
|
+
return FileSystem.getDocumentDirectory();
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
resolveLocalFileSystemURL(url: string): Promise<IFileEntry> {
|
|
32
|
-
|
|
33
|
-
return Promise.resolve({} as IFileEntry);
|
|
34
|
+
return FileSystem.resolveLocalFileSystemURL(url);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
async getFolderBasedOnUserId(userId: string): Promise<string> {
|
|
37
|
-
|
|
38
|
-
return "";
|
|
38
|
+
return FileSystem.getFolderBasedOnUserId(userId);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
async deleteUserFolder(userId: string): Promise<void> {
|
|
42
|
-
|
|
42
|
+
return FileSystem.deleteUserFolder(userId);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
getDatabaseAdapter(): IDatabaseAdapter {
|
|
@@ -139,7 +139,8 @@ export class ReactNativePlatformAdapter implements PlatformInterface {
|
|
|
139
139
|
},
|
|
140
140
|
getBackupLogFileContent: async () => {
|
|
141
141
|
// TODO: Implement backup log file content retrieval
|
|
142
|
-
|
|
142
|
+
const content = await logger.getBackupLogFileContent();
|
|
143
|
+
return content || '';
|
|
143
144
|
},
|
|
144
145
|
clearLogFile: async () => {
|
|
145
146
|
// TODO: Implement log file clearing
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { IFileEntry } from './FileSystem.types';
|
|
2
|
-
/**
|
|
3
|
-
* Base File System Class
|
|
4
|
-
* Handles file system operations for React Native
|
|
5
|
-
* - iOS/Android/Windows: Uses @dr.pogodin/react-native-fs
|
|
6
|
-
* - Web: Limited functionality (not supported)
|
|
7
|
-
*/
|
|
8
|
-
export declare class BaseFileSystem {
|
|
9
|
-
/**
|
|
10
|
-
* Get document directory path
|
|
11
|
-
*/
|
|
12
|
-
static getDocumentDirectory(): string;
|
|
13
|
-
/**
|
|
14
|
-
* Resolve local file system URL
|
|
15
|
-
*/
|
|
16
|
-
static resolveLocalFileSystemURL(url: string): Promise<IFileEntry>;
|
|
17
|
-
/**
|
|
18
|
-
* Get folder based on user ID
|
|
19
|
-
*/
|
|
20
|
-
static getFolderBasedOnUserId(userId: string): Promise<string>;
|
|
21
|
-
/**
|
|
22
|
-
* Delete user folder
|
|
23
|
-
*/
|
|
24
|
-
static deleteUserFolder(userId: string): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Create directory
|
|
27
|
-
*/
|
|
28
|
-
static createDirectory(path: string): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
* Read file content
|
|
31
|
-
*/
|
|
32
|
-
static readFile(path: string, encoding?: string): Promise<string>;
|
|
33
|
-
/**
|
|
34
|
-
* Write file content
|
|
35
|
-
*/
|
|
36
|
-
static writeFile(path: string, content: string, encoding?: string): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* Delete file
|
|
39
|
-
*/
|
|
40
|
-
static deleteFile(path: string): Promise<void>;
|
|
41
|
-
/**
|
|
42
|
-
* Check if file exists
|
|
43
|
-
*/
|
|
44
|
-
static exists(path: string): Promise<boolean>;
|
|
45
|
-
/**
|
|
46
|
-
* Get file info
|
|
47
|
-
*/
|
|
48
|
-
static stat(path: string): Promise<any>;
|
|
49
|
-
/**
|
|
50
|
-
* List directory contents
|
|
51
|
-
*/
|
|
52
|
-
static readDir(path: string): Promise<any[]>;
|
|
53
|
-
/**
|
|
54
|
-
* Copy file
|
|
55
|
-
*/
|
|
56
|
-
static copyFile(source: string, destination: string): Promise<void>;
|
|
57
|
-
/**
|
|
58
|
-
* Move file
|
|
59
|
-
*/
|
|
60
|
-
static moveFile(source: string, destination: string): Promise<void>;
|
|
61
|
-
}
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
// BaseFileSystem.ts
|
|
2
|
-
// Base file system implementation
|
|
3
|
-
import { Platform } from 'react-native';
|
|
4
|
-
import { FileSystemNative } from './services/FileSystemNative';
|
|
5
|
-
import { FileSystemWeb } from './services/FileSystemWeb';
|
|
6
|
-
// Select file system implementation based on platform
|
|
7
|
-
const fsImpl = Platform.OS === 'web' ? new FileSystemWeb() : new FileSystemNative();
|
|
8
|
-
/**
|
|
9
|
-
* Base File System Class
|
|
10
|
-
* Handles file system operations for React Native
|
|
11
|
-
* - iOS/Android/Windows: Uses @dr.pogodin/react-native-fs
|
|
12
|
-
* - Web: Limited functionality (not supported)
|
|
13
|
-
*/
|
|
14
|
-
export class BaseFileSystem {
|
|
15
|
-
/**
|
|
16
|
-
* Get document directory path
|
|
17
|
-
*/
|
|
18
|
-
static getDocumentDirectory() {
|
|
19
|
-
return fsImpl.getDocumentDirectory();
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Resolve local file system URL
|
|
23
|
-
*/
|
|
24
|
-
static async resolveLocalFileSystemURL(url) {
|
|
25
|
-
try {
|
|
26
|
-
return await fsImpl.resolveLocalFileSystemURL(url);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.error('Error resolving file system URL:', error);
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Get folder based on user ID
|
|
35
|
-
*/
|
|
36
|
-
static async getFolderBasedOnUserId(userId) {
|
|
37
|
-
try {
|
|
38
|
-
return await fsImpl.getFolderBasedOnUserId(userId);
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
console.error('Error getting user folder:', error);
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Delete user folder
|
|
47
|
-
*/
|
|
48
|
-
static async deleteUserFolder(userId) {
|
|
49
|
-
try {
|
|
50
|
-
await fsImpl.deleteUserFolder(userId);
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
console.error('Error deleting user folder:', error);
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Create directory
|
|
59
|
-
*/
|
|
60
|
-
static async createDirectory(path) {
|
|
61
|
-
try {
|
|
62
|
-
await fsImpl.createDirectory(path);
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
console.error('Error creating directory:', error);
|
|
66
|
-
throw error;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Read file content
|
|
71
|
-
*/
|
|
72
|
-
static async readFile(path, encoding = 'utf8') {
|
|
73
|
-
try {
|
|
74
|
-
return await fsImpl.readFile(path, encoding);
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
console.error('Error reading file:', error);
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Write file content
|
|
83
|
-
*/
|
|
84
|
-
static async writeFile(path, content, encoding = 'utf8') {
|
|
85
|
-
try {
|
|
86
|
-
await fsImpl.writeFile(path, content, encoding);
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
console.error('Error writing file:', error);
|
|
90
|
-
throw error;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Delete file
|
|
95
|
-
*/
|
|
96
|
-
static async deleteFile(path) {
|
|
97
|
-
try {
|
|
98
|
-
await fsImpl.deleteFile(path);
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
console.error('Error deleting file:', error);
|
|
102
|
-
throw error;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Check if file exists
|
|
107
|
-
*/
|
|
108
|
-
static async exists(path) {
|
|
109
|
-
try {
|
|
110
|
-
return await fsImpl.exists(path);
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Get file info
|
|
118
|
-
*/
|
|
119
|
-
static async stat(path) {
|
|
120
|
-
try {
|
|
121
|
-
return await fsImpl.stat(path);
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
console.error('Error getting file stats:', error);
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* List directory contents
|
|
130
|
-
*/
|
|
131
|
-
static async readDir(path) {
|
|
132
|
-
try {
|
|
133
|
-
return await fsImpl.readDir(path);
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
console.error('Error reading directory:', error);
|
|
137
|
-
throw error;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Copy file
|
|
142
|
-
*/
|
|
143
|
-
static async copyFile(source, destination) {
|
|
144
|
-
try {
|
|
145
|
-
await fsImpl.copyFile(source, destination);
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
console.error('Error copying file:', error);
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Move file
|
|
154
|
-
*/
|
|
155
|
-
static async moveFile(source, destination) {
|
|
156
|
-
try {
|
|
157
|
-
await fsImpl.moveFile(source, destination);
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
console.error('Error moving file:', error);
|
|
161
|
-
throw error;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|