wowok 1.5.52 → 1.5.56

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- # Wowok
2
+ # WoWok
3
3
 
4
4
  Create, collaborate, and transact on your own terms with the AI-driven web3 collaboration protocol.
5
5
 
@@ -27,5 +27,8 @@ The protocol address may change due to protocol upgrade. Please update the SDK t
27
27
  * Encrypted personal information transfer and order management
28
28
  * Support compensation and dispute voting arbitration
29
29
 
30
- #### [See more examples](https://github.com/wowok-ai/sdk-examples)
30
+ #### [How can social resources collaborate to meet a Kenya 10-day personalized travel dream](https://github.com/wowok-ai/sdk-examples/tree/main/kenya)
31
+ * Demand + Service + Machine/Progress + Order + Permission + Treasury + Arbitration
32
+
33
+ #### [See more examples...](https://github.com/wowok-ai/sdk-examples)
31
34
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wowok",
3
- "version": "1.5.52",
3
+ "version": "1.5.56",
4
4
  "description": "Create, collaborate, and transact on your own terms with the AI-driven web3 collaboration protocol.",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -39,7 +39,8 @@
39
39
  "move",
40
40
  "treasury",
41
41
  "payment",
42
- "arbitration"
42
+ "arbitration",
43
+ "oracle"
43
44
  ],
44
45
  "author": "wowok",
45
46
  "license": "Apache-2.0",
