@openbrf/plugin-sdk 1.0.0 → 1.4.0

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.
Files changed (104) hide show
  1. package/README.md +95 -0
  2. package/dist/abort-signal.d.ts +23 -0
  3. package/dist/abort-signal.d.ts.map +1 -0
  4. package/dist/abort-signal.js +2 -0
  5. package/dist/abort-signal.js.map +1 -0
  6. package/dist/action-refusal.d.ts +101 -0
  7. package/dist/action-refusal.d.ts.map +1 -0
  8. package/dist/action-refusal.js +96 -0
  9. package/dist/action-refusal.js.map +1 -0
  10. package/dist/action-schema.d.ts.map +1 -1
  11. package/dist/action-schema.js +4 -1
  12. package/dist/action-schema.js.map +1 -1
  13. package/dist/actions.d.ts +94 -6
  14. package/dist/actions.d.ts.map +1 -1
  15. package/dist/actions.js.map +1 -1
  16. package/dist/blocks.d.ts +310 -0
  17. package/dist/blocks.d.ts.map +1 -0
  18. package/dist/blocks.js +185 -0
  19. package/dist/blocks.js.map +1 -0
  20. package/dist/catalog.d.ts +1092 -41
  21. package/dist/catalog.d.ts.map +1 -1
  22. package/dist/catalog.js +472 -15
  23. package/dist/catalog.js.map +1 -1
  24. package/dist/entitlements.d.ts +117 -0
  25. package/dist/entitlements.d.ts.map +1 -0
  26. package/dist/entitlements.js +62 -0
  27. package/dist/entitlements.js.map +1 -0
  28. package/dist/extensions.d.ts +183 -0
  29. package/dist/extensions.d.ts.map +1 -0
  30. package/dist/extensions.js +67 -0
  31. package/dist/extensions.js.map +1 -0
  32. package/dist/finances.d.ts +294 -0
  33. package/dist/finances.d.ts.map +1 -0
  34. package/dist/finances.js +56 -0
  35. package/dist/finances.js.map +1 -0
  36. package/dist/findings.d.ts +92 -1
  37. package/dist/findings.d.ts.map +1 -1
  38. package/dist/findings.js +91 -0
  39. package/dist/findings.js.map +1 -1
  40. package/dist/host.d.ts +729 -4
  41. package/dist/host.d.ts.map +1 -1
  42. package/dist/host.js +54 -0
  43. package/dist/host.js.map +1 -1
  44. package/dist/imports.d.ts +104 -0
  45. package/dist/imports.d.ts.map +1 -0
  46. package/dist/imports.js +70 -0
  47. package/dist/imports.js.map +1 -0
  48. package/dist/index.d.ts +17 -7
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +15 -6
  51. package/dist/index.js.map +1 -1
  52. package/dist/localized-text.d.ts +18 -0
  53. package/dist/localized-text.d.ts.map +1 -0
  54. package/dist/localized-text.js +17 -0
  55. package/dist/localized-text.js.map +1 -0
  56. package/dist/manifest.d.ts +859 -0
  57. package/dist/manifest.d.ts.map +1 -1
  58. package/dist/manifest.js +957 -12
  59. package/dist/manifest.js.map +1 -1
  60. package/dist/package-check.d.ts.map +1 -1
  61. package/dist/package-check.js +9 -1
  62. package/dist/package-check.js.map +1 -1
  63. package/dist/permissions.d.ts +170 -11
  64. package/dist/permissions.d.ts.map +1 -1
  65. package/dist/permissions.js +210 -2
  66. package/dist/permissions.js.map +1 -1
  67. package/dist/recipients.d.ts +139 -0
  68. package/dist/recipients.d.ts.map +1 -0
  69. package/dist/recipients.js +223 -0
  70. package/dist/recipients.js.map +1 -0
  71. package/dist/records.d.ts +130 -0
  72. package/dist/records.d.ts.map +1 -0
  73. package/dist/records.js +85 -0
  74. package/dist/records.js.map +1 -0
  75. package/dist/require-capability.d.ts +37 -0
  76. package/dist/require-capability.d.ts.map +1 -0
  77. package/dist/require-capability.js +88 -0
  78. package/dist/require-capability.js.map +1 -0
  79. package/dist/settings-schema.d.ts +35 -0
  80. package/dist/settings-schema.d.ts.map +1 -1
  81. package/dist/settings-schema.js +55 -2
  82. package/dist/settings-schema.js.map +1 -1
  83. package/package.json +4 -4
  84. package/src/abort-signal.ts +22 -0
  85. package/src/action-refusal.ts +178 -0
  86. package/src/action-schema.ts +4 -1
  87. package/src/actions.ts +103 -6
  88. package/src/blocks.ts +289 -0
  89. package/src/catalog.ts +630 -72
  90. package/src/entitlements.ts +150 -0
  91. package/src/extensions.ts +212 -0
  92. package/src/finances.ts +317 -0
  93. package/src/findings.ts +94 -0
  94. package/src/host.ts +768 -4
  95. package/src/imports.ts +135 -0
  96. package/src/index.ts +209 -0
  97. package/src/localized-text.ts +19 -0
  98. package/src/manifest.ts +1231 -12
  99. package/src/package-check.ts +15 -0
  100. package/src/permissions.ts +223 -3
  101. package/src/recipients.ts +294 -0
  102. package/src/records.ts +172 -0
  103. package/src/require-capability.ts +106 -0
  104. package/src/settings-schema.ts +64 -2
