xync-schema 0.6.31__tar.gz → 0.6.32.dev1__tar.gz
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.
- {xync_schema-0.6.31/xync_schema.egg-info → xync_schema-0.6.32.dev1}/PKG-INFO +1 -1
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema/models.py +65 -98
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema/pydantic.py +9 -4
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1/xync_schema.egg-info}/PKG-INFO +1 -1
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/.env.sample +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/.gitignore +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/.pre-commit-config.yaml +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/README.md +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/makefile +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/pyproject.toml +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/setup.cfg +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/tests/__init__.py +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/tests/test_db.py +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema/__init__.py +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema.egg-info/SOURCES.txt +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema.egg-info/dependency_links.txt +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema.egg-info/requires.txt +0 -0
- {xync_schema-0.6.31 → xync_schema-0.6.32.dev1}/xync_schema.egg-info/top_level.txt +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
from enum import IntEnum
|
|
3
3
|
from tortoise import fields
|
|
4
|
+
from x_auth.enums import Role
|
|
4
5
|
from x_auth.models import Model
|
|
5
6
|
from x_model.models import TsTrait, DatetimeSecField
|
|
6
|
-
from tg_auth.models import
|
|
7
|
+
from tg_auth.models import UserStatus, AuthUser
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class AdStatus(IntEnum):
|
|
@@ -131,14 +132,13 @@ class Cur(Model):
|
|
|
131
132
|
countries: fields.ReverseRelation[Country]
|
|
132
133
|
|
|
133
134
|
_name = {"ticker"}
|
|
134
|
-
_icon = "currency-yuan"
|
|
135
135
|
|
|
136
136
|
class Meta:
|
|
137
137
|
table_description = "Fiat currencies"
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
class Coin(Model):
|
|
141
|
-
|
|
141
|
+
id: int = fields.SmallIntField(True)
|
|
142
142
|
ticker: str = fields.CharField(15, unique=True)
|
|
143
143
|
rate: float | None = fields.FloatField(null=True)
|
|
144
144
|
is_fiat: bool = fields.BooleanField(default=False)
|
|
@@ -151,13 +151,6 @@ class Coin(Model):
|
|
|
151
151
|
# deps_bonus: fields.ReverseRelation["Dep"]
|
|
152
152
|
|
|
153
153
|
_name = {"ticker"}
|
|
154
|
-
_icon = "coin"
|
|
155
|
-
|
|
156
|
-
def repr(self, *args):
|
|
157
|
-
return super().repr() + (self.is_fiat and " (fiat)" or "")
|
|
158
|
-
|
|
159
|
-
class Meta:
|
|
160
|
-
table_description = "Crypro coins"
|
|
161
154
|
|
|
162
155
|
|
|
163
156
|
class Ex(Model):
|
|
@@ -179,9 +172,7 @@ class Ex(Model):
|
|
|
179
172
|
pmexs: fields.ReverseRelation["Pmex"]
|
|
180
173
|
pairs: fields.ReverseRelation["Pair"]
|
|
181
174
|
# deps: fields.ReverseRelation["Dep"]
|
|
182
|
-
tests: fields.ReverseRelation["TestEx"]
|
|
183
|
-
|
|
184
|
-
_icon = "exchange"
|
|
175
|
+
# tests: fields.ReverseRelation["TestEx"]
|
|
185
176
|
|
|
186
177
|
class Meta:
|
|
187
178
|
table_description = "Exchanges"
|
|
@@ -210,16 +201,12 @@ class Pair(Model, TsTrait):
|
|
|
210
201
|
ex: fields.ForeignKeyRelation[Ex] = fields.ForeignKeyField("models.Ex", related_name="pairs")
|
|
211
202
|
directions: fields.ReverseRelation["Direction"]
|
|
212
203
|
|
|
213
|
-
_icon = "circles-relation"
|
|
214
204
|
_name = {"coin__ticker", "cur__ticker"}
|
|
215
205
|
|
|
216
206
|
class Meta:
|
|
217
207
|
table_description = "Coin/Currency pairs"
|
|
218
208
|
unique_together = (("coin", "cur", "ex"),)
|
|
219
209
|
|
|
220
|
-
def repr(self, *args):
|
|
221
|
-
return f"{self.coin.ticker}/{self.cur.ticker}"
|
|
222
|
-
|
|
223
210
|
|
|
224
211
|
class Direction(Model):
|
|
225
212
|
id = fields.SmallIntField(True)
|
|
@@ -228,25 +215,27 @@ class Direction(Model):
|
|
|
228
215
|
total: int = fields.IntField()
|
|
229
216
|
ads: fields.ReverseRelation["Ad"]
|
|
230
217
|
|
|
231
|
-
_icon = "direction-sign"
|
|
232
218
|
_name = {"pair__coin__ticker", "pair__cur__ticker", "sell"}
|
|
233
219
|
|
|
234
220
|
class Meta:
|
|
235
221
|
table_description = "Trade directions"
|
|
236
222
|
unique_together = (("pair", "sell"),)
|
|
237
223
|
|
|
238
|
-
def repr(self, *args):
|
|
239
|
-
return f"{self.pair.coin.ticker}/{self.pair.cur.ticker} {'SELL' if self.sell else 'BUY'}"
|
|
240
224
|
|
|
225
|
+
class User(Model, TsTrait):
|
|
226
|
+
id: int = fields.BigIntField(True)
|
|
227
|
+
role: Role = fields.IntEnumField(Role)
|
|
228
|
+
status: UserStatus = fields.IntEnumField(UserStatus, default=UserStatus.RESTRICTED)
|
|
229
|
+
username: str | None = fields.CharField(95, unique=True, null=True)
|
|
230
|
+
ref: fields.ForeignKeyNullableRelation["User"] = fields.ForeignKeyField(
|
|
231
|
+
"models.User", related_name="proteges", null=True
|
|
232
|
+
)
|
|
233
|
+
ref_id: int | None
|
|
241
234
|
|
|
242
|
-
|
|
243
|
-
chat_status: UserStatus = fields.IntEnumField(UserStatus, default=UserStatus.RESTRICTED)
|
|
244
|
-
in_channel: bool | None = fields.BooleanField(default=False, null=True)
|
|
245
|
-
|
|
235
|
+
proteges: fields.BackwardFKRelation["User"]
|
|
246
236
|
agents: fields.BackwardFKRelation["Agent"]
|
|
247
237
|
fiats: fields.BackwardFKRelation["Fiat"]
|
|
248
238
|
limits: fields.BackwardFKRelation["Limit"]
|
|
249
|
-
proteges: fields.BackwardFKRelation["User"]
|
|
250
239
|
# vpn: fields.BackwardOneToOneRelation["Vpn"]
|
|
251
240
|
# invite_requests: fields.BackwardFKRelation["Invite"]
|
|
252
241
|
# invite_approvals: fields.BackwardFKRelation["Invite"]
|
|
@@ -254,33 +243,44 @@ class User(BaseUser, UserRefTrait, UserInfoTrait): # tg user
|
|
|
254
243
|
# borrows: fields.BackwardFKRelation["Credit"]
|
|
255
244
|
# investments: fields.BackwardFKRelation["Investment"]
|
|
256
245
|
|
|
246
|
+
async def free_assets(self):
|
|
247
|
+
assets = await Asset.filter(agent__user_id=self.id).values("free", "coin__rate")
|
|
248
|
+
return sum(asset["free"] * asset["coin__rate"] for asset in assets)
|
|
249
|
+
|
|
250
|
+
async def fiats_sum(self):
|
|
251
|
+
fiats = await self.fiats._db_queryset().values("amount", "pmcur__cur__rate")
|
|
252
|
+
return sum(fiat["amount"] * fiat["pmcur__cur__rate"] for fiat in fiats)
|
|
253
|
+
|
|
254
|
+
async def balance(self):
|
|
255
|
+
return await self.free_assets() + await self.fiats_sum()
|
|
256
|
+
|
|
257
|
+
def get_auth(self) -> AuthUser:
|
|
258
|
+
return AuthUser.model_validate(self, from_attributes=True)
|
|
259
|
+
|
|
260
|
+
class PydanticMeta(Model.PydanticMeta):
|
|
261
|
+
computed = ["balance"]
|
|
262
|
+
|
|
257
263
|
|
|
258
264
|
class Agent(Model, TsTrait):
|
|
259
|
-
id: int
|
|
260
265
|
exid: int = fields.IntField()
|
|
261
266
|
ex: fields.ForeignKeyRelation[Ex] = fields.ForeignKeyField("models.Ex", related_name="agents")
|
|
262
|
-
auth: dict = fields.JSONField(null=True)
|
|
267
|
+
auth: dict[str, str] = fields.JSONField(null=True)
|
|
263
268
|
user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField("models.User", related_name="agents")
|
|
264
|
-
user_id: int
|
|
269
|
+
# user_id: int
|
|
265
270
|
assets: fields.ReverseRelation["Asset"]
|
|
266
271
|
orders: fields.ReverseRelation["Order"]
|
|
267
272
|
ads: fields.ReverseRelation["Ad"]
|
|
268
273
|
|
|
269
|
-
|
|
270
|
-
_name = {"ex__name", "user__username"}
|
|
271
|
-
|
|
272
|
-
# def repr(self, *args):
|
|
273
|
-
# return f"{self.ex.name}-{self.user.username}"
|
|
274
|
+
_name = {"exid"}
|
|
274
275
|
|
|
275
276
|
def balance(self) -> int:
|
|
276
|
-
return
|
|
277
|
-
# return sum(asset.free * (asset.coin.rate or 0) for asset in self.assets)
|
|
277
|
+
return sum(asset.free * (asset.coin.rate or 0) for asset in self.assets)
|
|
278
278
|
|
|
279
279
|
class Meta:
|
|
280
280
|
table_description = "Agents"
|
|
281
281
|
unique_together = (("ex", "user"),)
|
|
282
282
|
|
|
283
|
-
class PydanticMeta:
|
|
283
|
+
class PydanticMeta(Model.PydanticMeta):
|
|
284
284
|
computed = ["balance"]
|
|
285
285
|
|
|
286
286
|
# class PydanticMetaListItem:
|
|
@@ -302,7 +302,6 @@ class Adpm(Model):
|
|
|
302
302
|
ad: fields.ForeignKeyRelation["Ad"] = fields.ForeignKeyField("models.Ad")
|
|
303
303
|
pm: fields.ForeignKeyRelation["Pm"] = fields.ForeignKeyField("models.Pm")
|
|
304
304
|
|
|
305
|
-
# no need repr()
|
|
306
305
|
_name = {"ad__id", "pm__name"}
|
|
307
306
|
|
|
308
307
|
class Meta:
|
|
@@ -326,9 +325,6 @@ class Ad(Model, TsTrait):
|
|
|
326
325
|
_icon = "ad"
|
|
327
326
|
_name = {"direction__pair__coin__ticker", "direction__pair__cur__ticker", "direction__sell", "price"}
|
|
328
327
|
|
|
329
|
-
def repr(self, *args):
|
|
330
|
-
return f"{TradeType(int(self.direction.sell.name)).name}: {self.price:.3g}"
|
|
331
|
-
|
|
332
328
|
class Meta:
|
|
333
329
|
table_description = "P2P Advertisements"
|
|
334
330
|
|
|
@@ -350,12 +346,10 @@ class Pm(Model):
|
|
|
350
346
|
exs: fields.ManyToManyRelation[Ex] = fields.ManyToManyField(
|
|
351
347
|
"models.Ex", through="pmex"
|
|
352
348
|
) # no need. use pmexs[.exid]
|
|
353
|
-
|
|
349
|
+
orders: fields.ReverseRelation["Order"]
|
|
354
350
|
pmcurs: fields.ReverseRelation["Pmcur"] # no need. use curs
|
|
355
351
|
pmexs: fields.ReverseRelation["Pmex"]
|
|
356
352
|
|
|
357
|
-
_icon = "currency"
|
|
358
|
-
|
|
359
353
|
class Meta:
|
|
360
354
|
table_description = "Payment methods"
|
|
361
355
|
|
|
@@ -373,9 +367,6 @@ class Pmcur(Model): # for fiat with no exs tie
|
|
|
373
367
|
|
|
374
368
|
# _sorts = ['-limits_count']
|
|
375
369
|
|
|
376
|
-
def repr(self, *args):
|
|
377
|
-
return f"{self.pm.name}-{self.cur.ticker}"
|
|
378
|
-
|
|
379
370
|
# @classmethod
|
|
380
371
|
# def pydListItem(cls, max_recursion: int = 1, backward_relations: bool = False, exclude: tuple[str] = (), include: tuple[str] = (), force: bool = False) -> type[PydanticModel]:
|
|
381
372
|
# if not cls._pydListItem:
|
|
@@ -412,9 +403,6 @@ class Pmex(Model): # existence pm in ex with no cur tie
|
|
|
412
403
|
|
|
413
404
|
_name = {"pm__name", "ex__name"}
|
|
414
405
|
|
|
415
|
-
def repr(self, *args):
|
|
416
|
-
return f"{self.pm.name}-{self.ex.name}"
|
|
417
|
-
|
|
418
406
|
class Meta:
|
|
419
407
|
table_description = "Payment methods - Currencies"
|
|
420
408
|
unique_together = (("pm_id", "ex_id"), ("ex_id", "exid"))
|
|
@@ -429,9 +417,6 @@ class Pmcurex(Model): # existence pm in ex for exact cur, with "blocked" flag
|
|
|
429
417
|
|
|
430
418
|
_name = {"pmcur__pm__name", "pmcur__cur__ticker", "ex__name"}
|
|
431
419
|
|
|
432
|
-
def repr(self, *args):
|
|
433
|
-
return ("[X] " if self.blocked else "") + super().repr()
|
|
434
|
-
|
|
435
420
|
class Meta:
|
|
436
421
|
table_description = "Payment methods - Currencies"
|
|
437
422
|
|
|
@@ -439,8 +424,8 @@ class Pmcurex(Model): # existence pm in ex for exact cur, with "blocked" flag
|
|
|
439
424
|
class Fiat(Model):
|
|
440
425
|
pmcur: fields.ForeignKeyRelation[Pmcur] = fields.ForeignKeyField("models.Pmcur")
|
|
441
426
|
pmcur_id: int
|
|
442
|
-
|
|
443
|
-
|
|
427
|
+
country: fields.ForeignKeyRelation[Country] = fields.ForeignKeyField("models.Country", related_name="fiats")
|
|
428
|
+
country_id: int
|
|
444
429
|
detail: str = fields.CharField(127)
|
|
445
430
|
name: str | None = fields.CharField(127, null=True)
|
|
446
431
|
user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField("models.User", "fiats")
|
|
@@ -451,20 +436,16 @@ class Fiat(Model):
|
|
|
451
436
|
exs: fields.ManyToManyRelation[Ex] = fields.ManyToManyField("models.Ex", through="fiatex", related_name="fiats")
|
|
452
437
|
orders: fields.ReverseRelation["Order"]
|
|
453
438
|
|
|
454
|
-
_icon = "cash"
|
|
455
439
|
_name = {"pmcur__pm__name", "pmcur__cur__ticker", "amount"}
|
|
456
440
|
|
|
457
|
-
def repr(self, *args):
|
|
458
|
-
return f"{self.id}: {self.pmcur.repr()} ({self.user.username})"
|
|
459
|
-
|
|
460
441
|
class Meta:
|
|
461
442
|
table_description = "Currency accounts balance"
|
|
462
443
|
|
|
463
|
-
class PydanticMetaListItem:
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
444
|
+
# class PydanticMetaListItem:
|
|
445
|
+
# max_recursion: int = 2
|
|
446
|
+
# backward_relations = False
|
|
447
|
+
# exclude = "user", "pmcur__exs"
|
|
448
|
+
# # exclude_raw_fields = True
|
|
468
449
|
|
|
469
450
|
|
|
470
451
|
class Fiatex(Model): # existence pm in ex with no cur tie
|
|
@@ -476,9 +457,6 @@ class Fiatex(Model): # existence pm in ex with no cur tie
|
|
|
476
457
|
|
|
477
458
|
_name = {"fiat__detail", "ex__name"}
|
|
478
459
|
|
|
479
|
-
def repr(self, *args):
|
|
480
|
-
return f"{self.fiat.detail}-{self.ex.name}"
|
|
481
|
-
|
|
482
460
|
class Meta:
|
|
483
461
|
table_description = "Fiat on Ex"
|
|
484
462
|
unique_together = (("fiat_id", "ex_id"), ("ex_id", "exid"))
|
|
@@ -496,12 +474,8 @@ class Limit(Model):
|
|
|
496
474
|
added_by: fields.ForeignKeyRelation["User"] = fields.ForeignKeyField("models.User", related_name="limits")
|
|
497
475
|
added_by_id: int
|
|
498
476
|
|
|
499
|
-
_icon = "frame"
|
|
500
477
|
_name = {"pmcur__pm__name", "pmcur__cur__ticker", "unit", "income", "amount"}
|
|
501
478
|
|
|
502
|
-
def repr(self, *args):
|
|
503
|
-
return f"{self.pmcur.repr()}[{'<-' if self.income else '->'}]"
|
|
504
|
-
|
|
505
479
|
class Meta:
|
|
506
480
|
table_description = "Currency accounts balance"
|
|
507
481
|
|
|
@@ -517,18 +491,14 @@ class Asset(Model):
|
|
|
517
491
|
lock: float | None = fields.FloatField(default=0)
|
|
518
492
|
target: float | None = fields.FloatField(default=0, null=True)
|
|
519
493
|
|
|
520
|
-
_icon = "currency-bitcoin"
|
|
521
494
|
_name = {"coin__ticker", "free"}
|
|
522
495
|
|
|
523
|
-
def repr(self, *args):
|
|
524
|
-
return f"{self.coin.ticker} {self.free:.3g}/{self.freeze:.3g} user:{self.agent.repr()}"
|
|
525
|
-
|
|
526
496
|
class Meta:
|
|
527
497
|
table_description = "Coin balance"
|
|
528
498
|
unique_together = (("coin", "agent", "type_"),)
|
|
529
499
|
|
|
530
|
-
class PydanticMeta:
|
|
531
|
-
|
|
500
|
+
# class PydanticMeta(Model.PydanticMeta):
|
|
501
|
+
# exclude_raw_fields: bool = False
|
|
532
502
|
|
|
533
503
|
|
|
534
504
|
class Order(Model, TsTrait):
|
|
@@ -538,19 +508,16 @@ class Order(Model, TsTrait):
|
|
|
538
508
|
amount: float = fields.FloatField()
|
|
539
509
|
fiat: fields.ForeignKeyRelation[Fiat] = fields.ForeignKeyField("models.Fiat", related_name="orders", null=True)
|
|
540
510
|
fiat_id: int | None
|
|
541
|
-
# pm: fields.ForeignKeyRelation[Pm] = fields.ForeignKeyField("models.Pm", related_name="orders", null=True) # why commented: already has in fiat.pmcur.pm
|
|
542
|
-
# pm_id: int | None
|
|
543
511
|
taker: fields.ForeignKeyRelation[Agent] = fields.ForeignKeyField("models.Agent", "orders")
|
|
544
512
|
taker_id: int
|
|
545
513
|
status: OrderStatus = fields.IntEnumField(OrderStatus)
|
|
546
514
|
notify_pay_at: datetime | None = DatetimeSecField(null=True)
|
|
547
515
|
confirm_pay_at: datetime | None = DatetimeSecField(null=True)
|
|
548
516
|
|
|
549
|
-
|
|
550
|
-
_name = {"fiat__pmcur__pm__name", "ad__direction__sell"}
|
|
517
|
+
_name = {"fiat__pmcur__pm__name"}
|
|
551
518
|
|
|
552
|
-
def repr(self
|
|
553
|
-
return f"{self.
|
|
519
|
+
def repr(self):
|
|
520
|
+
return f"{self.fiat.pmcur.pm.name}/{self.fiat_id}:{self.amount:.3g} {self.status.name}"
|
|
554
521
|
|
|
555
522
|
class Meta:
|
|
556
523
|
table_description = "P2P Orders"
|
|
@@ -611,22 +578,22 @@ class Order(Model, TsTrait):
|
|
|
611
578
|
# table_description = "Investments"
|
|
612
579
|
|
|
613
580
|
|
|
614
|
-
class TestEx(Model):
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
581
|
+
# class TestEx(Model):
|
|
582
|
+
# ex: fields.ForeignKeyRelation[Ex] = fields.ForeignKeyField("models.Ex", related_name="tests")
|
|
583
|
+
# # ex_id: int
|
|
584
|
+
# action: ExAction = fields.IntEnumField(ExAction)
|
|
585
|
+
# ok: bool | None = fields.BooleanField(default=False, null=True)
|
|
586
|
+
# updated_at: datetime | None = DatetimeSecField(auto_now=True)
|
|
587
|
+
#
|
|
588
|
+
# _icon = "test-pipe"
|
|
589
|
+
# _name = {"ex__name", "action", "ok"}
|
|
590
|
+
#
|
|
591
|
+
# def repr(self, *args):
|
|
592
|
+
# return f"{self.ex.name} {self.action.name} {self.ok}"
|
|
593
|
+
#
|
|
594
|
+
# class Meta:
|
|
595
|
+
# table_description = "Test Exs"
|
|
596
|
+
# unique_together = (("action", "ex"),)
|
|
630
597
|
|
|
631
598
|
|
|
632
599
|
# class Vpn(Model):
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
from pydantic import BaseModel
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class FiatUpd(BaseModel):
|
|
5
|
+
detail: str | None = None
|
|
6
|
+
name: str | None = None
|
|
7
|
+
amount: float | None = None
|
|
8
|
+
target: int | None = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FiatNew(FiatUpd):
|
|
5
12
|
cur_id: int
|
|
6
13
|
pm_id: int
|
|
7
14
|
user_id: int
|
|
8
15
|
detail: str
|
|
9
|
-
|
|
10
|
-
amount: float
|
|
11
|
-
target: int | None = None
|
|
16
|
+
amount: float = 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|