package/src/guard.ts CHANGED
@@ -267,14 +267,14 @@ export class Guard {
267
267
  [MODULES.progress, 'Parent Node', 816, [], ValueType.TYPE_STRING, 'The node name of the parent process where the child process is located.', []],
268
268
  [MODULES.progress, 'Forward Accomplished', 817, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_BOOL, 'Has the forward been accomplished?', ['session-id', 'next node name', 'forward name']],
269
269
  [MODULES.progress, 'Forward Operator', 818, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_ADDRESS, 'The forward operator.', ['session-id', 'next node name', 'forward name']],
270
- [MODULES.progress, 'Forward Sub-progress', 819, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_ADDRESS, 'The forward child process address(if set).', ['session-id', 'next node name', 'forward name']],
271
- [MODULES.progress, 'Forward Deliverables', 820, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_ADDRESS, 'The forward deliverable(if set).', ['session-id', 'next node name', 'forward name']],
270
+ [MODULES.progress, 'Forward Message', 819, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_STRING, 'The forward message.', ['session-id', 'next node name', 'forward name']],
271
+ [MODULES.progress, 'Forward Order Count', 820, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_U64, 'The forward Order count.', ['session-id', 'next node name', 'forward name']],
272
272
  [MODULES.progress, 'Forward time', 821, [ValueType.TYPE_U64, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_U64, 'The time when the forward was last triggered.', ['session-id', 'next node name', 'forward name']],
273
273
  [MODULES.progress, 'Closest Session Time', 822, [ValueType.TYPE_STRING], ValueType.TYPE_U64, 'The time a node that closest time to the current node completes its session.', ['node name']],
274
274
  [MODULES.progress, 'Closest Forward Accomplished', 823, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_BOOL, 'Has the forward been accomplished?', ['node name', 'next node name', 'forward name']],
275
275
  [MODULES.progress, 'Closest Forward Operator', 824, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_ADDRESS, 'The operator of the forward that closest time to the current node.', ['node name', 'next node name', 'forward name']],
276
- [MODULES.progress, 'Closest Forward Sub-progress', 825, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_ADDRESS, 'The child process address(if set) of the forward that closest time to the current node.', ['node name', 'next node name', 'forward name']],
277
- [MODULES.progress, 'Closest Forward Deliverables', 826, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_ADDRESS, 'The deliverable(if set) of the forward that closest time to the current node.', ['node name', 'next node name', 'forward name']],
276
+ [MODULES.progress, 'Closest Forward Message', 825, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_STRING, 'The message of the forward that closest time to the current node.', ['node name', 'next node name', 'forward name']],
277
+ [MODULES.progress, 'Closest Forward Order Count', 826, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_U64, 'The Order count of the forward that closest time to the current node.', ['node name', 'next node name', 'forward name']],
278
278
  [MODULES.progress, 'Closest Forward time', 827, [ValueType.TYPE_STRING, ValueType.TYPE_STRING, ValueType.TYPE_STRING], ValueType.TYPE_U64, 'The time when the forward that closest time to the current node was last triggered.', ['node name', 'next node name', 'forward name']],
279
279
 
280
280
  [MODULES.wowok, 'Builder', 900, [], ValueType.TYPE_ADDRESS, 'Builder address of Wowok.', []],
package/src/machine.ts CHANGED
@@ -1,18 +1,24 @@
1
1
  import { Transaction as TransactionBlock, TransactionObjectArgument, type TransactionResult } from '@mysten/sui/transactions';
2
- import { Protocol, FnCallType, PermissionObject, RepositoryObject, PassportObject, MachineObject, MachineAddress, GuardObject, TxbObject} from './protocol';
2
+ import { Protocol, FnCallType, PermissionObject, RepositoryObject, PassportObject, MachineObject, MachineAddress, GuardObject, TxbObject, ServiceObject} from './protocol';
3
3
  import { IsValidInt, Bcs, array_unique, IsValidArray, IsValidAddress, IsValidName, IsValidName_AllowEmpty,
4
- IsValidEndpoint, IsValidDesription, IsValidU64 } from './utils'
4
+ IsValidEndpoint, IsValidDesription, IsValidU64,
5
+ IsValidTokenType} from './utils'
5
6
  import { Permission, PermissionIndexType } from './permission';
6
7
  import { Errors, ERROR} from './exception'
7
8
  import { ValueType } from './protocol';
8
9
 
9
-
10
+ export interface ServiceWrap {
11
+ object:ServiceObject,
12
+ pay_token_type: string,
13
+ bOptional: boolean,
14
+ }
10
15
  export interface Machine_Forward {
11
16
  name: string; // foward name
12
17
  namedOperator?: string; // dynamic operator
13
18
  permission?: PermissionIndexType; // this.permission-index or named-operator MUST one defined.
14
19
  weight?: number;
15
20
  guard?: GuardObject;
21
+ suppliers?: ServiceWrap[];
16
22
  }
17
23
  export interface Machine_Node_Pair {
18
24
  prior_node: string;
@@ -156,6 +162,16 @@ export class Machine {
156
162
  ERROR(Errors.InvalidParam, 'forward')
157
163
  }
158
164
 
165
+ forward?.suppliers?.forEach((v) => {
166
+ if (!IsValidTokenType(v.pay_token_type)) {
167
+ ERROR(Errors.IsValidTokenType, 'forward.suppliers:'+v.object);
168
+ }
169
+ this.txb.moveCall({
170
+ target:Protocol.Instance().ServiceFn('add_to') as FnCallType,
171
+ arguments:[this.txb.object(v.object), this.txb.pure.bool(v.bOptional), f],
172
+ typeArguments:[v.pay_token_type]
173
+ });
174
+ })
159
175
  return f
160
176
  }
161
177
 
@@ -481,7 +497,9 @@ export class Machine {
481
497
  let forward_namedOperator = f.fields.value.fields.namedOperator;
482
498
  let forward_permission_index = f.fields.value.fields.permission_index;
483
499
  forwards.push({name:forward_name, namedOperator:forward_namedOperator, permission:forward_permission_index,
484
- weight:forward_weight, guard:forward_guard?forward_guard:''});
500
+ weight:forward_weight, guard:forward_guard?forward_guard:'', suppliers:f.fields.value.fields.suppliers.fields.contents.map((v:any) => {
501
+ return {object:v.fields.key, bOptional:v.fields.value, pay_token_type:''}
502
+ })}); //@ NOTICE...
485
503
  });