package/src/imports.ts ADDED
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Handing a member list to the board (ADR 0043).
3
+ *
4
+ * A plugin that brings the association's member list in from elsewhere - a
5
+ * file mailed to an address, an export fetched from the economic manager's
6
+ * system - hands it to the core here, and the core holds it as an **import
7
+ * proposal**: an import session on the core's own import screen, marked as
8
+ * proposed by the plugin, which a board member previews, decides and applies,
9
+ * or rejects. The plugin never applies anything, and it learns nothing about
10
+ * what the file would do: each of those is a read of the register, and the
11
+ * permission behind this, addressBook:proposeImport, grants none.
12
+ */
13
+
14
+ /** The file a plugin hands over. */
15
+ export interface ImportProposalFile {
16
+ /** Shown to the board beside the proposal. 1 to 255 characters. */
17
+ fileName: string;
18
+ /**
19
+ * The file, CSV or XLSX, which the core parses exactly as it parses an
20
+ * upload, with the same limits. A source that gives JSON is written out as
21
+ * CSV first.
22
+ */
23
+ content: Uint8Array;
24
+ /**
25
+ * Who sent the file, as the source reports it: the address an email came
26
+ * from. Absent for a source that has no sender, such as a fetch from a
27
+ * manager's system. A claim, not a verified identity, and shown to the board
28
+ * as one. At most 320 characters.
29
+ */
30
+ sender?: string;
31
+ }
32
+
33
+ export interface ImportProposalReceipt {
34
+ proposalId: string;
35
+ /** Data rows read from the file, below its column titles. */
36
+ rowCount: number;
37
+ /** ISO 8601. When the proposal expires if nobody decides it. */
38
+ expiresAt: string;
39
+ }
40
+
41
+ /** Where one of the plugin's own proposals stands. */
42
+ export const IMPORT_PROPOSAL_STATES = [
43
+ /** Waiting for the board. */
44
+ "pending",
45
+ /** A board member started the import, and it is being written. */
46
+ "applying",
47
+ "applied",
48
+ /** The import a board member started stopped before the end. */
49
+ "failed",
50
+ "rejected",
51
+ /** A newer proposal from the same plugin replaced it. */
52
+ "superseded",
53
+ /** Nobody decided it in time. */
54
+ "expired",
55
+ /** The plugin took it back. */
56
+ "withdrawn",
57
+ /** Not one of this plugin's proposals, or no longer kept. */
58
+ "unknown",
59
+ ] as const;
60
+
61
+ export type ImportProposalState = (typeof IMPORT_PROPOSAL_STATES)[number];
62
+
63
+ export interface ImportProposalStatus {
64
+ state: ImportProposalState;
65
+ /** ISO 8601. When it reached the state it is in. Null while pending or unknown. */
66
+ decidedAt: string | null;
67
+ }
68
+
69
+ /**
70
+ * Why a file was refused. Nothing was stored for it.
71
+ *
72
+ * The reasons an upload is refused for, and four of a proposal's own:
73
+ * `file-unchanged` when the rows are those of the last file from this plugin
74
+ * the board applied or of the one still pending, `sender-too-long`,
75
+ * `sender-invalid` when the sender is neither text nor left out, and
76
+ * `file-name-invalid`. Treat a reason you do not know as a refusal all the
77
+ * same: a later core may add one.
78
+ */
79
+ export const IMPORT_PROPOSAL_REFUSAL_REASONS = [
80
+ "file-name-invalid",
81
+ "file-empty",
82
+ "header-row-missing",
83
+ "file-too-large",
84
+ "file-unreadable",
85
+ "file-mixed-encoding",
86
+ "too-many-rows",
87
+ "too-many-columns",
88
+ "cell-too-long",
89
+ "unterminated-quote",
90
+ "workbook-too-large",
91
+ "file-unchanged",
92
+ "sender-too-long",
93
+ "sender-invalid",
94
+ ] as const;
95
+
96
+ export type ImportProposalRefusalReason =
97
+ (typeof IMPORT_PROPOSAL_REFUSAL_REASONS)[number];
98
+
99
+ /**
100
+ * `host.imports.propose` refused the file. Carries the reason and nothing from
101
+ * the file, so it can be logged as it is.
102
+ */
103
+ export class ImportProposalRefusedError extends Error {
104
+ constructor(readonly reason: string) {
105
+ super(`The core refused the import proposal: ${reason}.`);
106
+ this.name = "ImportProposalRefusedError";
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Proposing imports. Requires addressBook:proposeImport.
112
+ *
113
+ * A plugin has at most one pending proposal: a new one replaces the one
114
+ * before, which becomes `superseded`. A proposal nobody decides expires after
115
+ * 14 days, and a decided one stays answerable by `status` for 90 days.
116
+ *
117
+ * What the plugin must not keep, which the catalog review checks: the file,
118
+ * or any part of it, is never passed to `host.jobs`, written to the log, the
119
+ * settings, any store the host offers or an error the plugin throws, and the
120
+ * plugin drops its copy once `propose` has answered. The sender likewise.
121
+ */
122
+ export interface PluginImports {
123
+ /**
124
+ * Hands a member list to the core for the board to review. Resolves once the
125
+ * core has parsed the file and stored the proposal, or rejects with
126
+ * ImportProposalRefusedError and stores nothing.
127
+ */
128
+ propose(file: ImportProposalFile): Promise<ImportProposalReceipt>;
129
+
130
+ /** Where one of this plugin's own proposals stands. */
131
+ status(proposalId: string): Promise<ImportProposalStatus>;
132
+
133
+ /** Withdraws this plugin's pending proposal. True when there was one. */
134
+ withdraw(proposalId: string): Promise<boolean>;
135
+ }
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  * a plugin ship as a self-contained bundle (ADR 0003).
9
9
  */
10
10
 
11
+ export type { PluginAbortSignal } from "./abort-signal.ts";
11
12
  export {
12
13
  ACTION_CHANNELS,
13
14
  ACTION_EFFECTS,
@@ -23,12 +24,24 @@ export {
23
24
  type ActionPersonalData,
24
25
  type ActionPrincipal,
25
26
  type ActionRequest,
27
+ type ActionRetry,
26
28
  type ActionSummary,
27
29
  type ActionSurface,
30
+ type PendingChangeReceipt,
31
+ type ActionWithSchemas,
28
32
  type PluginActionFilter,
29
33
  type PluginActionRegistration,
30
34
  type PluginActions,
31
35
  } from "./actions.ts";
36
+ export {
37
+ ACTION_ERROR_MCP,
38
+ ACTION_ERROR_REASONS,
39
+ type ActionErrorReason,
40
+ type ActionRefusal,
41
+ type ActionRefusalKind,
42
+ type ActionRefusalTransport,
43
+ isActionRefusal,
44
+ } from "./action-refusal.ts";
32
45
  export {
33
46
  actionInputJsonSchema,
34
47
  actionOutputJsonSchema,
@@ -39,15 +52,47 @@ export {
39
52
  PLUGIN_API_VERSION,
40
53
  SUPPORTED_PLUGIN_API_VERSIONS,
41
54
  } from "./api-version.ts";
55
+ export {
56
+ PLUGIN_BLOCK_ATTRIBUTES,
57
+ PLUGIN_BLOCK_CATEGORIES,
58
+ PLUGIN_BLOCK_ELEMENTS,
59
+ PLUGIN_BLOCK_ICONS,
60
+ PLUGIN_BLOCK_NAME_PATTERN,
61
+ PLUGIN_BLOCK_RENDER_TIMEOUT_MS,
62
+ type PluginBlockAbortSignal,
63
+ type PluginBlockCategory,
64
+ type PluginBlockContent,
65
+ type PluginBlockDeclaration,
66
+ type PluginBlockElement,
67
+ type PluginBlockElementName,
68
+ type PluginBlockIcon,
69
+ type PluginBlockNode,
70
+ type PluginBlockRegistration,
71
+ type PluginBlockRenderContext,
72
+ type PluginBlocks,
73
+ pluginBlockSchema,
74
+ pluginBlocksSchema,
75
+ pluginBlockType,
76
+ } from "./blocks.ts";
42
77
  export {
43
78
  type Catalog,
79
+ CATALOG_INDEX_VERSIONS,
80
+ CATALOG_REFUSALS,
44
81
  type CatalogArtifact,
45
82
  catalogArtifactSchema,
83
+ type CatalogDiagnostic,
46
84
  type CatalogEntry,
47
85
  catalogEntrySchema,
86
+ catalogEntryV2Schema,
87
+ CATALOG_INDEX_VERSION,
88
+ type CatalogExtensionPoint,
89
+ catalogExtensionPointSchema,
48
90
  type CatalogParseResult,
49
91
  type CatalogPluginEntry,
50
92
  catalogPluginEntrySchema,
93
+ catalogPluginEntryV2Schema,
94
+ type CatalogRefusal,
95
+ type CatalogRefusalCode,
51
96
  catalogSchema,
52
97
  type CatalogThemeEntry,
53
98
  catalogThemeEntrySchema,
@@ -55,51 +100,187 @@ export {
55
100
  parseCatalogIndex,
56
101
  } from "./catalog.ts";
57
102
  export { definePlugin } from "./define-plugin.ts";
103
+ export {
104
+ createTestEntitlements,
105
+ ENTITLEMENT_STATUSES,
106
+ type EntitlementState,
107
+ type EntitlementStatus,
108
+ LICENCE_FILE_MAX_BYTES,
109
+ LICENCE_FORMAT,
110
+ LICENCE_PRESENTATION_FORMAT,
111
+ LICENCE_PRESENTATION_MAX_BYTES,
112
+ type PluginEntitlements,
113
+ type TestEntitlementsOptions,
114
+ undeclaredAudienceError,
115
+ } from "./entitlements.ts";
116
+ export {
117
+ EXTENSION_MAX_OUTPUT_LENGTH,
118
+ EXTENSION_MAX_TIMEOUT_MS,
119
+ EXTENSION_POINT_ID_PATTERN,
120
+ EXTENSION_RESULT_REASONS,
121
+ EXTENSION_TIMEOUT_MS,
122
+ type ExtensionContext,
123
+ type ExtensionContributionDefinition,
124
+ type ExtensionContributionSummary,
125
+ type ExtensionPointDefinition,
126
+ type ExtensionResult,
127
+ type ExtensionResultReason,
128
+ type ExtensionTarget,
129
+ MAX_EXTENSION_POINTS,
130
+ type PluginExtensions,
131
+ } from "./extensions.ts";
132
+ export {
133
+ PLUGIN_FINANCE_EVENTS,
134
+ PluginDeliveryRefusedError,
135
+ type PluginDeliveryReceipt,
136
+ type PluginDeliveryReceiptInput,
137
+ type PluginDeliveryReference,
138
+ type PluginFeeNotice,
139
+ type PluginFeeNoticeHolders,
140
+ type PluginFeeNotification,
141
+ type PluginFeeNotificationSummary,
142
+ type PluginFinanceEvent,
143
+ type PluginFinanceEvents,
144
+ type PluginFinanceEventType,
145
+ type PluginFinances,
146
+ type PluginMemberCharge,
147
+ type PluginMemberChargeParty,
148
+ type PluginMemberChargeReason,
149
+ } from "./finances.ts";
150
+ export {
151
+ IMPORT_PROPOSAL_REFUSAL_REASONS,
152
+ IMPORT_PROPOSAL_STATES,
153
+ type ImportProposalFile,
154
+ type ImportProposalReceipt,
155
+ type ImportProposalRefusalReason,
156
+ ImportProposalRefusedError,
157
+ type ImportProposalState,
158
+ type ImportProposalStatus,
159
+ type PluginImports,
160
+ } from "./imports.ts";
58
161
  export { formatSha512, IntegrityError, parseSha512 } from "./integrity.ts";
59
162
  export {
60
163
  PLUGIN_FINDING_REASONS,
164
+ PLUGIN_MANIFEST_RULES,
61
165
  type PluginFindingDetail,
62
166
  type PluginFindingReason,
167
+ type PluginManifestRule,
63
168
  } from "./findings.ts";
64
169
  export {
170
+ PLUGIN_RECIPIENT_ERROR_CODES,
171
+ type DeviceTokenSummary,
172
+ type PluginAddress,
65
173
  type PluginAddressBook,
174
+ type PluginAddresses,
66
175
  type PluginApartment,
176
+ type PluginAudit,
177
+ type PluginAuditEntry,
178
+ PLUGIN_AUDIT_LIMITS,
179
+ type PluginBookableResource,
180
+ type PluginBookings,
181
+ type PluginBusyInterval,
182
+ type PluginCalendar,
183
+ type PluginContentAudience,
184
+ type PluginDevices,
185
+ type PluginDisclosure,
67
186
  type PluginHost,
68
187
  PluginHostUnavailableError,
69
188
  type PluginJobs,
70
189
  type PluginLogger,
71
190
  type PluginMail,
72
191
  type PluginMailMessage,
192
+ type PluginMedia,
193
+ type PluginMediaFile,
194
+ type PluginMediaStream,
195
+ type PluginMeetingNotice,
196
+ type PluginNews,
197
+ type PluginNewsItem,
73
198
  type PluginOccupancySummary,
199
+ type PluginOccurrence,
74
200
  PluginPermissionError,
201
+ PluginRecipientError,
202
+ type PluginRecipientErrorCode,
203
+ type PluginRecipientRequest,
204
+ type PluginRecipientResponse,
205
+ type PluginRecipients,
75
206
  type PluginResident,
207
+ type PluginResidentFilter,
76
208
  type PluginSettings,
209
+ type PluginInstalledTheme,
77
210
  type PluginSms,
78
211
  type PluginSmsMessage,
212
+ type PluginThemeInstallOptions,
213
+ type PluginThemeInstallResult,
214
+ type PluginThemeInstallWarning,
215
+ type PluginThemes,
79
216
  } from "./host.ts";
80
217
  export type { PluginModuleFactory } from "./module.ts";
81
218
  export {
82
219
  assertPluginPackage,
83
220
  composedActionName,
84
221
  CURRENT_PLUGIN_API_VERSION,
222
+ declaredExtensionPointsSchema,
223
+ declaredExtensionsSchema,
224
+ extensionGroupRefusals,
225
+ extensionHostPersonalDataRefused,
226
+ extensionPermissionsRefused,
227
+ extensionPointIdSchema,
228
+ extensionPointRefusal,
229
+ type ExtensionPointRefusal,
230
+ extensionRuleIssues,
231
+ MAX_DEVICE_ROUTES,
232
+ isCalendarDay,
233
+ licenceAudienceSchema,
234
+ licenceKeyIdSchema,
235
+ licencePublicKeySchema,
85
236
  type ManifestParseResult,
237
+ missingProcessingProblem,
238
+ readsAddressBook,
239
+ undeclaredPersonalDataProblem,
240
+ PLUGIN_DATA_SUBJECTS,
241
+ PLUGIN_LEGAL_BASES,
86
242
  type PluginActionDeclaration,
87
243
  pluginActionSchema,
88
244
  pluginActionsSchema,
245
+ type PluginDeviceRoute,
246
+ pluginDeviceRouteSchema,
247
+ pluginDeviceRoutesSchema,
89
248
  type PluginEntry,
90
249
  pluginEntrySchema,
250
+ type PluginExtensionDeclaration,
251
+ type PluginExtensionPointDeclaration,
252
+ pluginExtensionPointSchema,
253
+ pluginExtensionSchema,
91
254
  pluginIdSchema,
255
+ type PluginDataSubject,
256
+ type PluginLegalBasis,
257
+ type PluginLicenceDeclaration,
258
+ pluginLicenceSchema,
92
259
  type PluginManifest,
93
260
  pluginManifestSchema,
94
261
  type PluginPackage,
95
262
  pluginPackageSchema,
263
+ type PluginProcessing,
264
+ pluginProcessingSchema,
265
+ type PluginView,
266
+ pluginViewSchema,
267
+ type PluginViewSection,
268
+ PLUGIN_VIEW_SECTIONS,
96
269
  parsePluginPackage,
270
+ proposeImportPersonalDataIssues,
271
+ routePathsOverlap,
97
272
  } from "./manifest.ts";
98
273
  export {
99
274
  HOST_SHARED_PACKAGES,
100
275
  type PluginPackageContents,
101
276
  pluginPackageProblems,
102
277
  } from "./package-check.ts";
278
+ export {
279
+ PLUGIN_ROUTE_CAPABILITIES,
280
+ type PluginRouteCapability,
281
+ REQUIRED_CAPABILITIES_KEY,
282
+ RequireCapability,
283
+ } from "./require-capability.ts";
103
284
  export type {
104
285
  StandardSchemaIssue,
105
286
  StandardSchemaResult,
@@ -111,7 +292,33 @@ export {
111
292
  PLUGIN_PERSONAL_DATA_CATEGORIES,
112
293
  type PluginPermission,
113
294
  type PluginPersonalDataCategory,
295
+ PROPOSE_IMPORT_ONLY_PERSONAL_DATA,
296
+ PROPOSE_IMPORT_PERSONAL_DATA,
114
297
  } from "./permissions.ts";
298
+ export {
299
+ canonicalRecipient,
300
+ type PluginRecipient,
301
+ pluginRecipientSchema,
302
+ pluginRecipientsSchema,
303
+ RECEIVING_HOSTS_MAX_LENGTH,
304
+ receivingHosts,
305
+ recipientHost,
306
+ recipientOriginSchema,
307
+ recipientsBeyondConsent,
308
+ sameRecipientDeclaration,
309
+ } from "./recipients.ts";
310
+ export {
311
+ type JsonValue,
312
+ PLUGIN_RECORD_COLLECTION_PATTERN,
313
+ PLUGIN_RECORD_KEY_PATTERN,
314
+ PLUGIN_RECORD_LIMITS,
315
+ type PluginRecord,
316
+ PluginRecordConflictError,
317
+ PluginRecordIdentityNumberError,
318
+ type PluginRecordLimit,
319
+ PluginRecordLimitError,
320
+ type PluginRecords,
321
+ } from "./records.ts";
115
322
  export {
116
323
  defaultSettings,
117
324
  type PluginSettingsField,
@@ -119,5 +326,7 @@ export {
119
326
  type PluginSettingsSchema,
120
327
  pluginSettingsSchema,
121
328
  type PluginSettingsValues,
329
+ secretValueValidator,
122
330
  settingsValidator,
331
+ withoutSecretFields,
123
332
  } from "./settings-schema.ts";
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Text written in both languages the interface is offered in.
5
+ *
6
+ * For what the board reads before anything has been downloaded: the catalog's
7
+ * own name and description of an entry, and the parts of a declaration the
8
+ * consent screen shows, such as a recipient's purpose. A plugin's locale files
9
+ * reach the instance with its package, so a key into them would have no words
10
+ * behind it on the screen that decides whether the package is fetched.
11
+ *
12
+ * Strict, so a misspelled language is refused rather than dropped.
13
+ */
14
+ export const localizedTextSchema = z.strictObject({
15
+ sv: z.string().min(1).max(500),
16
+ en: z.string().min(1).max(500),
17
+ });
18
+
19
+ export type LocalizedText = z.infer<typeof localizedTextSchema>;