486
504
  pairs.push({prior_node:p.fields.key, threshold:p.fields.value.fields.threshold, forwards:forwards});
487
505
  });
package/src/progress.ts CHANGED
@@ -1,11 +1,21 @@
1
1
 
2
2
  import { FnCallType, PermissionObject, RepositoryObject, PassportObject, MachineObject,
3
- ProgressObject, ProgressAddress, Protocol, TxbObject} from './protocol';
3
+ ProgressObject, ProgressAddress, Protocol, TxbObject,
4
+ OrderObject} from './protocol';
4
5
  import { Machine } from './machine';
5
- import { Bcs, array_unique,IsValidName, IsValidAddress, IsValidArray, IsValidInt } from './utils'
6
+ import { Bcs, array_unique,IsValidName, IsValidAddress, IsValidArray, IsValidInt, IsValidDesription, IsValidTokenType } from './utils'
6
7
  import { ERROR, Errors } from './exception';
7
- import { type TransactionResult, Transaction as TransactionBlock } from '@mysten/sui/transactions';
8
+ import { type TransactionResult, Transaction as TransactionBlock, } from '@mysten/sui/transactions';
8
9
 
10
+ export interface OrderWrap {
11
+ object: OrderObject;
12
+ pay_token_type: string;
13
+ }
14
+
15
+ export interface Deliverable {
16
+ msg: string;
17
+ orders: OrderWrap[];
18
+ }
9
19
 
10
20
  export type ProgressNext = {
11
21
  next_node_name: string;
@@ -23,8 +33,7 @@ export type CurrentSessionId = TransactionResult;
23
33
  export interface Holder {
24
34
  forward: string;
25
35
  who?:string;
26
- sub_progress?:string;
27
- deliverables?:string;
36
+ deliverable: Deliverable;
28
37
  accomplished:boolean;
29
38
  }
30
39
  export interface Session {
@@ -251,19 +260,37 @@ export class Progress {
251
260
  }
252
261
  }
253
262
 
254
- next(next:ProgressNext, deliverables_address?:string, sub_id?:string, passport?:PassportObject) : CurrentSessionId {
255
- if (!Progress.IsValidProgressNext(next)) {
256
- ERROR(Errors.InvalidParam, 'next')
263
+ private deliverable(deliverable:Deliverable) : TransactionResult {
264
+ if (!IsValidDesription(deliverable.msg)) {
265
+ ERROR(Errors.IsValidDesription, 'deliverable.msg')
257
266
  }
258
- if (deliverables_address && !IsValidAddress(deliverables_address)) {
259
- ERROR(Errors.IsValidAddress, 'deliverables_address');
267
+ if (deliverable.orders.length > 0 && !Protocol.IsValidObjects(deliverable.orders.map(v=>v.object))) {
268
+ ERROR(Errors.IsValidObjects, 'deliverable.orders')
260
269
  }
261
- if (sub_id && !IsValidAddress(sub_id)) {
262
- ERROR(Errors.IsValidAddress, 'sub_id');
270
+
271
+ const d = this.txb.moveCall({
272
+ target:Protocol.Instance().ProgressFn('deliverable_new') as FnCallType,
273
+ arguments: [this.txb.pure.string(deliverable.msg)],
274
+ })
275
+ deliverable.orders.forEach(v => {
276
+ if (!IsValidTokenType(v.pay_token_type)) {
277
+ ERROR(Errors.IsValidTokenType, 'deliverable.orders:' + v.object)
278
+ }
279
+ this.txb.moveCall({
280
+ target:Protocol.Instance().OrderFn('as_deliverable') as FnCallType,
281
+ arguments: [this.txb.object(v.object), d],
282
+ typeArguments:[v.pay_token_type]
283
+ })
284
+ })
285
+ return d
286
+ }
287
+
288
+ next(next:ProgressNext, deliverable:Deliverable, passport?:PassportObject) : CurrentSessionId {
289
+ if (!Progress.IsValidProgressNext(next)) {
290
+ ERROR(Errors.InvalidParam, 'next')
263
291
  }
264
-
265
- const diliverable = this.txb.pure.option('address', deliverables_address ? deliverables_address : undefined);
266
- const sub = this.txb.pure.option('address', sub_id ? sub_id : undefined);
292
+
293
+ const d = this.deliverable(deliverable);
267
294
  const clock = this.txb.sharedObjectRef(Protocol.CLOCK_OBJECT);
268
295
 
269
296
  if (passport) {
@@ -271,14 +298,14 @@ export class Progress {
271
298
  target:Protocol.Instance().ProgressFn('next_with_passport') as FnCallType,
272
299
  arguments: [passport, Protocol.TXB_OBJECT(this.txb, this.object), Protocol.TXB_OBJECT(this.txb, this.machine),
273
300
  this.txb.pure.string(next.next_node_name),
274
- this.txb.pure.string(next.forward), diliverable, sub,
301
+ this.txb.pure.string(next.forward), d,
275
302
  Protocol.TXB_OBJECT(this.txb, this.permission), this.txb.object(clock)],
276
303
  })
277
304
  } else {
278
305
  return this.txb.moveCall({
279
306
  target:Protocol.Instance().ProgressFn('next') as FnCallType,
280
307
  arguments: [Protocol.TXB_OBJECT(this.txb, this.object), Protocol.TXB_OBJECT(this.txb, this.machine), this.txb.pure.string(next.next_node_name),
281
- this.txb.pure.string(next.forward), diliverable, sub, Protocol.TXB_OBJECT(this.txb, this.permission), this.txb.object(clock)],
308
+ this.txb.pure.string(next.forward), d, Protocol.TXB_OBJECT(this.txb, this.permission), this.txb.object(clock)],
282
309
  })
283
310
  }
284
311
  }
@@ -301,8 +328,8 @@ export class Progress {
301
328
  var s:Session = {next_node: v.fields.key, holders:[], weights:v.fields.value.fields.weights, threshold:v.fields.value.fields.threshold};
302
329
  v.fields.value.fields.forwards.fields.contents.forEach((i:any) => {
303
330
  s.holders.push({forward:i.fields.key, accomplished:i.fields.value.fields.accomplished,
304
- who:i.fields.value.fields.who, deliverables:i.fields.value.fields.deliverables ?? undefined,
305
- sub_progress: i.fields.value.fields.sub_progress ?? undefined
331
+ who:i.fields.value.fields.who, deliverable:{msg:i.fields.value.fields.msg,
332
+ orders:i.fields.value.fields.orders ?? []},
306
333
  })
307
334
  })
308
335
  sessions.push(s);
@@ -320,7 +347,8 @@ export class Progress {
320
347
  weights:i.fields.value.fields.weights, threshold:i.fields.value.fields.threshold, bComplete:i.fields.key === next_node};
321
348
  i.fields.value.fields.forwards.fields.contents.forEach((k:any) => {
322
349
  s.holders.push({forward:k.fields.key, who:k.fields.value.fields.who, accomplished:k.fields.value.fields.accomplished,
323
- sub_progress:k.fields.value.fields.sub_progress ?? undefined, deliverables:k.fields.value.fields.deliverables ?? undefined});
350
+ deliverable:{msg:k.fields.value.fields.msg,
351
+ orders:k.fields.value.fields.orders ?? []}});
324
352
  })
325
353
  sessions.push(s);
326
354
  })
@@ -329,6 +357,7 @@ export class Progress {
329
357
  }
330
358
 
331
359
  static MAX_NAMED_OPERATOR_COUNT = 20;
360
+ static MAX_DELEVERABLE_ORDER_COUNT = 20;
332
361
  static IsValidProgressNext = (next:ProgressNext) => {
333
362
  return IsValidName(next.forward) && IsValidName(next.next_node_name);
334
363
  }
package/src/protocol.ts CHANGED
@@ -221,14 +221,15 @@ const TESTNET = {
221
221
  }
222
222
  */
223
223
  const TESTNET = {
224
- wowok: "0x4cd9cecc9720f778678a8d7c4005834a99aff27bb573b15738fbbc6419e380ac",
225
- wowok_origin:'0x4cd9cecc9720f778678a8d7c4005834a99aff27bb573b15738fbbc6419e380ac' ,
226
- base: '0x985dd058e7f7d6c216b8a55d0170c47c1a6db048a8045c56c6cca4ba9333684d',
227
- base_origin: '0x985dd058e7f7d6c216b8a55d0170c47c1a6db048a8045c56c6cca4ba9333684d',
228
-
229
- wowok_object: '0x60aab3dc3e911a5f952a97fd411531b4e1e61676cdf0f8fe10685ce15310dd31',
230
- entity_object: '0xec60850cde84c92bad3a161f7c5db4f7b86440e1fdc819be94523a29fff67497',
231
- treasury_cap:'0x4bf3375d58afc7b9de3335e777223b3fad16f154305c313d65ec75c2183e2df9',
224
+ wowok: "0x66f08884668a7b18b34ce0ae91cfb7bdab284d4dbbc28ad3fb009df50f88e11e",
225
+ wowok_origin:'0x66f08884668a7b18b34ce0ae91cfb7bdab284d4dbbc28ad3fb009df50f88e11e' ,
226
+ base: '0x3960658ad695c829bd62a083a8a92f94f04404ae3ea6b13bbc72e5780cfeec4c',
227
+ base_origin: '0x3960658ad695c829bd62a083a8a92f94f04404ae3ea6b13bbc72e5780cfeec4c',
228
+
229
+ wowok_object: '0xa51c94e11a4693e63b77cc6577a2deb0e4eed1cc6a1fbc3971b35edafc72eaed',
230
+ entity_object: '0x5f45ec58ed208c7b1b5d427fa77bbc64ad2256203aa6f11961b9417a7eeca053',
231
+ treasury_cap:'0xc1f614972987e8839584710c0a8b9f284745e667f2e19594c0ffa09ca5e59721',
232
+ oracle_object:'0x57c89a7ba9f2aaf784a5325da111989f157939a14df15bb9698de0a46285d746',
232
233
  }
233
234
  const MAINNET = {
234
235
  wowok: "",
@@ -239,6 +240,7 @@ const MAINNET = {
239
240
  wowok_object: '',
240
241
  entity_object: '',
241
242
  treasury_cap:'',
243
+ oracle_object:'',
242
244
  }
243
245
 
244
246
  export interface CoinTypeInfo {
@@ -254,6 +256,7 @@ export class Protocol {
254
256
  protected wowok_object = '';
255
257
  protected entity_object = '';
256
258
  protected treasury_cap = '';
259
+ protected oracle_object = '';
257
260
  protected graphql = '';
258
261
  protected txb: TransactionBlock | undefined;
259
262
  static _instance: any;
@@ -288,6 +291,7 @@ export class Protocol {
288
291
  this.entity_object= TESTNET.entity_object;
289
292
  this.treasury_cap = TESTNET.treasury_cap;
290
293
  this.graphql = 'https://sui-testnet.mystenlabs.com/graphql';
294
+ this.oracle_object = TESTNET.oracle_object;
291
295
  break;
292
296
  case ENTRYPOINT.mainnet:
293
297
  this.package.set('wowok', MAINNET.wowok);
@@ -298,6 +302,7 @@ export class Protocol {
298
302
  this.entity_object= MAINNET.entity_object;
299
303
  this.treasury_cap = MAINNET.treasury_cap;
300
304
  this.graphql = 'https://sui-mainnet.mystenlabs.com/graphql';
305
+ this.oracle_object = MAINNET.oracle_object;
301
306
  break;
302
307
  };
303
308
  }
@@ -307,6 +312,7 @@ export class Protocol {
307
312
 
308
313
  WowokObject(): string { return this.wowok_object }
309
314
  EntityObject(): string { return this.entity_object }
315
+ OracleObject(): string { return this.oracle_object }
310
316
  TreasuryCap() : string { return this.treasury_cap }
311
317
  GraphqlUrl() : string { return this.graphql }
312
318
 
@@ -339,7 +345,7 @@ export class Protocol {
339
345
  TreasuryFn = (fn: any) => { return `${this.package.get('wowok')}::${MODULES.treasury}::${fn}`};
340
346
  PaymentFn = (fn: any) => { return `${this.package.get('wowok')}::${MODULES.payment}::${fn}`};
341
347
  GuardFn = (fn: any) => { return `${this.package.get('base')}::${MODULES.guard}::${fn}`};
342
- MintFn = (fn: any) => { return `${this.package.get('base')}::${MODULES.wowok}::${fn}`};
348
+ BaseWowokFn = (fn: any) => { return `${this.package.get('base')}::${MODULES.wowok}::${fn}`};
343
349
  ArbitrationFn = (fn: any) => { return `${this.package.get('wowok')}::${MODULES.arbitration}::${fn}`};
344
350
  ArbFn = (fn: any) => { return `${this.package.get('wowok')}::${MODULES.arb}::${fn}`};
345
351
 
package/src/repository.ts CHANGED
@@ -380,6 +380,11 @@ export class Repository {
380
380
  static MAX_KEY_LENGTH = 128;
381
381
  static MAX_VALUE_LENGTH = 204800;
382
382
  static MAX_REFERENCE_COUNT = 100;
383
+
384
+ static TYPE_NORMAL = 0;
385
+ static TYPE_WOWOK_GRANTEE = 1;
386
+ static TYPE_WOWOK_ORACLE = 2;
387
+
383
388
  static IsValidName = (key:string) => {
384
389
  return key.length <= Repository.MAX_KEY_LENGTH && key.length != 0;
385
390
  }
package/src/wowok.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Protocol, FnCallType, TxbObject, ResourceAddress, PermissionObject} from './protocol';
1
+ import { Protocol, FnCallType, TxbObject, ResourceAddress, PermissionObject, RepositoryAddress} from './protocol';
2
2
  import { IsValidDesription, IsValidAddress, IsValidName, IsValidArray, IsValidU64, } from './utils';
3
3
  import { ERROR, Errors } from './exception';
4
4
  import { Transaction as TransactionBlock} from '@mysten/sui/transactions';
@@ -52,10 +52,19 @@ export class Wowok {
52
52
  if (!IsValidAddress(recipient)) ERROR(Errors.IsValidAddress, 'mint');
53
53
  if (!IsValidU64(amount)) ERROR(Errors.IsValidU64, 'mint');
54
54
  this.txb.moveCall({
55
- target:Protocol.Instance().MintFn('mint') as FnCallType, //@ base package
55
+ target:Protocol.Instance().BaseWowokFn('mint') as FnCallType, //@ base package
56
56
  arguments:[Protocol.TXB_OBJECT(this.txb, Protocol.Instance().TreasuryCap()), this.txb.pure.u64(amount),
57
57
  this.txb.pure.address(recipient)]
58
58
  })
59
59
  }
60
+ oracle(description: string, permission: PermissionObject) : RepositoryAddress {
61
+ if (!IsValidDesription(description)) ERROR(Errors.IsValidDesription, 'oracle.description');
62
+ if (!Protocol.IsValidObjects([permission])) ERROR(Errors.IsValidObjects, 'oracle.permission');
63
+ return this.txb.moveCall({
64
+ target:Protocol.Instance().WowokFn('oracle_repository') as FnCallType, //@ base package
65
+ arguments:[Protocol.TXB_OBJECT(this.txb, Protocol.Instance().OracleObject()), this.txb.pure.string(description),
66
+ this.txb.object(permission)]
67
+ })
68
+ }
60
69
  }
61
70