From 88a3c7a077cd2cb030ff4bd25f050cfb8b53b469 Mon Sep 17 00:00:00 2001 From: ThisPythonJS Date: Sat, 2 May 2026 06:53:47 -0300 Subject: [PATCH 01/22] feat: add icons, snapshots, UI improvements and more. --- CHANGELOG.md | 11 ++ l10n/bundle.l10n.json | 19 ++- l10n/bundle.l10n.pt.json | 21 +++- package.json | 90 ++++++++++++-- package.nls.json | 10 +- package.nls.pt.json | 10 +- resources/dark/bot.svg | 1 + resources/icons/carbon.png | Bin 0 -> 15809 bytes resources/icons/diamond.png | Bin 0 -> 18092 bytes resources/icons/free.png | Bin 0 -> 13099 bytes resources/icons/gold.png | Bin 0 -> 17882 bytes resources/icons/krypton.png | Bin 0 -> 16435 bytes resources/icons/platinum.png | Bin 0 -> 21343 bytes resources/icons/ruby.png | Bin 0 -> 15695 bytes resources/icons/sapphire.png | Bin 0 -> 21013 bytes resources/icons/vibranium.png | Bin 0 -> 17343 bytes resources/light/bot.svg | 1 + src/@types/api.ts | 55 +++++++++ src/@types/structures.ts | 15 +++ src/commands.ts | 7 ++ src/commands/snapshot/create.ts | 29 +++++ src/commands/snapshot/download.ts | 29 +++++ src/commands/snapshot/refresh.ts | 12 ++ src/commands/subdomain/create.ts | 39 ++++++ src/commands/subdomain/delete.ts | 35 ++++++ src/core/extension.ts | 4 + src/events/activate.ts | 6 +- src/events/missingToken.ts | 7 ++ src/events/unauthorized.ts | 7 ++ src/events/vscode.ts | 19 ++- src/localize.ts | 47 +++++-- src/providers/SnapshotTreeDataProvider.ts | 70 +++++++++++ src/structures/BaseChildTreeItem.ts | 2 +- src/structures/SnapshotAppTreeItem.ts | 143 ++++++++++++++++++++++ src/structures/SnapshotInfoTreeItem.ts | 15 +++ src/structures/SnapshotVersionTreeItem.ts | 63 ++++++++++ src/structures/SubDomainTreeItem.ts | 2 + src/structures/UserAppTreeItem.ts | 3 +- src/structures/UserAppTypeTreeItemView.ts | 20 ++- src/structures/UserTreeItem.ts | 74 ++++++++++- src/structures/VSUser.ts | 7 +- src/utils/constants.ts | 1 + src/utils/plans.ts | 75 ++++++++++++ src/utils/utils.ts | 11 ++ 44 files changed, 913 insertions(+), 47 deletions(-) create mode 100644 resources/dark/bot.svg create mode 100644 resources/icons/carbon.png create mode 100644 resources/icons/diamond.png create mode 100644 resources/icons/free.png create mode 100644 resources/icons/gold.png create mode 100644 resources/icons/krypton.png create mode 100644 resources/icons/platinum.png create mode 100644 resources/icons/ruby.png create mode 100644 resources/icons/sapphire.png create mode 100644 resources/icons/vibranium.png create mode 100644 resources/light/bot.svg create mode 100644 src/commands/snapshot/create.ts create mode 100644 src/commands/snapshot/download.ts create mode 100644 src/commands/snapshot/refresh.ts create mode 100644 src/commands/subdomain/create.ts create mode 100644 src/commands/subdomain/delete.ts create mode 100644 src/providers/SnapshotTreeDataProvider.ts create mode 100644 src/structures/SnapshotAppTreeItem.ts create mode 100644 src/structures/SnapshotInfoTreeItem.ts create mode 100644 src/structures/SnapshotVersionTreeItem.ts create mode 100644 src/utils/plans.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fb0c430..b7ff070d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ Seja Bem-Vindo a nossa página e atualização da Extensão da Discloud. Aqui vo --- +## 2.31.0 + +- Adição de ícones na interface da extensão, presentes em praticamente todas as seções, incluindo Apps (ao lado de Bot e Site), User e Snapshots. +- Correção de bugs no sistema de tradução, que anteriormente não aplicava grande parte dos textos. +- Implementação do novo sistema de Snapshots da Discloud: agora é possível selecionar seu app, visualizar os snapshots disponíveis e salvá-los diretamente no seu computador. +- Melhoria no gerenciamento de subdomínios, permitindo criar e deletar diretamente pela extensão, sem precisar acessar o dashboard. +- Atualizações na interface de User: + - Exibição da RAM em MB de forma mais organizada + - Visualização do plano com suporte a português/inglês, acompanhado de ícone + - Identificação do idioma mais clara (ex: de pt-BR para Português (BR)) + ## 2.30.0 - Correção no sistema de autenticação, e orquestração de sessão. diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index 83721d69..bbce7d90 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -60,10 +60,17 @@ "input.set.locale.available.title": "These are the available languages.", "input.set.locale.prompt": "Set your language.", "input.set.locale.validate": "Language must be like en-US.", + "input.subdomain.prompt": "Enter the subdomain name.", + "input.subdomain.validate": "Subdomain must use 2-20 lowercase letters, numbers or hyphens.", "invalid.discloud.config": "The discloud.config file is invalid or does not exist.", "invalid.discloud.config.main": "The {file} file specified in the main scope does not exist.", "invalid.input": "Invalid input", "invalid.token": "Invalid token.", + "label.user": "User", + "label.customdomain": "Custom Domains", + "label.snapshot": "Snapshot", + "label.teamapps": "Team Apps", + "label.subdomain": "Subdomains", "label.apps.amount": "Amount of Apps", "label.available.ram": "Available RAM", "label.cpu": "CPU", @@ -81,6 +88,8 @@ "missing.discloud.config.main": "The {file} file was not found in the list to ZIP.", "missing.input": "Missing input", "missing.locale": "Missing locale", + "missing.snapshot.version": "Missing snapshot version", + "missing.subdomain": "Missing subdomain", "missing.moderator": "Missing mod", "missing.moderator.id": "Missing mod ID", "missing.team.appid": "Team app ID not found.", @@ -91,6 +100,7 @@ "no.app.found": "No app found.", "no.apps.found.to.choose": "No apps found, please upload before that.", "no.backup.found": "No backup found", + "no.snapshot.found": "No snapshots found.", "no.folder.found": "No folder found", "no.log.found": "No log found", "no.workspace.folder.found": "No workspace folder found", @@ -123,15 +133,22 @@ "progress.mod.rem.title": "Remove MOD", "progress.ram.title": "RAM", "progress.restart.title": "Restart", + "progress.snapshot.create.title": "Create snapshot", + "progress.snapshot.download.title": "Download snapshot", "progress.start.title": "Start", "progress.status.title": "Status", "progress.stop.title": "Stop", + "progress.subdomain.create.title": "Create subdomain", + "progress.subdomain.delete.title": "Delete subdomain", "progress.upload.title": "Upload", "ratelimited": "You have reached the request limit. Try again in {s} seconds.", "readdiscloudconfigdocs": "Read the [documentation](https://docs.discloud.com/en/discloud.config).", "readdocs": "Read the [documentation](https://docs.discloud.com/en).", "refreshing": "Refreshing...", "rejected.action": "Rejected action", + "snapshot.created.at": "Created at", + "snapshot.size": "Size", + "snapshot.version": "Version", "see.also.your.apps": "See also your apps", "see.also.your.n.apps": "See also your {n} apps", "see.also.your.n.team.apps": "See also the {n} apps of their teams", @@ -170,4 +187,4 @@ "valid.token": "Token set up successfully!", "your.app.is.now": "Your app {app} is now", "your.team.app.is.now": "Your team app {app} is now" -} \ No newline at end of file +} diff --git a/l10n/bundle.l10n.pt.json b/l10n/bundle.l10n.pt.json index 9ffe0162..0f4365f4 100644 --- a/l10n/bundle.l10n.pt.json +++ b/l10n/bundle.l10n.pt.json @@ -2,7 +2,7 @@ "action.cancel": "Cancelar", "action.cancelled": "Ação cancelada", "action.ok": "Ok", - "action.title": "Tem certeza que quer fazer {action}?", + "action.title": "Are you sure you want to perform this action?", "app.status.errorCode": "Erro de código", "app.status.off": "Desligado", "app.status.on": "Ligado", @@ -60,10 +60,27 @@ "input.set.locale.available.title": "Estes são os idiomas disponíveis.", "input.set.locale.prompt": "Defina seu idioma.", "input.set.locale.validate": "Idioma deve ser como pt-BR.", + "input.subdomain.prompt": "Digite o nome do subdominio.", + "input.subdomain.validate": "O subdominio deve usar 2-20 letras minusculas, numeros ou hifens.", + "missing.snapshot.version": "Versao do snapshot nao encontrada", + "missing.subdomain": "Subdominio nao encontrado", + "no.snapshot.found": "Nenhum snapshot encontrado.", + "progress.snapshot.create.title": "Criar snapshot", + "progress.snapshot.download.title": "Baixar snapshot", + "progress.subdomain.create.title": "Criar subdominio", + "progress.subdomain.delete.title": "Remover subdominio", + "snapshot.created.at": "Criado em", + "snapshot.size": "Tamanho", + "snapshot.version": "Versao", "invalid.discloud.config": "O arquivo discloud.config é inválido ou não existe.", "invalid.discloud.config.main": "O arquivo {file} especificado no escopo principal não existe.", "invalid.input": "Entrada inválida", "invalid.token": "Token inválido.", + "label.user": "Usuário", + "label.customdomain": "Domínios Customizados", + "label.snapshot": "Snapshot", + "label.teamapps": "Apps de Equipe", + "label.subdomain": "Subdomínios", "label.apps.amount": "Quant. de apps", "label.available.ram": "RAM disponível", "label.cpu": "CPU", @@ -170,4 +187,4 @@ "valid.token": "Token configurado com sucesso!", "your.app.is.now": "Seu app {app} agora está", "your.team.app.is.now": "Seu app de equipe {app} agora está" -} \ No newline at end of file +} diff --git a/package.json b/package.json index e5ad35b2..848adeef 100644 --- a/package.json +++ b/package.json @@ -244,6 +244,31 @@ "title": "%command.subdomain.refresh%", "icon": "$(refresh)" }, + { + "command": "discloud.subdomain.create", + "title": "%command.subdomain.create%", + "icon": "$(add)" + }, + { + "command": "discloud.subdomain.delete", + "title": "%command.subdomain.delete%", + "icon": "$(trash)" + }, + { + "command": "discloud.snapshot.refresh", + "title": "%command.snapshot.refresh%", + "icon": "$(refresh)" + }, + { + "command": "discloud.snapshot.download", + "title": "%command.snapshot.download%", + "icon": "$(cloud-download)" + }, + { + "command": "discloud.snapshot.create", + "title": "%command.snapshot.create%", + "icon": "$(history)" + }, { "command": "discloud.team.backup", "title": "%command.team.backup%", @@ -585,8 +610,8 @@ ".discloudignore" ], "icon": { - "dark": "resources/icons/discloud_icon.svg", - "light": "resources/icons/discloud_icon.svg" + "dark": "resources/icons/discloud_white_icon.svg", + "light": "resources/icons/discloud_white_icon.svg" } }, { @@ -595,8 +620,8 @@ "discloud.config" ], "icon": { - "dark": "resources/icons/discloud_icon.svg", - "light": "resources/icons/discloud_icon.svg" + "dark": "resources/icons/discloud_white_icon.svg", + "light": "resources/icons/discloud_white_icon.svg" } } ], @@ -1005,6 +1030,26 @@ "command": "discloud.user.set.locale", "when": "view == discloudUser && discloudAuthorized" }, + { + "command": "discloud.subdomain.delete", + "group": "inline", + "when": "view == discloudSubdomains && viewItem =~ /^SubDomainTreeItem/" + }, + { + "command": "discloud.snapshot.create", + "group": "1", + "when": "view == discloudUserApps && discloudAppLength && viewItem =~ /^TreeItem/" + }, + { + "command": "discloud.snapshot.create", + "group": "1", + "when": "view == discloudSnapshots && viewItem =~ /^SnapshotAppTreeItem/" + }, + { + "command": "discloud.snapshot.download", + "group": "inline", + "when": "view == discloudSnapshots && viewItem =~ /^SnapshotVersionTreeItem/" + }, { "command": "discloud.logout", "group": "inline", @@ -1048,6 +1093,16 @@ "when": "view == discloudSubdomains", "group": "navigation" }, + { + "command": "discloud.subdomain.create", + "when": "view == discloudSubdomains", + "group": "navigation" + }, + { + "command": "discloud.snapshot.refresh", + "when": "view == discloudSnapshots && discloudAuthorized", + "group": "navigation" + }, { "command": "discloud.team.refresh", "when": "view == discloudTeamApps", @@ -1218,7 +1273,7 @@ { "type": "tree", "id": "discloudUserApps", - "icon": "resources/icons/discloud_icon.svg", + "icon": "resources/icons/discloud_white_icon.svg", "name": "%view.apps.title%", "visibility": "visible", "when": "discloudAuthorized" @@ -1226,31 +1281,39 @@ { "type": "tree", "id": "discloudTeamApps", - "icon": "resources/icons/discloud_icon.svg", + "icon": "resources/icons/discloud_white_icon.svg", "name": "%view.team.title%", "visibility": "collapsed", "when": "discloudAuthorized" }, + { + "type": "tree", + "id": "discloudSnapshots", + "icon": "resources/icons/discloud_white_icon.svg", + "name": "%view.snapshot.title%", + "visibility": "collapsed", + "when": "discloudAuthorized" + }, { "type": "tree", "id": "discloudSubdomains", - "icon": "resources/icons/discloud_icon.svg", + "icon": "resources/icons/discloud_white_icon.svg", "name": "%view.subdomain.title%", "visibility": "collapsed", - "when": "discloudAuthorized" + "when": "discloudAuthorized && discloudHasSubdomainsAccess" }, { "type": "tree", "id": "discloudDomains", - "icon": "resources/icons/discloud_icon.svg", + "icon": "resources/icons/discloud_white_icon.svg", "name": "%view.domain.title%", "visibility": "collapsed", - "when": "discloudAuthorized" + "when": "discloudAuthorized && discloudHasCustomDomainsAccess" }, { "type": "tree", "id": "discloudUser", - "icon": "resources/icons/discloud_icon.svg", + "icon": "resources/icons/discloud_white_icon.svg", "name": "%view.user.title%", "visibility": "collapsed" } @@ -1261,7 +1324,7 @@ { "id": "discloudActivityBar", "title": "Discloud", - "icon": "resources/icons/discloud_icon.svg" + "icon": "resources/icons/discloud_white_icon.svg" } ] }, @@ -1325,6 +1388,7 @@ "bytes": "^3.1.2", "jose": "^6.2.3", "json-schema-library": "^11.4.0", + "path": "^0.12.7", "ws": "^8.20.0", "yocto-queue": "^1.2.2" }, @@ -1347,4 +1411,4 @@ "npm-run-all": "^4.1.5", "typescript": "^5.9.3" } -} \ No newline at end of file +} diff --git a/package.nls.json b/package.nls.json index 1c7606e1..d3ee3ec0 100644 --- a/package.nls.json +++ b/package.nls.json @@ -25,6 +25,11 @@ "command.login": "Login Discloud", "command.logout": "Logout Discloud", "command.logs": "Get app logs", + "command.snapshot.create": "Create snapshot", + "command.snapshot.download": "Download snapshot", + "command.snapshot.refresh": "Refresh snapshot list", + "command.subdomain.create": "Create subdomain", + "command.subdomain.delete": "Delete subdomain", "command.subdomain.refresh": "Refresh subdomain list", "command.team.backup": "Backup team app", "command.team.commit": "Commit team app", @@ -76,7 +81,7 @@ "config.team.sort.by.title": "Sort team app by", "config.team.sort.online.description": "Show team apps with online status first", "config.team.sort.online.title": "Show online team app first", - "config.token.description": "Your [Discloud](https://discloudbot.com) API token.", + "config.token.description": "Your [Discloud](https://discloud.com) API token.", "config.upload.focus.logs": "Focus of logs during upload", "config.upload.focus.logs.always.label": "Always", "config.upload.focus.logs.errors.label": "Errors", @@ -100,6 +105,7 @@ "submenu.team.sort.by": "Sort team apps by", "view.apps.title": "Apps", "view.domain.title": "Custom domains", + "view.snapshot.title": "Snapshots", "view.subdomain.title": "Subdomains", "view.team.title": "Team apps", "view.user.title": "User", @@ -110,4 +116,4 @@ "welcome": "Welcome!", "welcome.token.missing": "You have not yet provided a token to access Discloud resources.\n[Submit your Discloud token](command:discloud.login)", "welcome.token.unauthorized": "You provided an invalid token to access Discloud resources.\n[Submit your Discloud token](command:discloud.login)" -} \ No newline at end of file +} diff --git a/package.nls.pt.json b/package.nls.pt.json index ad6af558..eb5034f0 100644 --- a/package.nls.pt.json +++ b/package.nls.pt.json @@ -25,6 +25,11 @@ "command.login": "Login Discloud", "command.logout": "Logout Discloud", "command.logs": "Obter logs do app", + "command.snapshot.create": "Criar snapshot", + "command.snapshot.download": "Baixar snapshot", + "command.snapshot.refresh": "Atualizar lista de snapshots", + "command.subdomain.create": "Criar subdominio", + "command.subdomain.delete": "Remover subdominio", "command.subdomain.refresh": "Atualizar lista de subdomínios", "command.team.backup": "Backup app de equipe", "command.team.commit": "Commitar app de equipe", @@ -76,7 +81,7 @@ "config.team.sort.by.title": "Ordenar app de equipe por", "config.team.sort.online.description": "Mostrar apps de equipe com status online primeiro.", "config.team.sort.online.title": "Mostrar apps de equipe online primeiro", - "config.token.description": "Seu token da API da [Discloud](https://discloudbot.com).", + "config.token.description": "Seu token da API da [Discloud](https://discloud.com).", "config.upload.focus.logs": "Foco dos logs durante o upload", "config.upload.focus.logs.always.label": "Sempre", "config.upload.focus.logs.errors.label": "Erros", @@ -99,6 +104,7 @@ "submenu.manage.mods": "Gerenciar equipe", "submenu.team.sort.by": "Ordenar apps de equipe por", "view.apps.title": "Apps", + "view.snapshot.title": "Snapshots", "view.domain.title": "Domínios personalizados", "view.subdomain.title": "Subdomínios", "view.team.title": "Apps de equipe", @@ -110,4 +116,4 @@ "welcome": "Bem vindo!", "welcome.token.missing": "Você ainda não forneceu um token para ter acesso aos recursos da Discloud.\n[Envie seu token Discloud](command:discloud.login)", "welcome.token.unauthorized": "Você forneceu um token inválido para acessar os recursos do Discloud.\n[Envie seu token Discloud](command:discloud.login)" -} \ No newline at end of file +} diff --git a/resources/dark/bot.svg b/resources/dark/bot.svg new file mode 100644 index 00000000..dd88ace2 --- /dev/null +++ b/resources/dark/bot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/carbon.png b/resources/icons/carbon.png new file mode 100644 index 0000000000000000000000000000000000000000..98c9769cc7349882fdd9005e30678652fa1425a3 GIT binary patch literal 15809 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 literal 0 HcmV?d00001 diff --git a/resources/icons/diamond.png b/resources/icons/diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..216321c3c682690ef23ead491b35afdfd93e7357 GIT binary patch literal 18092 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 literal 0 HcmV?d00001 diff --git a/resources/icons/free.png b/resources/icons/free.png new file mode 100644 index 0000000000000000000000000000000000000000..49ac431ffae8264e670ab3db95c8f775ae3dff68 GIT binary patch literal 13099 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 G(EkG2RcSu} literal 0 HcmV?d00001 diff --git a/resources/icons/gold.png b/resources/icons/gold.png new file mode 100644 index 0000000000000000000000000000000000000000..4cecae696f067c4e4ed2d237cdc9967e05fe8f6a GIT binary patch literal 17882 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 literal 0 HcmV?d00001 diff --git a/resources/icons/platinum.png b/resources/icons/platinum.png new file mode 100644 index 0000000000000000000000000000000000000000..8153ebc49b65a578c7a7c02550a43b8c4ee8b50f GIT binary patch literal 21343 zcmZ^K1yCKq)91q_xIWx1xVyW%I}e9IaQEO&aCaxT1Shyl@Zj$5^7#1QclBLe)!k0b zcJFj|_3qZxZqKiKB2|>6krD9`0RRB9tc--(Ck^~hhll+<_Y0Yhe-cuVjG7_<;7$EG z{sRDb`H%bv0B~ag08UH*0KRkp0QY-#yQ;va0M<-iS_1I#pO)WM_VaTD!qHht17f<+ zBlGiu%2iUw)!fw8f)C_u@ksz|ENoniES!uiY#Jw&MMjHQhE@Ab67iqJhxtqL4_1>5_>W4V_voHHIGy`lqzD z{d#ue4}7vMd1ra&hGm95&3naXDdv&~+3cdhCa@v^Xwd-#ZdVV@oJZ-$oZsv~O0{GO z;k;)oSdWXY^#wPj9KL7x%`#GQcJKvUS%Q=_mNiYjRxbo17c&c4CV6=uhE{fy+Fy?S z<5*?HF-cMq1<1<^IF_qg^xNss@8dRy)zRyPTc1Mt#6uk9*#)~6uKI`6p%I}iaCLUf4~ket#Fze8$n?IQZMx$DKz0$E|v`zjJD zVJOTaw{i-Ac-Xzb8Sl)2lq#(Pt(B_*b(-BLvL7A=)lldJ1vnyD8l(|kl+oMtCfyAO zXN@E-Lsxf0W!6@Pm`!L&lqgg9bCe=G6a`nVVxl-uWS$XvQwxFc<-xNzk9}L42wNtY z{E#Rn08D6+V3We$tt}H4QL^zFwD|il59mLy8oN}w8qqM-0O(#yQ3x|E2KWjc=&E&< zH5q#HUN>t1)VKAPT?) z4Kxn~#lW$UyEa@f&^%OP-3oC!TM+kGixg|gkHo$N{~-lJ<_8W%B>^I^s7uWZRk3(L zGWENv_hB+`YFNLB@CjGdJ(Y70e{AJMNs!t)dgGT04fkO7(q}I>5p7Dt3%Ys%qQwiT zdrQpry2`yemcA>X)lHF+_t{Alai`OAAW!~ODt&)*U*<-P#YaM|+nQK7)B6CP5kkZ- z!oqR zaO4Uw3)DnfY z6FyW>((y#fd)ePC>9U~NBif6>d^(^0U?kuc9%lCt8WHE-fIZElopz;{i%GQp4q;~& zSYCdG^f}MEq1WK@@kK*a2UUn!Uq0Wf9F3Nmh$E*M37ihh8|jtN7P8d0OAtO1nQdJg z?S##rq~G8BR_UMJL^`DUS^H&1Zd_*e3j$9zT>?D)q-P)En|&c?U^fAlJQn-hyes7CGm88{`>oZ zfBPwJJ7%@W5N(%ymZ-?;2`JF@VZdFnflkTLM~VaId{zGeG$djW5{`HEnATox8J?p|G=bqxVqReexVlIqI2jVb)JrsVuPt-^OrYMX<5!ii)Y~T;ZhxI@6 zJM-Ohx_Dnij#=}LKLR^xV~LQaW|Mhnz4P|+7QW^FVeG{Xa>TQcMlC8yK!8V|2+H2} zfv)9+pp<3XZ$_2$0-;MFS=9(;y^Y8}v4;Hu1)OimoqjlV;GL~0DIAFt9%6MNDDZjwTx;W51aFd_ct zO>PoAsAc=3*(-$Zl2hqRmd|bAdTjv`f~{^|^E#bWQpA`R{#f(8?0Qr(MYIeCH_wyP zHb-htRiQE}bRS6fxdh()n&3FgMuHhFYtVW_C(M;7iE2XgspaXu|3RJ-Gby0>|lly@b`O3cLZZ z5ScUuW~F3;>vt%G#L(ZrBrSFq^aY^Pdl-1mN)}jq{JzZXkf?6NPTkRfgvUJVp$x>+ z8A2z5*ffSFl~e_ytAZ4;taz^nFuhDqAJp|hMVE4LnU_orI}Dv_wF?nJz#41xPO?Zb z_R#(4I^3LLyfnk!H_Z6{2?8@pbJq|Wo?&aBY!ik>y?MM~dB9(3K;q}K5VArnTYK9f ztFns9k|Sj$uZXle{>X`U+}kE_G#hUH6*9>zhAuO2qpo1@HY}-ThiGgv2R$G}tiR4I zFZkYbI>qPnE{-ZNqfY=8F_>}_oJi5*3Odi%;^b)}RdW7U%9LR^&^k zT*5<01SKcSP(I>Sd~GIYktV#?8ZuMkGV-7&aQvNv>(Ks1>QPJxMUrODTFSR>C|bhU z!~mlR)dPJOH+Iz#kOi=h#0VMiG>6V7j4klu>pWl+fiDp2j_kG9{H0`YWAsJ)Ae5wK zlCO^*IqgNM^&8LuNJ}`5(@(Hef6~Cs*0iI8!)UDJU@Co-a7clLgNSNIq(pX2Drw%k zaD~&ZM`nD4FcYp*JQ|9DjyBea8zDt4;a>)TftAUDBA3Ki#ucnk1fu?#;oq2`a`d4G z@q08{yi*9=ECdAmTyULDBb^7+%2LY3;1i8VmK#7Hpav00-bK@H##Q>vT5E7Bp#?rn zUSgBJ_(%Z)OOlTQu%3z|81DNh%t#f*BGAn&`B?cZm$oMs2tBrWv%LqYma(H(G;yU6 z1aeyC%j9ZY!Q~p|nBSp;d1sC=G*#uyiRly$%k>x?=d9+hOPj*++bs1vBpU1qJ-Zy98d&2}Vg)O^!Upxz!7$Wbq>&p;&)-NG*6&9-*M$ zj`tqEE?#hkXe$EP)yxqu(W=ePe~p+4PoQX30weg z!YqXA`2WSP!fpWPbqc>i59-K=>LNmIq>j)cE!(o+LAQ<|Ew&v4b77qhgfXi?q;Ty3 zU}hV_O%!D8iW}B64@FxT%_{Z1RE`CSFK(INmEf6=?HA?EYXCuySJ&0@Pp!u@nsV*k zq;%@Ymo;VxFuG^zT(^nj9w$ZcQWDhNVn8nNy;Guo1DGd&z|tFK!JzAbGi>b7dOIx? z`(PqgMQz_agR=00ENU#7XDx+%?=p@pJ>%a?r&jZ_V(G|r<{;SM8Ts!!O^&f z+9IJ54o_@18H4FkvpuL|_lFxmO@p^nTd_Nm@~;()W&1@*^8}cWM-}~*^>@2~W|m08 zd0{GughGJJ8%6)cg zNH1jfuV=^!MlEqJOhN=+Uby_1Ug`S6*TZ#oc?*f?j>#!PSC2y@s8R!>42t6lx`)T7 z;B|_?{y>;c_#PrCN7Sh&^Qi=J{_JNv;pv-JY= zg|L)tKf~rhyXpzdXbK;{a>uBU)HkzSiKlp~=xSdaF`>mA2Y=o)7P55wPTs|39>8q7 zNKBbG`hT=u6+QHGjcm)W=&< zb^D2$(a7quUaaNZlahkziErtb;N$_-N0r-TJ$F=gIWJ3{5e6*3&GD*PX5&)`ZU1|h z8j3T=*z4f)hPRV1yzk<|kj+0#>{@6!0-ycRy`m$Y#>gIsLNCuw*tcQyA>PE%ibP`) zfZIvU+3$TG^}Ke8RCF~H$}7*cRKQTmWaxyjn-9$8c-f%qN%WH6Ka$gX8aJk@nqcQb)Kchz{DlBXzCDd!sqXCMiO6 zl2kB4iYOyOMx(>MFC&(e^6O?6k*IdE6uD4!H$FbVOxaCQ!1;vISzt$R`ko7ZVSj{1 z5zVzfoYpZvlwi*NbPzXy*or~k%4Nk7jOa9o(c-S}TGJm*7LkE9Vnl()xolmRLT!Qt zTU3x?gEwHR7&%BjXAcwBI5%Mjk_9whUO^JUCyL-{;In#yJQHPnMtwK#4+9{FnIMt1 zBz!Ze9bIkSm8&?xaYQh+;ODWL(}bhMrw@QIl&7ZK1fJyz^BeSbwPq&=S6nk)UotBG ztD_&5siGj+FYXxpn1_LeilX6{*kJBN+Qi>US7%VD;v0+}J;3D$^4BHd@hfXld^v|% zhJ2&<0OyLA;i^y`Q^zB^XH}$~lg?^69zSd=@TzogZ?DK-?9j)`7xb-=@J~F872#M+AvS%bNj7t6ldk0y~ zrXe`Br+M0SxR}K~P}V)zQh@}2%tghgbQ`Ez3*4QVPaF=;lus{1=+Am|IvxIis|f&W zFK>o<8WAfH{fCnaB||ji`+P^h8X`t#`M%>Y~ed=ziK0As+c#x{C)%y%SoyrQ-&LX zoqJtw;+7~qIh3lC`mTz{w3TkX;_*nacFP}tM9?ZCpV)-Zr>^hCV7lBV^Thx%V{YXN zD}LPxuAe?`ci^WIP+z3)vCcjN5GkjuTu9OhZ052X3<@iN=k#`AxhmLJ{k)%;eB zi}(!!6g4GS&}Q*RO{;$DGA~DA#NU71otq@|eD@-u#ewV5O3fzySM9a|uI<`uf@ zAfaH&76%e<%~fs6Q6uORd*{z1H6Yz&Ck}I8jl2x&b~#f;r%qUHF2m2Oj~QU;6A7xF zuM`QxdkZMPw*Aq7DoFtLgJ=C1^qdI)`Q`hZ`g!W(4oLaBr@*%&wpaWaRUM8a;)M8I zJ4Z;M>qd=metyE{^@8yoJ$Ln(UXP~h8AB6_J?-F!k`>g)*ZoN?l$y)$r*11Q9|>M) zq~`;N0$sw=;cX6hW#N_|n)TaGwf%AZED0p~fb#aOb!9aNhaV5qy087hBi)%~j+Cx7 z2`DJeFEDnzk7L|U|C*QjF1mp9)@30=zawcbJEM7{aT{J@)K}D95o{2FeCvd=47FiU z15xjfQaz<)kX#Z;O;QfXc1p(MVP(c5c^eGY(1Y;Ta-zatV$zHSvN;4b!}#Y-DWlKe! zFn!u*C4Sn>JN*6e&b$0~DC0-EM~~$+sWGDG=UWuSyjG&1CS1+HNN_} zwoR=B+!2h}&;!w_fZDw3-hVcWANNx*MK;A`tBs^FtaNjc%r5-G{(=8}gikeli1P>Q z6vAX*Ep9#og~8z;If>i&l7`k+j5yT&CSL|bxZOvJ1LrZq>4Y zpkGOj%M&jh#O4cQ3k(9=(7tLRz=WH<8YyO*UIib+^UuhZOAg!19EGn*&mBS$0SF{E z8OMbO(qm^Xm3QXle-=1PqFN|Wo3h}*S$zV@(X zcogj;YKO+q*%of)&=oEidRYBeSscW$z&mR*!t`6?Ql{~}%w?K!(lt!LuP0?G)+|De zxQqzuOBz!lmlY24x-uWhf|wxFo=ou?rvbneR$&_d#)8 zEvL7$%6oezC4`-I=^wa&z+33$5VU!d_zv~Z!Xb&ZSz=krB$p>L<2g z)E`hu6j?PSuS*d$7R5eYty=d*p(mC;a)uL2AC&ir<&K(fAz`CCvhvw7%A=q{rHlp^ zjU(%n-}4!#)%ohnj=Rft`xn>KINVo_38?t+evIC@9Oh`Km3kLtii2xC?im9dbSld* z&MMv8Qxen5HR>92ib`_K3MF+9a3B0u{-IT#VZId|R_Fi_XCS%DLvT#I=L7dBhd|~A z8W~Y297f#tC;$v`3Es~$b?s%jNd7ZtHF=uT-r{IVjm@l~g5HUaXg3nGJ$d;Aky@=c z8S*GB;_F4inH8vggWJ*o&a7qkolsNK=_aHP6Qk&ZCr>36qu$qY_3IGSFtw1w!})Hm z^)D&Ey?b0|qa=&ETF`@0dEE`w|4?aG#C|>#`Lcho==I?P#JKvj6U~ev5gDGqjv^00 zXmgnsVn18^eXGv%n+^K9c&fn_2N%5UxUFO`baBDMR59Bqq)7hIOF)7Q5g~?8e;YwJ zyU)k_O0wMR((@v_+!QYbVhVk2bhB(6lQWrBes z!d%H~)pZ*iHMm)%U1>qRm(&eF=8rG@v66P}fd{TOzWjIQR zf)Y*%fbh6jv3moZl6*wCjRu^C9pUAk1HV^4E##SQOP($ZbjQC`lWCACCK&;r`f9!4 zAys03UPdcD9cuOx45C>}c|L@7Y{wzbAU-Yf@FiRw7(cP}Jf!8BZvxKb$%!yW=Rw6- zLnu7naV9I8r1;_|Cru!!Z~3Dgo43Rd2YC9#z6m<66`ZF(64Bj-pRpc=UV!7uJdwJ$ zI6LE=k^>S9iMb8sY#9KX`0vDjwW}gvB4t^W(pz02CP8V9@2meJby>(@jawboAI|@| z=lWcDJ%00Z%K9sgMZkjvp%cU+#04HoWccVrEng(SDPz04Xmz?l?TNLDc3Rs)6G|rk zb`>74lNlG`&)-sL?xn;%UiWL>8d2Z`iP9p_NxYg^n5DJjJoi3M@bw2~>WxdltChhU z#Yd1|vrGqUA7W&^W-}`9-g{ZJX~~%yN(foW++qzGpSTR;Dbw!+?8BPsBHNUGK&o*5QxyM_++M-&L@Bp9j+XqP=Eh+6B1m>c0b- z1fo5_-~iA#p|l+f)%3gSZ>=5w~dp}cp@qQ?41`6J6V6~J1dbDJ0-;_nP z(yxsBEL&#bYr-EHQRpq5vd{52hz?*#?I3vfAkE_ULF|6s;Bwi&2me81e1{|m%^ShMa-%4 zM5ru5z`1eP{UIX65q)^!8&T);V|9i>tP1&bsnMw)v)Z6JllKb_267W9h&m3EiX7T9 zNos5*3xV-JX$*4;UJPWzs%#f9AMxu@tI4JiUN$EhyuSmyH-7pwam?H~k`k1(P5y@; z_OlAoj?1Ro1j$w`$*W}MVa}fed+4lEYg$1qb%Dfi2z0t4uU88;aQ@hX4tLsaDx-yGo9vPV zWQiqdN`F}%v{?z{1Fq~*Yrw9LEEw7 zJAdexWuwt%+qSPScRA!Y+!43ULA)*2^X6M+o0AB_Z(1#(PED5b>uYKVI{OpeJ+G}M z*lDcSt+F|-cV!+?DENYU=7idIb>^=|-S-3}(jU`Srtj=czj|o8KSG4J52iBI$Af8r zWN3A)W)$U(%L9r>w?9++qW~zRy~i!DP>&Uv(}$XD_nSx=#=eCUEKfq&lJyjK;TJ-Awa|JP zYDT(upHhtr@>$vq*e1)P%-~%m!JukYtH<+43=p|R0<3ZY!-~pPU0bax)zZkZ1nGjKM80ve$%dm)>RKwY)Z7Gi z(Aoz1R?2C%QH62Xu%J=f2K zFY99pqxbIg0lrt^)m3@p2nVLDnm?MIxhq1tRY3Y-jyR^GpcIy0dIenbua0#)+hqwo zP(dJ+e(9@>4N)-$Ch`^w4>b3n{Q^G+G7Qe3hF)laLspYtTC-zkAdN#0@;NkAOOByWBqWnZ=<35i=>=ij%VAUA9HZiQGVRu+1hm-m zLazTm`U4FF<@6**9^_@6h7XApse*}9iMdH;mvtI&@cPG<=8;Nj;Ha}TSKEzMK-9;} za9%#pmW4XV+b^M0F79{*F5!|A;;x6=5IRc^pe_NVK19nV!z^dc9?#mm=34!2HJ;-k zK2FgBd)_9y1nZ0MLu?ojqu#!nepo77G=oSs;-9@rR;{86=omu2F2WNu-93$ z-r_J@6fc;Kj#(5#xgkcLoyU;5$RgY-c1&XZbfYz32#_NAV9x-O6ZC$fte@-p!PX8H=o6cj z%H3}VVZDFqnXb3XR{VDjJD;AUqGp}4-G+d>MPau=J{o&?(DXyP(xa0BjJ9u3R)6y= znWk^qlpOLAq7VL@fPmfBMDo*op^{bFCit9eCQC=~q6~e|W+w@hRGAIcl?ZYa@R@EE z`tpmmjrM(JXDwZ8k4t$Ld&b?!@Uk%yBnanRWj(v+Z-<+&$PJp&Kw0RtHY1`};p z1&Vn=mw>16wmn>-9}N0(((3KAXtea%(Aw>lgkp1F)R`f<@YSqjPvU&dg})%0KB`aO z?7e&3uHAF@*E~WXR8*c25KWu z0dH^7pXnEbAiqlq5t=>e&;QVo|JH6zyt3?n(9|J5Ym`;f;H{)L8lj?yc!YOV7I3#F* zr%FQmlpk;G${)jM{lbe`AqCioKC_o^`0`Uip&gFhx!+pX5eT?~Z2olP;1uLiHc=Il zg=B_G5ycr!tc^2SUhC2{?sT%VLb>_U^q;Lxe+ziW8|v}X$J0QExgnhE9n13;7JmNM zBL@1O-sMHWdMvRD93l=>asiNdD$lf$=iRC0 z?OYg&F2>5lPDKLeZREA>L^~k&?g_@#P58NcJw~uQgV94^Kz*|tkIRvMA&&v-XEHfR zCHR1f9^du*PCZg~N2=SQ;mF0k^7VkRf2KFFctQ5^kc|9 zFO+(d50f1ADZ_E9GQ#1l>31w2E`i}8{mbp&{KS+#dro>eg}$pzx=Oxl{h)s<9rt!; z?>kFgX3u5^xjtOOH3n1td0;~O4bvguMUTBxICDj$(qy+gtqt2X=R)o=FnAj2O0-Ceu%@>{IM2x z)1>kYQ1`l@zi6D1+d0RO-~or}&b{tdYfIwV_Zm5fZHgn^lK)1RoNk6ba`zd$h;Q3WKl{cHZ0MX32Z6 z)QE_4w9pf9>Fr5+ys%9Oj;MN03?|G9f_EYdhK8xcecOvLpig%~_}KH0No=B0T3H94 zn;Ri0xxSwDduo`xO>8WgS$mhRCbE`Dj4J|5LxAwSdXzv}%6`)c-MY7!LoX(t9!q=y z%okmko6*jDtAI>g67OuQ%eJ)Gr47Ke0BT2v>+pl<4p0X6N|cq{HS$O#xNB(H118()>8N5QIVRYU)oMFa{rN95m^}|Xkmr19><4?^ zWWy5ZPCm5=ytFidh z^|rUjKgLT!(HfC0h5wegM9`yxWoOUn5`u)%@Ylyy>G^u|sn)=Eb>(d|{v9c2Caei! z1)d@2i=DFNRVO9*1QWlH8($25viINlAw=W{l|~955Suq<$fURN^HeJn^!a2H(gj3|Hcv~FbxB< zkdTJxE(^dP$6)rt($MVVE4jkV?T9S4JdTYD!V}M2tY;!KJHjXslCi7nn+gLRHDQ{r zVE96t?Sb_#NfEZhbVDAGK&D2QGI@xYCq?l(Ft`-T8y{%216sJL%q3o9*8+#b#~h4$ zwLcfLikU==HQ78(#eO>p^auq!zPYxa z=vc-rWl)r`l&PFW8Vb7nD`IshjzqRdDB?9L*0@^~i#%uoLD?sK`{*i&2)q_HxOFIu zkTy-4&1cR7Au)5BstwV^Y4Fr@Zi%3!Tv!aeY{4%YZRh$+?5$kzzuD&S_$xjC1VnEk zqyzDs5tjV+t4w|r8-;9};^aDGg!0x=#y+G#r5mx)q=SKB5m;Wjn*2X1f5aUBrWbiZ zAWf=5GlNf{ekv@-=g724dh9b{o2YMPXSdUFJASS+XWFIkff)bGy*BjJlEVR)DbwZ3 zNb(zr<*(Uxh8{vAg=mj$kOW z3bwMvt>`PcIBf-a`B$KR1AZi-(?>gAKFdrFe?-@wuL`OxBJx#P^^~ zvH9fRZ$6K+b{8yv<4*T$A0E1L;LX$D=rH81E&wzJ{t(5mKY6akJ`4N$*32UYiX)V! z!}wh}e_guP{JP{Ut`K*geqUOL{DvwdW|a(cnAeArrmoR!LmezOm_MYD+L;4Obr>(B z(V!HrR0ehKgcib%69J>5g57*!+%LPRA{T980ImuoWw}5qGXP8JvV7}@I%HR3vV?jKKS|lOGh0u?tn>G@ zEfdO=?aU7Y^5?!Y4NEPnl0^QAD%%+;i(Fh5ze4*12e4Y51YgW}ZIm5VP>S$UY5p-! z$+q?b6MRJ~5_K~#9zW;x!n?Lby7z4&Q(eb*?CX%2QA&~5K1+RM?A_{@{kz{P^pFwx z&{f!Q>FFk(nrtG>T}||Vo*ldJ8&GuBxP01fGacFV<83K zO&EooSk}x3+c}{RN8(8rE>ujg3}%ic<6T}V$!H)J!$FOa=W^V%UZA&HBt|g-TMJfd(FR2Tb&^XCu7{YHQg) zu2LW=v?yGHw|~|8*2Kiup~E7NPxFQ>E(7mre->P_>0Ug17cW$D<*9mwr`ScKs0;#v z976N;hDfqN@q$`kjO$#t$vH(`Dw#2{Fn6k$wg^>+e8Y4b07^O#-GP(^o-evwYyNPu zG3p7g-YyrN_%h@Ik6YfJHq1y!DGr-IYtKconNHxp-#q(|Il?=W+ zOVo^aJG*g(tvmh?Ui%<@bmEb6_OT;XQ6*5`XwOTxej2_Mo*1isXj_31O8w#Qq>F}C zRBM+1fim^SAM<;Mzu|S+GP!z|jQU7c*+`KfYm#;E;>vX_If_yJCK=8LryQ{X zLzP>bJt|r!C;LwtcB*^U2Y4F8sWiEkZ`=3FdPKf)+5U*`U>03+PxP2&ghmJEYxDNw zN5CHaUJjFP8PdzK>yW8El7#Aggp5(`QY5LYS;mpChGF$-4E^nj#`SiJOo87Jd8iTH zACZ;R{cLVS$aStEojSV5weMeC+bw=lpFzKJk5#1#cW;tHPU+ywiZLQSZu)+iC$P}O z#^l|9YaVFtk1o6x@jLpyvQ(%ZKR)`Qy%ZIt+Wx+o(Hg(Z?vz?D?l7Da29$+db?iFWO z$4OEV3wtqxg zofh;-lS`DZbEO@B#|^mS$q>>7B{wj}4L;t?(Jmy0YN^ibgAPqyB^v5Y|||MWj3FY%$YiPk@O z$5VS{>BnLU=j*L@f1df7!tHq($LB5yD?GO7#v)Z%{G}iO>h=^UAlNN#wUta5b|)L= zu(mU)r8m6Dp2RD_rn~-=7GrQhNQ^jL2(5H?!b1@F^wnS#lA7DY#>C<>r6rcHL>4H^ z_d8{VF$d2VH&{;P;_2lQ*x2 z5qNdw#@(-D)Xmz_SAUotr_4|+#!|92qx{B>ZJ-`2lYKX6o$TzHK#LjH*yZy$*H}&$ z6yZKD5F|1mcw7<&6DzUst5QodhjhGw!heP$h;}9triity+n$U;AG+upV3i=x@)T29 zxjj5y4HE1R&Av@YZ_FQSAMi%^AbbN|>~?feXUiKxLnu#!GjH2WXXi#)R#2%X>81?+ z^_|b@G7|PLdiu$Aj#>+A;W|(}qqTO-)2>tb=0Z^8xYma%U(+Uo9DVM&k>{fDmJ9~Z zy0;tU^wP^Z7*Klga@j2KG1jL5w36#Po8`X@N#qKF>Q|9Zce(yO@<+F+k!i}VqD7T6 zlS`Tgo*>8e<=jG-wRua!4O*i)?jnV75 zF?aM~k!M{+#g*NFfjd3ZQ)7hr)hd}2FZD0urQ2A#hN-vav-eL92}JU9%b(A7O3a1>g(^TJ z?d&omH=`%cbBAe#$Ws79Z z#;t^!V7{|mm?2te1koMl)RaPGUSap&ni<7FFW1mM`TLUpw&OQL|~?}WvI zg?(_AgDKA~5|+hGD$PS^+C8pt1_DZa(*%BMjXoSrHKdgY1@neGebK+xG~Hh>FD;04 zTU2J~4}v|h>mF;`VSWUmKjT5$D>R8&+RAGu6j(t6Z3vTe$QC_&G$ekVF_$t(W;uXo z2?Ra*bXpUZ)o&iwZF^3*%gRdx+0n0;?P*!U_jsvZ@^j~ELrDZbu&5+yUk`~^iCKOF z`L0`?_lB;MnkRa8Zsxw~$eT?26L;)$VVsUcb+W01<`$gz#QrS`gP*WPxw%_M{i9RX z1kQ-yeN@nM$=r(zf$m6_J}WT$h(O1LzDGya%y=sv3Y-TLN3T5{2aq`|!&}?j-425F z8lQFOPYZ{vWss=DA{v<>xnAnlq2I9&i_%2~^mAV}KO|lgX>`>{BntE3r!@$#;o}0u zMNN@v`XCk!yew8S881c9+wKWA^AGG7eqPQ*zrHiVicM0_SAU;I=1%br*uOCFo8^sJ zkSm&|hbb}%PBjQso4$1KK#~n!Z;GDcb||Q1)7D&W>N)efCSTNR=JLi;9|)`}0fNM? zHss**WqH>?ha-qK* z2GO08c3o{j#l)U5k5`UQXg~Xlzfp!~K|{cnH@b{-ac#KccExp6>-GKlskAki*o7HN zh|;VC2Nfb3)oGtWpS(Vb1^cD#u~r!B-!LhS2HpC{=Ut$Xtx`JmmBvl@C{%mD@z_-? z*nTY;-m>BtSTDUw0uucGP<8m2x61f8X#-ukRWmwYr`>7&iBS+*qBfjGjTg{bbHJKR z!#}Qn7i_HQvmVf<(y^M0o-`fuAb1h)K~|wSoaMg=?&>hjho}H89@G4!3I4`~N+C@Y z2EejMcM>9<{X0Dg7D2O7`64vkD1k0CHjvRfdsj1reWkI_? z+pEbQ*_M-Q?K>1y4r>f8amcWWNhMhSoe>|^Ny;A=UFiK-u;h{XTkQ1{Be$p;{doHV z1N{_#mbrDr8i~+>^UG1jq2v!0tS7D3YUb)hFZ7123yP1mG|_hR=U)*L6ti!gwESZN zgt6;d(GDG&VG$7OVm*Sa(DN{Nx0Nqm5lS^`z(cXH%PHV`q_A0PZ1pJBG!UWQ>1 z0&x~e`VTN}lo_Q^69KGeo>Gvod1dC$0!T&Egqp!h_ZN^dZaXnoXRv8>UxT8-bI z^`84zC`TW(iE=c}rGEm4N@SMBYqLKcsXr=JP{=i}Jl<`dN~M|d+AV2kXPWCGAw0~* zTcdS$U5udaY5BKzfNT<}re>N0?U4*6^z_M)fW!MMbKk+YVy0Lo6O3IWtbGav90#7> zDr@hKfK~sK(7MY-v;aNvWFD^4bbNiGd)<~zXBrnOwY^vRyk2@Z(K^{NrsKMoq+8O1 zlDkb!hmTcGjxXhsV=VQR4VuTx0xuFNOZeWLA?nz3DhK>)9_N!Y$b08pXgbefjb8rt z+=j>l-|wL94OhTil^9*ac>QZleM5E*rf;X*BA=N=!C%y{1y{l~l|CAp8k|!DC6jkK z^SIBL01t2|u3s#g(0-wg_LIoL^O)ls7gUG4OSQc0?yS&&2KuB5PX1YO>h82LR8?Hb z$Um8yp+?ji>0!S4FXDna3bfzW*gz=T9=P5fxk*Q zht6lbR&&2}VZ*{%$dl+)(g{=zXC8u9H*pQ?De7DPE!!%+$t-7uRw)7YNN>hg8+h|^6eu}COjK&&Ng_>w_ z1KT3bgejO{QEXjR+3sq`;i6;T-4>{TUZF1awIY=;f64Fk6=IAMjm0Z)g5ALGW+vyc zH=4hKGi#=N*0Z12HL1ZlYPKOGZ2xEqV28vCYlbw>IuTFj;d}7$r!+@|ac)xK?)iWr z%-G+xAJgw*-v7PWapV09kNBD~^j;KwE%80RP>d$sOnX-jbTC!4VUH0(87s9QpHJzKNEni*TJrMiM@rV$hSH=;L)}EoB9@1} zzwk?8Cg8HzB^&YFz-Jn)>L z&&PwY^U$rL3|JkjyEi}0$hUsO`}F*;to4{+TobG&^Y03n0~*QSnpm-TnSQ&}EB*^9 z6JGxaj^!lO^bxEQJ)u+o7}+i5^4U`DE2ed3WPK)hu6UJBo*4P%Y21@i4XAM}CLrs- z8lF}yZ9=iU&t@(3V>y|*H8O;U)mfhFW%K+9w54-Dy&E!TH#8d8j9Ji2dCo-V#Agqx zIrroL_*?t&2i5nWqNW4);xg$+FusXcukz?cF0bx;J~}R@pg+xOZ^1srsAWEabG=x8 zN`|7c;ONR_8)7DBVZCS3k4Qwll3(1VmwKz-86u zhThKGwHvZn63I}F^qp66#m9b*Ev}$rg=kzg^_kbl#Nq;v)ksk1b;8+F*^w ze|q+x{`o(h@y5&DV}JK0e@teWp9L1U8ZmleRBpMgcLdCQk0Uq&dJEZO2>@gef5Iwv z*K8`?j@R(nugQb!)^Xg=zKzy?E1j( zWWMktK6jkBg!g~r@7cF}9($vrNu4Aa;9#ntA)>y^B43cMe}*sq+%Lgn&%y8z6d7{y zIb875|B>ff`%qPCwOXnBhe(W}iiMxKX_T4hSp8Z;M5hs5s2W1lYAN$Z0-HYlHO6ka z52>eU?84Idy!CJXl-(foMxnWui`4msXcE&c8_K;LxH&FOUS_*1PWR$J+sL2pM2fO_09Vl`%m6KS7UNdNIu(Fc%a$|bGd$B=*B+psgD)_?BeH6X>F=#l*x^T)doc^Of z#LIaHn>bQuQ6GptK!~LoH7cTlXs^|(Ob&XLO5`;h<+JtwEpaJ?$k@mj&IpT^FXQEB zo`je8VTT6LJ!3q#eJ5wU=?Xe&Qg$gf@gN;b6;DQEw9WB*3hwm4ing^1oWrmS~tuJirVRYt=a-_80^Y~Rml}Oa+yG8aPufAL4 z9n#_1s<+(B#;<&vc`;&X>6j9x6-1s6qlO-u(l# zhw9`;2{BL<1$j|=AHz|bpIl$ zHJ15=y00p+^%Z%DK(q!VQVWqqHs!f*-UN3%NNQ`^=;qQGZ+8X@xo1{Tut~I{7$Z|$ z;ZrlKW?r)yIKb3h+5_qRxi89J5QmkQx*D?j;NaDrPA3qJ+4jJFthnra<{z_^w$Jg# zl93Rw#LSb%$eYzi};FTO&v{#ZlK8|sxjJ3zhGVvNo8Yx|kbjL?nEQb8?XL2^cS8C%5S z*9(fTZ{57f;zN9K^CmWL+QioFFR*$0Ha2hF#tU1wO%whP)HY@yfCGDTPP{zuPbvmm zA86h+-fmrv9kv&g!dy`4p{Ul2&kA^S+Zu*?->t3@IeMuVde_KlcOXE zVX8lMdMW+>c$JSD8V)4G9-EI+V zregTtCEros8OS$ zMiG883N3?*P3y|d4{_JueTku>j2uiglE#Q?m%5J(jdc0)pZyJN*a(Rsh88RwX2n$( z@Pg@(%o-$mfAoPSud>AbQA2-z{tTnt=`a>@w$tT}Kk{x^wis=Vl^wxe+{vw<`YbD4 zgCUf>J%-gX{>kAP$|6sHF2A$ZQeU61P(&zBg zKXMMh%%7~KH68D?t(!HtJLK8^6#I^bOG8!!v*+;*tbW_oq;qDW(PAUmZpH!+5B~EP z*!{Qv0BWn?HqV(q`NObsA^Tjw+p;yh9AtI}19Ollo5}O=a98MMT1RS-Sq2+*hVsb33%hyrxBd*q zl>`%v80&-o#o^(h>-O&5Yn#nxETW%sV>5lm2R!ZpN5HhhblL+S3KU3cDZ}&TXsg|F z14BdihHidA8d;rUL)OmBlg~WOrB}U$Jhc!bbFu8c_hBCVg^$?HtHt{nKO9(a_(LR7^?#pfBb zmM&m>dkmi6QbxKaP4?V*7xT|sLu26_@|vL$BP&OhZ-4AhVB>Zg9Sy3{MZ+~3{4aWq z)+8?ES_Q`SRM9HSYhsQvIb>qp%#`)A2j3A#z&`|LEu2R{>1JJuZcg30+p?_l<1zTU zsW&ui+9ZC?TuwOqOvpTo+sYR|`rl#8j&cVW5384R;``sqXw#6JIFT9+lS0+Z^gGj( z_A=XLjx48_7s%$H`ms_JuL@$f>&oL5eSK8 z+-Ia|E#ke2!V5Y4VpWMK+JU*O{~v!#v0*bOWR7qC#-G4_PeO=g{M0dXIraTNh#zV& z5()}qDxbNj8de<|rdQ3JURCou1+nj%2dmOK9eQqJ8%u)jHO)-t&*F@CUInvi&>e;P z0Nnc|PyOT9I3=CM{)ad6(x<-2Kr)1?#2zMf-Uu&SX6rc)ZKCP5B#b*0Er{- zbQm5OM1pFk({c4?<6)B~XXTytsoL%a^1^J}wTFT6F8BTA-<8M@EigF?-t%_SRZG|x zy9~{qO;HpR;Z^1H=>fN#GE15I{~ia3uaFT)?~cvm%jxsjF7a75G6Wq`3gopCKy*YE~r%X2D@cP(0;|l zOq+90b3Ygdcy)VZir65%H7nhKMiv8)s+D<&1u4|GoJ44>)WIZ~NV^Z-#=Ws(C-9z8Pk?A1!DC@VV= zeSvyU^a0!TTzJYFwr<)+v12FoAPoC5nm9rz3|567NA*5bEm}IidzIZJmR{PKMEL&a zI212`ttv36h&Y7DfYm5#EY1tYAcoLL8D6k};4H)Q=3uN~(}b7^-a(jRXep_yS2i_@ z5M;6h>x_u+BY=Kn9ti2-iuBwi{K0i|ttcPXeha!O2%zr8(rrHU!1$iuu zZYhvw>Mart%~UWE<_*H~r8G`n#q493FmKrsf|Px5gMqFCFOz+7gP4iM7A9HoWV!k& zb0|HAQ=anRN5IUPM5g-ww7SSW#8&}{rtb{ym3VO)Ns6-YQ%@k=yX__RZQD-w$>-pO zmtfZzm^vm`O}ZgEjR8n=!}dTtGot&eN^bEWvpXab4|fc_rVexwu^0&kd52TJ1k|H7 zWgR?AK#YPK#F*apGRu}Q``BYxdh#lURxBYd9A>|I@)%I(C`=iM84P$I%7RkH;H<$I zSEi~}7!NU2C_dC4n0B^Llj<}|#p9JlHO8ncJ-siPAE-U5j&Ep65i zW2DSO>AxscuuTkzc%5}gu1Nxk5G{jy;&w&I` zic5zU^S);UFfHN17;9n~p%MWW0v8(PEx;vF%*nlTz3h^yp$ze{hQt{(LbCyL=Cbgl zmDJ}BvvAq5*oAZ0RS%4rf)M&bti>W#x6NLi!(QNqN}OU5>nDhk0Lq}vo{LshCo~XI z=yW<5YcR$#5Df$483SI}^WsjnKl41r_MPz3E*Kk!dL6pmh!Sn$#3)unBzj*JaW+pG zV{VIZjcU9T*cq#6Y@-;}7^wnZX53syfWYq;0zixy5$Q!t#=i5`Md3^@dZohEV(qyS zp<}O@-Izu64Fhr>2g~B)@W>U42 zIE52voEpI1n|H6IoeiN3%#7ukKHMCjJJw=s?>@q4n-?E^47TlreWN8xT3yAaDq^Em zZ>@UK=*gpk(!y}Rz_kXs!6=VZ&76Bt!bVG06en7K#+f6Yj)Vw~L=Ak+kAUgU5-XKb zR0hN&MnjY;#;E+rGJ#8gt5CUE#2()ZNiC76p|mHI1u_^&p^?Jk1q?4=%)FJ$sLh*= z8*b8Zj#lC*jF~8*s!}yiGUc)1Lykm6L~vENbX(cY(->LgQgrV)VXRHqH^S!iPttm6 zH|*F|nzDUf=BrM$>@aqsE4O-3zgZ)<0oNnkhVnvBIIR$90kk|OCrml2herH#BA5w| z#3%Y)CxG70pD^9(gw|{*H*MbmEDaG^2j*(vO5kiT>BQS*reH*a!H7_^Les(QLFBk) z%sFlui%wcikvJrArIU$>M~GJNS{@w+a9S2~Y>36gfaIPu_w3&IEc>=>CEKzcIt7e( zpis45)kUK3^|$IB6G8zz3|z13uT#|rRJGl|B$P<+l{lEf-+S>4->ua5?>YfYhw0~A zc}z?s6@;nZHz!hY2Nf<-)uk9I11yZ7F?gxhL_6(LI8JLYG)TH+0Si_fNAs8k%wD~m zaVNASGV0s7MvXKI%^(csFtTYoo$Wi>y=e=6$1d16Qsy6E6eF?BN{_B*el2ALb`ay8 zz_lXgHV9Amo~;_af~hkkG#;fX{^%UGhsV!%4ATd@!O;`Iw3idXUsZ|1Uc?WxRX86p zZ%NbSO+^vU(7Yo^LM=&A)sPpNib;%GXK+AGV97#iCoJcflU9)oHHlW)yYprCJhK_L zy$mn!D=Tb-hzT(oC0azHV9TQ_5YdS029%pbxkjSiLyY^&2~Rwa(-NW{GOFeO&k5it zzdwaLsKC(BEb=@jgm}6*b6MVMy@fQr0Bh!!9>=Pdq2N&!1VgWncE5o~q*r?)qNovZ zJ^daL2w^Y2xX0FN*Jy}08DpMs#%S=NXK%3Obai5v_sZwIG87zK^6!UNdr-XI2w?i$ zO^hl-%^~k<30YB4Z#LLJHo7SK;zDZa)nwUaD64zUDyIgAM2o1=GL%9k#wdu7!FW-E zPT2FGG4m%Ht!lOyO z=F_xJQFyvzqeiSV8hkXy>Cn)Sj*X2?oA199z_bNxk=PW9#I%cXku>1S2|mmB5nz?&+&#I3+Lfty#JxOx**+gjj>C!cbqE#8ErR?{R& nFvdWLp1RAiA62oL}O0J6NCl*T_A@}B|+^RFHjF`xcN$SmbFlmP%gnt%P_ z0Km(C#{U2So@@ZXsTlwukPQIfy5{$&3;i2_u~3wi0(|}_7xz`A{p$g`xT|OZ=S#hF z|23#Rr1de%&|D(af-q{-DVeahu|6n_<7r0+{82gPNh!iu$uhFwA4eVAtaST0Z&2!e+@v*A6XRJzN)UB zSr@G}F$KVdAcrUiVm)EKtkylAT3buW$h=W-Ncu#ik?aPF!$DN!I7**EkZI!3N!fiA@yQUEM$nktRB$B)1x5@yz@?cT&KqE=wO>C6 z2a7fgX$w&V8w6zp?Gqb{Mcn;r@_f%p3!vs_PWNnVMtJJgy%h5-!|TUFz-3b+GfT8s z@Yzw=i2~!&hf}aN_3gDEnhTyDegP}Vk9{J9**)u^rLgR5$4uZ#A0V)1M~5q5@pGq0 zDB9iFa~fgEUw%dKQ6EW;3pM2+hai!#!+ylEj*SeAPzJJIbhKu*@r{trk*ANtVl2+a zRBNy3pBpu%aB8>L@|}6b@HemXD^l40b#OCr!<0RzN-D^X8!@6%bzmZ0nouWE$&clO z_8eWbhgbK-Iu%(IqfV^Hk=0ReDfF}WJEDvMVDiGq2jzf9y}8{x?b3}J)x)~r z+|;?q;UG@YasnnsN-8e-bZ`nOfZ2aF#bm2ge;83L+50aHX&S~(kODt3`4E@Q_LSIl zxmk^E?xD(f@viy~6jV&viirKam%oLWcbNs4?YGw(w&ZTkf2nZTQ9x#iWWYdz7$R6W z3$3ttXa<|r)E3}X46FH(6410gKLrzgMG$E>0oUUIpdB#w+whL7(a;$qvzN*2s5#zE zvHQ^7bfMMQZwRR8q*J6ss@CE;Lmj^#-8g0$O;)Umpg8@WI~o%wK-eQP9_*^^i9cI2 z9`>{~R&qJ|8EA%UUxmE-MZQ%_c_c0tG-RFfQ&t+z#0QQ%4lMx|hCEkVMe$OT|ra1`H zZ7-Ies6M6#&317#-i3l#_AVIbY!>CFh){n&URi1iOxS5vpX8#x4dr9^dfhPK=#TVp z&hLe3GumCA**5bJ*%fM#Q|PH73@^s%cfzm191_E^nhBLq2dSNgr&97bvmwfg@?!UP{;K`M%Ro8qa*y|Jivz!{|(fx-dkI`FPB z84g!~R4q$zkB}tt!oMEDslbKQl-RM~YPprJxR<>Tp%K;w*7rR?ZoJ%c1~@Li3w`mA zc11EI!!=4a6NiJtr3k=$%7p$X<0Qc$gNhN#tb?me%Ra6WvE}Qy1mIe&!yz~~Z_3X91lXF;IZ9OT?~pM%f}#aGp?1+#`j73+YxA;VjEpj&!_ldJqw|> zFzAv6=*8n)lkK3>yUL?urX`{qCL>Jj){jd1{ec_TYCJRF7QXj8&UV%eQG>HKDI5^r zKZ{{|n)$ovMUh6u&X zwo8T?T0|yIX#{9TIu@3nb~A5C;$G{^;w9t!2=%o=Cjw1Do5kL9(&t9GPG4ajh2xtb22h>o`#f|J zAkfAxi0OKvvbi+F(-;}60uZtp00JLHAaywM8SGte^w(avES&e^Bk<^8`7|NuE}s*9 zODGt5t!WeN$8disI1xrR6Ndp;qU92%7c-{MehZ55B5JX=6U|!!$`DzlU|5ei;?`Te ze_Pf1jUV$E&Ot<29s;67lmasBRoloUQ8DESCMmM?q|-%(e)N@-lL5mhN&vvG1T;9t z#VJ8d;cB{Wr~<1rYRl}*bci0m|g-vZ&JM=rk z&a=2ikHM0PtIb5Bgz{z}PX%PW9XTLlrpx_9fyJ;tx4NJNsuz!+e-2_!Y!)rU{g&&R zzXfa**KIb5z#?pkd}lQB<6~0_Xapg@Dqn|RE|@6HkYQ$ChWQA@#uspzTZd-r& z`zVNsj?RtFjK>SjmrNgJrnx16@iobce!Xq~uo*aZ?5qA)u;Ze4Y5x;+{lO5zH46e$ zN5=gQ9i_vLM=XWzJ;`sc2VrOO{9;-c4T*(BJTQlN%SZZ(^C4+QWKf~jkcRAr8#|`- zuo4Srz9?ytc7q8@psu`0Ev;>OUMZ09ZvqJ^gwfZRH1J!>-M8DPZ|gPi$+NcTanDk&sprYudGHV}ahze%GPPK@}8m*VA+&Rv&= zg+c?qa?2jas!$wjM;k17+;o&Rw*`*SuszX}X?o0d!Q8E(kRuU;PJ?IixaFc$i{HET zI|`RMUl&@Lue>K4HZZD#*}r|ZZN9u;m9kgagH(sB__bCu&!K;n39+hCuC0$V@Goqjw(7N3dPv&9Wn}zq1D)DL2TTU7I zQw}diYoPlfgN6>d#Yhp%NI?oy_q-G6kaM(E2XTiy$L3@Em+Rxu{`hVy!q)AV+U}2- z=@vRN7PPt@DRgb6IJCZKl09=WX(-x9eioI9)!pM2Uk^Lc$MzR^&>2-b!7rz~U!#s) zJ}3BEnyUH7QmYIabrPA%?WR_-qdL`iyf*?I6}5>}h*}($@A}8?m#NEc4e14tuM2V$ z?B6!9B-MK1JuzRQCASh5lCJUgkkDzBT8o?*y!d`L+5S4q(ga9JQN*IVfUPNR*T7fN z6BG#8v?@yej@)}pwkd-K=}AR*1dW&aQ`C)7g@fv~zA{oWt|ZH1P7%_VbbEC+vN5f- zl*;K&LAa z8BXbIRM0A`LmX+2a6r&A#3GW}j4nq*#=ucz|0&@Kfr41D>zv4%-KYH^>pcH8rTX%C z!4{_XE_C||@`y5PRQ?^+t{%74ud|4a(;9dRp zf?KQvN*V$!ZlWrLQ2KxX922eU8Y6p(lZ|UeKjyDuIPI@fFwPCiYPPDL4J+>AqHax3 zk1y_z{z=JqMu){%>TF=5E*(ZjCmyi^Z|OE7wt6FB{502C^>hnLa#ysB-xM>6(i)U< zm6w`;#G$7g^!f4xND_L`-0K?a9j!vg7tt56DL@)%G-~XCcr{|H^gK8GD3H8fg zIILaKP+c94jfm?$FO74%NEd#6BpX~1D-l6sAFQ)4AM>LO2$!%FfwEfHDkMFF6FJco z<5$JM#@Ufkf912-q~nj(s*TYZCHEauNO#nqYbxvy?flEKm)}v<`LmP-rrd`+j1iBy zlFtqLH?y@Og3jPT%vJ8qVLv6LJ z1(Inuopl5KFIsijx!uQrP}s*W`yUPSd&fFC0|D&X3CT7xQd%!58ekwySZTpyGkjw; z*3TN8+uP3w(FJ7EM%u$B&lCO2py&zRp zj@~>5f{4WOA3ov|e&OHsV}%GvmtRT(N{{HB({rUfV5`IPK{Yp-)VQv*y{k;l75D8? zi^*X)C&DIJtXPPY^-aYIH7Ixx{6tthGsy?3cuP9qT5T4#hELRgs|!bJX9^ zk&HVM=+)jp49ozy{8lII7LZU&AfqyZoSwEDO9@S)L!lb#uF z(rq zii!__7y!MGDOQ#qLjNYbHy`iecJPe?M2Emd0fef=MS012qZ@oA{5a<-1LF&Ky9UTGL$RqELyb_i|VSeR#3)( zUl3++#~nFIi#iHKLOIt;dB|5sex_A{&j(@B-AB<6dXc9WNBx6SC*M8w;)V7t_g}s; z(?U3d`<9d&z0W`sJVEe@ZGHLoI>KXe1dY8!j>31w(tWl9@@S&M=Y6DW8SbxlxcPH= ztUalx$+k|e(U9g?wD36x77hltT;pAE=1Sq;rJ|c_dPNTL#VhJ;DQ*qH`US5F{Gz$2 z9y!+?y3S_%CyshQBe!hws9aLe&?3~RR+QDv!-^@Q83yC^jQFJ)fU>pd4Rq#gIxpWb zzWjb9`UFj1Y^)O4s6_z3(nt&a%u%~pC>Vz2F`2dvdhhhP%5X9Ja#`Kx{-f^{VypRv z;8tg5hwhyNK@f`*uDTOrCE zHrsePI6?*M+9O-UShfPXG<__!WdoLi{E1MB6C=zn4qfs9TKL(wuu_#s4E|p ze6*1kpM36uQ>9!(T(6F$>Z}{?a6r%*&Bx6Sk5}e9mrccDH9LbuIy8&uyOPLj&Gu25 z?m$L`8*byG%qIL`Zb&87oP+ z6MIe5Hs~tg)+=_*%^u32q$Ug}MW}_IKul_Z4u(^rFby>^Sz5vI#E9oN+~=CI>8_z@ zUs5HVGa{5MI^>`A0%?Ff=k;TV0xYb5j0GDdknYtGdL||SO;6DrjzNr#5|sp(pMbo1 zfPX~Nze578=jA1NoxRf=MZZqI(0`AQg=sI5+Zh-`WNB#`t!w1M`jvvHT3TpbXrj~G z<&d>gbS$%eG-N0n+mA!MMq`xeaHeqi3AO0WGw2F)U@&(}dgV8Nd#~IBxE`)CyTq65 zCX_Ri`Pg~QSkcrJ^}F`~7!i_E?{^uDN=A8AoJ`@jGT|xVd7-HfW7cMmRrl0>{&48{N1E3m!Z8ZjU6$oO{GXnW!v ziVoc%uq4Fl3WZ%S^(kd#1Xy`uh)g6TWvv2`S;Pha^cc<1OWo+2Z>SJgs3b5;YLdN2 z59EhF9`KSLU5JAW(TZB78u!ejRW{Uk3S!-e2)*CDtK1P3-ME{?C3Z>D&$&OEuikghf-bwNog33XglqwFnAi9oG3bX2`@$`(?np{t4++4C z0y3KVOSh3YYT&SQt=kA(VL^L%(a~_gVU53Ux=e{Y2A;>l7YSxymIN|i@Qr)W zU6#n?8LL4O3iqE>yh%t2y8UzWT6CLH|9!5>KtwS#>bp>(M0~fxs1D)T;P;_pAG5XA zwva}@@E)=6#AII$@CEuUb}_cRo@IEL1PVCE+#P1)7gzRiAFeeWZxj44_X=%EY0UP zteF28wukl2-T8=&&H5Ma#(n3#F+zGZDmF$R3t@_?mGFjPJT-oM_&YE((EX96-)X^p zBZrCaoD3x?jkuG@(Q9aMvTwnLe_Y@puCxeXmmq>55K_cp+Hqd%i{U()xBZJ zd4MKBV#zR1-mCwBU*_ zj|Xa$l%l5+Hd+VVCtU6HAUEwR^1ed`-!wE~woNeCuVBc?Xyk)UzUFnf91dR0yWRNW zHa7%|CS7ih1{Eg`Ycq2FW_E}vTbk3iX*M~&Nvt^jW`5&tRX>^72dVWY^(t+xkhl{w zft8&DAR2vl1@@r%sr!LsjSRt4-T~46rapy)SKS#!Jg9riVtHUTU=q62Pg_bWK@^PD zSZedZUw8|ex&#SgxYs|XO=ejKj=vhU9U#^6TYXi&o!OUyv*5a=S#|Inlg}_Wq7(~5 z^C#aF9f@ru3A%e97;$Xs$(;|pkoofcc>Jj)JywE5eA$feYos4Zz}xN~Ns3wu6m6_c zsEKB&*PKC*&)v7yZofqZ6~Tpa$4BwnzX+D?a9M=_mLe`79|iW7JR00w+F_YlVqLlD-6IreLKqSdm0p>XujGPDj`s(OZlKq#x2<{rR3;m)U5etVR3#x2h_& zOo2K1sJzAjzegoA{l>J)`mm3hY)1&RW5Bwk^9xgyj=`=~I82NZl` z84$Rf^!(A9CodZri#`L@VR9EX51P9;J$iTXh5fv3xU&4hsYdLC2{WEt*a#2ky^qbX z)C&O-g|V>+5$AJb`2-&zzsRcDIvIgP&OUdNo?n+BaOUoHvAd#0=xq8_3nzpBB!V_S3EcNF7xSRX}ax-daFpyT|;Y*rHy# z{xYD7-Yac^QtYjIPuiwDG_O!N>6azJsyx$=h|Zh2gthDK&kw~7kF|^YD*7ClFuXgV z`l=~G715&UB`xhtt)OT|f?jtX9|3c?y{iH5fVIa0x6 zt*^?qYu;2xpHa6RH0i*@h4qJCjeB2<*Qi6#Bkw1&qaP0X15#>v|3ZUG35II@P{B-b znmn;;$ucMbha2SK7*S2^I?SA@?f3Lp^oHe_)j&0d@J5csa`m^VKXUCalhvx-+&7|A zeZpVJ$@#@ViEiFia}R$$_<3)IrJ;rq&j8qlGLKdyF1$cD-UOqR-6Nm5E|1KSPR?JH z$hRw+%Bd7@zvLe~ROULATGnY@_R5xV4TxqL@jkcAt1%CA0xqFb?cREEbn)!tEz~7) zD}BP1u$n?1CkD-r?0NgSBcXN4Qf;!~HLN1kknje*Go>_X2r}?zWu6N#!Fie;EM#nj zvh0Ol8mL7rVk->YvbmzCr4s0UpZD1z=ybPKEN1A-C#PKmYJF2%`0)*{@%Y1dN3TbK zsqPu*>192ZVuMey!$S@CLa4j!yc4ISef~5b1epm*-f_i3g11DidC>r=Ehu zW#41c*59&pA@%Tq^i|O@qo|s^f_Y{ij0tV7J{8exO6SzRZ}aZo@VFT(0f=5pYv8_o zk9BRu@s~|`nQO%j{!8hTL);K~hF(3T`&MbM@U?M8+BkLE-f=-iy7Z9PQi?8(zB+7q zrwBstg9Hs}=oXX@V=H(^TKc&+E$@Jr)6KGn+my|E%hJhrW82Vf}v7K&d2E2 z&B+j?bCSHNZgLtJMB^MHU)HauEAX1jhbe&01D;%osv0>x1$WA3?qELq$bwo_zKP|i z2;0bI@X>3|G_0fpY=UfRLaJ(cgH$*v;Nue$lQVbk+*fmAic4w782I1`iqkOp*fFM8 zSFGKScK>9+-4Zok5O=vOxotdVD{TH1z@CzeP03RS!Y~tkD_U19O{)b8 zHc{>J&2>!0!Ny~d@&#{E{8$=AX!fPg;A6uQ3Oj^w+i)q%LftQf4=$>Uhv`=4_SA8_DH1uZ3>>n zM(r5;^=+5C36V3fGR+Z+q=_KiKINOP(Cj&W>c%qfQhA-hejE1j)F`g;1FosxM@m)E zAD2-=*3E3+J^aq=10~?n&ms$p71a+yngUW2ga0yBk6@Cv0ywDN+C zOuu*XTaIy{U{Sy7cGq?N!Wx^yk8NM|g7z6y`|P17?r#?E4a;a5S%!vx%7gy2UGbeGFH`=y-GZu-Dp!|k zJzY3Ngw1Rf+30vY(ZiX4RJWbopD_$h{R0(B-ei>fv(*;iwSKZO_gHpV@O)q+V7Mvh zF-LZeU#S5O2It4~hH&R(L3s!6$6vgFfaBpu)4;=*HDRBt zKG7VtcGeV|#q0b=W*hZo6PhU^q2>#D5(;b43B3X@7-6yj_++Y^c)=4YyO7B`8idoC zSHE>1uz6(+ZUN6w+tVky2&3#Rlg+wq)Bz+B%fJpFdlaRRPTTTQ0ZviZ2FWZ?KKbvp9F_QKkhmuaeO!Lg>0c?`c`2x9mDf*%?e;@IQ zsVq^)?=7(6 z*QHnX!eem|ey_O3NG3IqyvHrUqlHY~1dIOlw2$%51QGLdy>X%;{%L!rK87Un%LZg* zrzCS!%UFs(g1>RDMUfJ%*Oq}OUVaaA&LQUZJp=X&9u+Vn_lwJ*5`Lk0+2!>ip1#?6 zbOt^oHocv87Wp2W2dZao`fa0*7KM}-Yo?;F{9L6_s_UjA7JX@c2FNO87ezu6f#&Yv zQ~#bg3y(DV#ykU}N?P=Ob`-~be(YaO>S+8%{`7+q`FI;nGFo004qjFz{lzt%0xmj+ zocZ&+Mw5haW7tNc5Eeh$zB9d$ETHynf=LVlH4B}}Jm7U`_z==V4#;mI0fQRQt>FiUclzO+gf0LbUR(#Ild|!yZ%I4;#7Ja7`lcPomDy@QKVVLod ziiZeTy?Wn&p04S-tFZZPQ~sEijufyAaVL5|1#d{tpLa&?ZL#A-KZ==X5Pelqumk3?XUxsAjYjq&p)Qudla@ z=Mg=&i&)nn0TBUq2`+!A9kypc8n1k0%=*yeI_KlaLW{?-+b;kuKkHt36Jp5lzx6%@ z#vKMCe5ED2Lm`x9DD;cvF%Yz10q<6Z&dp8yvkG4j`2T&e=`aG~JynL8G_=O0WuYo; zl8{{y+(IS?3vUu0QJ+^<#I_HR_UF9hm#J-DqKkwJ{Quk$S&AzA3*%qXSB_%xlBx6q zWF*wS zM(CE9AS`D`l2fSLn>L~_#Tu2KK(1})4?m)tm5Hm3Bjdg9uV%#ZOhvMC_yQ*Xb@ViW zGHGZgM8&(cE27jUNvubvs#(7$SIgZy9|J@*FV#JIWM^Yys#{IQqQW|~f-iXAkL#%O zQmGsg*@Yq;qz!Z@Zo(APXG9xaNg+qFQjYXz=w+kbYy7wfIEmUG)J%`$WJI7AYPTgU zdQSVCdN@L3DpcGMtlBWvB3Ge{+$fphSLz7|VckS1{{g#OIaqa;PnWI7wPtU1R56)^%~Xt8PL$M}Dp|NRMB z1mATxeJ}?<7Pz#u3P-9^Y+Non@!}F0K`0nxgNApZ z@6S9U?k_Mb1>duwM^-poN%oSLZ`|TP_r%K($tG#m9jaN*LVvW#2FESM}7rz$QB1St!wXteBY!k+OWWN3O7ApPC|azihnSrG^-_}OHRjj8Gfs`v`}?Vx*c z5}$kXkI_|^!>sK`bHB3)^$2_w%6$2h3X#T46x&N8>MD(LwreAZ%rt9fCiOjjW1)d# z=#N`PUe{scPBxlkLAhFmI^sXIV!v2oEm-Y`sgIlXpFaYHdTeRwB^JVG2D33AI^7>Q z$69}r>}@$G-7KyW`mDa07&OGU=*iPUYtm%N3v5Yb)5-#3O&AE*=*JuN*u_%?tewOY zcFSiIythY0MF(Pl2-dr3N2`u)l8IGxu>LIYE+-;!y!jxJa%L|o#ct3iNx$eDl%;`n zQwJWNeB6s8H{KM)=S4?e*Gb{;=aq4h!FFAz@U@%ri)%HPDWn|YX^8U^2-L_Bt3=JE&NYIL3- zB=ep&-aBst>?BC#QaD)OY~9x5DHO+A@I_% zr@I&DkPwcLHYimnmKWW)*CUC?&l{qjklsil(*QOM+;&e%8!CMn(@TBiUbiiUkI}k+ zcM=}VR+FJLiky}$)cJi@)V6;M=FC1x3`!y(R?8PyBwf51auPjaRMAE|%Mv;1va{5IU{D>Azg?}*$fTCH0rzFSjbh~S&XDg}F1lp@ z{0_WAs~U_BWrq-!@(DNRSgE2Ak2^tkKs0a>Y}v!SY!9aaeI^> zgxmVfk!3Xn$5>xw6t`IAsMuK94)Xi!P-YL$zjNlSV%QY3TA1h`eaF@#>J)e z)gM5&rUtx7Hs22E?746@zmrYeSCwc0+#V$}6j=x^x~&dX(1=?EmHQ57K%KNIl$C2} z-Sr2EW!JN0=-WzlPjz*3j>c2)e#8@&)}$7GJ;S`N@b=H{2t$~n{ht6xtTLKuL^D@$ z-Gapyn7HbjI9=0em;T3Lruvl{D)cf)$(2%u7UeM%gijXS>sqA5MD?p2NiBK2)_B&S zJIA-p*=?&L(h_uWNeE?Bx_cQ3@996#TkeAyy`IC4`YgsX_|rA<9nnif*u&ko-ea#S z>Q(o&uCIR(-)55r<}D@PiHgApOkr{sZF(w_aQGTNTq3APN;YW#I2EKTseWLuAXa78 znclL)s8&88E_6B6o0%`}EVE!1qiN+foo{~dm=E$VaS{X?^P$*c@d1LR_PE%nj{xz3 z|L@N0f+KM+Air82V?TPeVnn314}>Bk=xIf^>3EZ{spLCyJI+XM{ffHko@ZX_cGxV9{ z0s9zarB|d&Z?QK25LhJ_{81+kt!Dr-60#K;aQisxsth8q<;iFqWT$BThUB!%$P1HO)~=GCoRI?7SqNXJ`YhJ{x9a6l|LfIp zd-Ha*`L1s0(ziQL)r&=U2r z+xU+8Sd5-hK3bnEW~`(x=qG=gTDN|y+!k~?VnzfJC)dnqC3FD$A8em1=%%Bu$Mwhg zz_LfPG&<#&a;AD52nOPiSvGnU(=bJ8EwT{E1aZqjCbV{rA3u)V7W0?+W(8&PV1FWp z>ov>Oc2)0*0hC`1ISNnwrO=*1^ zS_*ez6UX2FkN%CXv`6hU;+a?L}YpB%2blLPpp1GYpO z$uU^l1lPJ0wP9#P~E*%Nm=Kt|(2!ujIuP zcJNU+^t(Lt;!-h8G}+0pc2w;C1udGOFF~j5L0AvXl4evuTj;`~;&NYfyPl_d5FWAP z&H1G>G}QqZ!|n)LOO03W)O>$0qxWiQ&E0&P1IIDpeuoY4w;MDWB^wunHy==FW#$0R z!zRDELCM?E{Y`J*Fon4HynAQ(^y+_k08eNE7wtCUmSHo&EXIZ$L61MQ4J=}7r3ulm zikwi?grb!IR2B_DKSAzjU^Y`t%43<{3BS}x%@ z#-RC^6-wD%A2^qx)T@n;H})j1<#)tp_-4G=McPP*GLkZ4$kK(SH&)<5L+E!jy0X6e z$P(@t7hjNhvZYE1adV6$h`zCSC!Uv!hvp|9@*8K=a{po`wO7v*i4LBa5kcM%%K6F3 z+~G+9UAz*4LD$jo%Dv+~G8)%6uRba`EG@PwSs=zb)*d&v>lrt{bNdUT=MiNQGen4b zHC_uu#jr6+hZTc;nxm&$h1Ry7RZWT4jkP7gs3Bu%-G$-ydye*b{9W~0XyG)LA5Vyx zb3{5Db>ViVW-MH1%*d==$9Jvn$Ia0lOT|3JsebWM`_ubPcmllzJk~`XoeOHTtrCKG z-9a);(!FO3>y+;l>TQFv=&qn4FDF7VK1=BU_AAo*-YSpN=h+z(Br4>0?6Ci ztBuF&>W+<}Mkw{s<;cX(77f!7@8_us4+TOB{zTw{vQo(iXdB%qSJ-f90d)DTM)aPg zPIr@?R&cOQs*TuES#rA>BMSh|5LfnZ6;XVV!=@^?VuCbZI5G4X6WT79mHy4qEI z{7fzYXNw6e-n*R(h<&jM2EO5P{zf*lNqc<=UzkJ-nF}ON&N|M5C;~Q~UBjqRNBdf` zu#x&`b7Xlpi6rShBiL48*M7Csa?nDNG1lkh89C&!E!gmI&U%ko{14}4MAsdBxs2SFd-5+rOjpaoPNfr18df>>~S#g>^| z7`^l1AwAsMH0-{S?Yy;e%d<;>h4PZzhcjQF z(ga=h`Um^0P&B5xz7FqGpkrcNq8)I82cQD+%GY(wIrde>4z651hBSx9+E=vB+V03y zqzJ&ap#yj1pB|VZC|w~wZWNMG&Ui@B>ld#-yHCFV^TPR!*n{~Mdyd0g(4O(+?y z#wW)lca%}dGmF(NY>rkS90Ecu`~n)6WtDP|$6s%#4kHRq-+{f@^el5D9fG)lL-zO3 z3!nMV_Y9m#aNW2@%j8G9z+543S58r)UxS1{@<*u~=W_lMWGKKiw8>Rw3^Q`Hvst@E z%F~(ugdaQ77(p*?+Y{{dj2IRDc`F*eXEF7~U`mcEe)epyB-A?VXgEXd=wV z_mtx0c)kq$0R?pPVeMK8XNM4cGa>PJXLV^}IXsnS>?(EkCdU|RHAhr z#6Xi!Px05VQC_e>^LC2a^D8b3bdEh`zV4rU8Br?17nCq%MZNNi4DNaUz0q@pj{?!a zAjeICbaasWB;z>I-Gvb|0TOP1A!Ry0dCj}LWFhgtb>pp3RpFo210-Tc{|RX1EQ&S9 z2@8J6sS*@;n>O2q2twR9jboRE0?}k*a>ZGgT!*rDc!B00gnNSyh#HMOd5#6eAI{76 z5EX@LbPymn6b`RE@>|?arpMFjE;0znmMvDstznuO*FO9g;Y&D1HN~bZ$%h{wnup;{ zUl$t!t|t9|%1*&8q+58IaiOYYEIw3gdX^ove$MYC!OAWTmXw65Ky>kD3_tAGR9Am| zb3x}c{{sb!6f;p3O33!C3XVcz6~C_0R4!0pjH>G6;Jao@LUuZyMV#MRRm@t-g5UH- z_is$Uc0|{?6tWOe2fP0oQyG$~2WOT2&H!t)ph(@6`b4Nt+OJWJIdETYeozH_{`U3_ zOR-?&Rklk`%RqE0KRuzH@`*b#Q zgTE7t;W)4EX((Zsxw&SPvjKAu| zK8(*YoguPnS>ULC(txYiTTZUwNTs6$efQ~IoIeh}cE0@i%ml3NX0Ys!kYht0lns?r zCcaK1dy4{eDxJEBzV9mPUTL*j^oqB}2!PCKySyAjNOP~@xr0#ogr_+;uAN6}K+&KL zZl0Otq>aJVFF?}oX2cg>#TMwRM71@g6{kF$5;0vKiE^`RO3=}>(Fl{@I_^80prKM{72T8RgpG%01vwj zXQb@$C!%l{z^6%m&{TLWZWwRqzhJDEB%bZR??U(2kKHyO99!+D+V!{GJp|}Kci`NV zT}9&e|H{D2X3Ap4N+l_fRNEt^F5{3FY)_+X?^Q-!9vwwpnbRVVl}~KmiOWTZohOGt z{-U^?4-w@s4+dW^@BBWYd_N?3CeCeuSSV2$=PxFG@&;$o9W8r9b`@`l$&SiTL%idC zM?K%0g#7L^{>{_qS7-Vt;wc*koSV|?%r6xAGol0Tw7>zAo$%3^TAeu8Nx&|1RKis&Y#5Q)o?D5Fmi-Kim-gy?Y-5ESFO8I#mk1uLL8L! zNwmA1A<12ZFtge356tx`v%h98I-!31oASNe zZ%gAxksD8+G5mYXLZzNH$!M6>*q@E?uXh-cGI;^-{+|<~SL+g@3myt4HA{9}t{Ef# zR|Nztc<*4+2yju(0z!#ces9hr=hn#k%HsKwERl({N*ptwI1=;Ppm%@^Zs2S-NLt%? z{55vQk=q9YK|U#j*Yuu%KxDs&^m`FHSu7<+{MipvannGQ?TUPEapI0Lrz0Vi7zrM%EbG-4W z{r6VhIi7D$oJ*Mf{+KHvQ4=5#kE`uj8w)}?-gvb<<{6*UmoE4hHCQ30M{Fyct7jx8 zg+s4XGjc@1R8vhYzhWLFB9B%WZTTpU3x6txMeAo53%(KAc0vo$*Ui|~6SOAMD8%uq z#7jw%NB1JZv?Nx;MF-hM@5z0|$AH%$z|kj(&PNL)mxE2#Fr(9Zk{lNKvi{ZPNB8Fl zQgA*&01sQB&hnznzc|mdmCvW{Xg+Of4Qh1bjOd{LFavD_XEecM##1KrcDa`Im~OeS zIIG+0&(gSqnYrpUi&4iGFOOTdd`iC#`w)FuPV5l*TyZHXcQ|+n;!Qott7yg7;!>8T z>els`Q5ARGe|Vch4z=lB%SC{a9%*mBWz=bPMMyNfZq=$JyeA x_5pjXzEjBIISbrMtf5=JVR!pCJ&yNJCI)k|!4g@Ce__4=d1)1?MhUa9{{nFUm|g$? literal 0 HcmV?d00001 diff --git a/resources/icons/sapphire.png b/resources/icons/sapphire.png new file mode 100644 index 0000000000000000000000000000000000000000..8fba5aeb238dfb004a90b3306f71b5fcc754d1e5 GIT binary patch literal 21013 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

FI~&>JPAR@_*{EU#BH^ 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

qb#NuhcGjW?WF|TJ0 zC9U0K0R5%rMQ{*|j%+80LiLAw;vI8%Zr&+upI4af+Qd#09)l4HKKjH<+{?A^63U@F zq2%Pz23;u^K4{*{S$)6Ph}r8wPe|WG_}^u`-#UH1F_Sd-7^$t3H+Hw{z4G4jDbr<<_SJ`A+4DtX#ZGK6lcwUCtccI7+-1H(5=>37+E8S z8vvF@3+|4~_axeW&U^?n`@)>5C7EI&&&kqMJ*dXhIyjWs`GneGlAkiV6DuIn{W4uY ztj8^DW*kCgOhsT}^R+|b%C%~SHASig{f0s)hcWnj=IS}n;1JVCHeX=1YIl*vI)W-m z`tYV1n4w0Wybj?G&x_wXNJ&p#6PQ4_tBx#}Z_B&CpuE4l-b#=>u@zo<+CLz4?Ixe< zjPxyHh^JcZ+?yqX*g3r-3>g6?*4{n()*_-Z)%f3|@423#D`uV3f1M-0(_R!Z(&0~x zh`=m zbieNqi6%#%Te>sTL0dtgJl#{eTYH|&G*LKKOuTO*GBNVm+KRr!8yV)+O7GYyQ@J<7 zB(BY?QnOE5S()3=eAPg*--L;)9t!jHseX|2)}NBoPi$uA1-1vzj5rCQ$UYFcS=RSr z-0hz9EeDdJeaFT@_`bWM?^Q$BZzaxR;SgE;$1J_r z^ldl3HEjD1BM(dSlo7s_x-~Gn%Ndg!D%yF|I8-Gqsnzt!oX5*jv5dH`ZlSoFEibX~ zem*>)67=oTlcCu*Ar}TmrjUh{)5Dj1LFv>9^BoQU%b|Bx&jb8#?G_=j0lnQhJ9T@3 z7`PuKHD^a%A7^?KAn~we#&)h{g>ri+_<}o}NJIxVmwN|e6wPB^Z~ogJHGc9ua8iY zORerno_4HmAA|OtVN<1l{T>zN8O2dbA`hFj^I(p#wMF7*O-!=Dtlzf?-9Fa=o>}>n zWqG<$BJo8hzl@BpTm>`nPAeVg_<58!NK8P^#QrwUaYohg2iKI7mPm5bhGfxJP1HNh zt7_8s%BX$~z$g>p1YpibYQ+XyPf(`l22ix@{~NAvsTt_>{so98HGSX1&nAH~;pr{aqY38X)t&aa+kOW`quux+sMBY61*&PkeOT!zZR89cS_B-X zF5C^*cHuIY;Bk4T4EDknMh#SQx}=CcZocS#&p~xE%v^Ytlo0U^>mIkxT`nwmFa)AnL~T9IfQD_j9aHdB)%1ofa+gmAAz%o`G6>U;J4E~V8Oe2o zA;z^E2mo_Y1~1@cL4Mw`Jdl)Qs&xnKFovGR6-=`9+VlJ|MyWDE+vx>;z#t4YqR}~X z;6}MH`}IM8Mz|o?3f~E#`!VTj>ZFPF9I=*RrM>>7up zyw=~F)b5&zIom{U#eD9z4NZarx$bA(KM}*n2Z^tYiiIq3ZM<=-orAUszpc|s%N16S zz53_?t=m3Lpc(JrF)5%}ICYn*S@Dfpb~9IGl_ygfQX4U0?Lg{>t@`j}l8Et)dXpbI z%j6IKi>41WLKbQCs`+*q+|8lnMo09$2!X?yE->O4(e{xhuxdsq!xT1OXpubA?qlf6 zonRzYsWncg`|3EvW8aPfBs5m}g7tH?%@@A+n~qPU19mExqEr^^hq3NW#imtt+e#Z$ zm`t2FE>p2&ent5I3IGxR?x7l4mKN6N_1CBpSesIAt&j4SFTIz0=u>2smT{;t24h=p zkL#p+`@KOjvuQ&U=Z}hUbM6US|4BnD&QJrGM5diq3lSmfwqtM5PqH+di|Y6L;CI#0 zYnFFe@oRE)@d#&c-a*Ht<2*rA9GT1)XewqWux@Fy(&E5lqH^Iy=drYOjJy3|)HLPQ zf4uD<32UCKuDFuY2l6aOeba9sE)r0TOUFr>rk<}>sZ1oa4Zro)-{E)O{ijqIT3D=( zc}| zt`J8Wv}TdM99lZU1sis-G3&tU5Q>0JlBQU)KHf>O+TaO5u`a=3=#ByxY}>(dZ^S~~ zBjgFez$b726l=W!S6+Tq<41>x4<)86lu{u{i?a4uAW02A73wL&e|gJq^Ly`mI~6H8 z87=i(-F*VDzUn%*4FwyUd_@*LX<%ICw1faLI?AD8^=Oa5;T6!xsI45Cs(H(;ALN#J zjFA*NilsK38nVX+-CLDD0jbMTK{>%-jFsu|AYVe-anzl z(xQcB#IxJq#7{kE7h48~R^1Re8X{?+K{-u^Vnl;4mEOvb{@RErF=Q|KDIvLn;e74ewiZ);4=IF1R0h}TcNSw&H?|@w{8Z|hUiE{hu z-Rzt`iw#p4G?g^e@NN|(sB?Qi0jp8EsrEK_0~ z3FbIoUxRaO;(Vh9Kl1dKd(D||0)sBx-7Wb2J3q*0xSK#w)lyZ1F{$j)$XNOK6BRyD z?WuXauQf^Dqh$a9F``M{%I74q-vqNOB3fW5iE?=L9=2`RN@fM8$6L+J*o%us8q~3g z=w$L3imdk?Jb}fpg3BDedI&Q)|7l#$uQAl6 z0)3u4^+bN^IoEM+nb9tx)G&7VCRM#ADrtNa)70~aJqjBbOv8S&$lLdSh%YctnTgh6 zs7hr_B70ow_Ie*3&Fs)q6nx*R{l+nX#_Nt=HR*Pz=X|L5SE1VF#_cO>RC1)h%-LHu zG2LoY*LCBs$7bbu%y{CMS%A1AClH{#?&cgl}>Ro}LBOB=Zfy^)7!;X#H*tB7WFsgC!IG#Yq11O`JY?R|MHIu%B z;JE05OE@;az!6r-x3b2{Xh7K(Ryu*Z(*b{e%LlocL#)|S4N;AWMl!p{WOi@S z8@Z{i8+|qW>gxI5I0i7b`F5I;=4o78>nBsQ({mc?J7e&>B0(WgP|LxkFLTcHc4k^r z*itcSfrKE2+C_qiP3d?%X2qz(!~_=|ongwioc{#wId(5c^cW!%$PNFr|DTv&UEsr? z`vkxD-hH$;Y@@0IEsZ=Y`zC(zIWJ~M-(oe62V5TS*pbO_GBJdaqqowhKj<@%ir$or zmH$z0TM94aM zT|Nxb5DFJk-9k_{_lJn;mY*PfjFDh7!e zz4<=FUcrcpUN>@A+T-nC`XIM*nAmOUDE3uQG7XxD0zE(K25_3aD={ig;hz-lRL8Dp(U3Tb5M_ROp0hWd zO~*8N0xQQu!wEQI!c!1U#Jd_0T6Knt371^_IQqR22dlgAM9@I4@VsqL<7fWW53zAs z={5v?7*#SATo|KvF}RcJ`2$*MMlY*5m=D-@=ll3loM$yH)l=v=CD<@?L`_7+PxLrJ zJ)N4#yWjQy2qE4dbpyDcv#h}r80Heoeha%yt?PJ#L(41d+;SG(B*VleC4AqfW0McQ)a1=gSj&Y zrt70`(f}?1I3kTxiCT^wJI1lqMfzrhKP%yme1$(b__utKd$6-zEvXcV#-;h5td;K# zF^rXO&dA4o=H1bWBGjWgBx$?zwyd4+PO+x0`&v`z%^cwm4*p+`7OU%o(i2Gd`V}Yr zh>e4o1ZWkJxIADu7!VmR%MeMbNM1xT&w4~*)Sx6N8KW|A@8Kg1v|`j&)@GG2nt9%O z*G+tZc~qhfR*q@G(8Pp2NjKlSHtajaJRlkFq)qN2n}?c{uZJmTwgCV$vom#nwU^Wy z_mQyM88x0-m*|HD*21le`$L+h__}^T=J4a&ty%BpjVK=0GkX)B!xP)HQAb%QON+}a z4SV#Yf*oD%FiX7k=67*({S{X7kroUzGBRnJ?s2VT@7lt$o0^_JGxH*#n15O2BdeH>;;mDcLxNP}Q(YWB2eT6@=yt-981 z*PA#d-%>Lk010Orx9u5g05AqGDOh8e+Oo0kt**M3G5ZoRMF)A^4EB!8wp^%XS-vRC zGGCXKI~6GtHC?xi2CUia0A|d+H+J~Pz5Wx{b3-5pbu2F|)9VcgiBira+~a!u`4>OP z5r!0L)KUvYF*aq7P2AqKwbi7vd8RgD%*TF)%Nc6`lOQ`pQWbfP* zlXq?<<;bzG@Py4fs?^yV>XG;DBy-+-hQ20gbx}XA7vOO*LJ(Tsk`u|tzbC7}g@9@x zm;_=9W76>KNkd@iv}qEVG*TEC&+u!qd_+T0)~qcR^m_yHnKu27 za;I75&+oX2TRBG0)vA;lH8c#I%HHv_^zv|Fx?g8G;|*ZqkR_qXy-R8_t{oQYz!$?} z_>mXbhfkH6S`?n__#0b7UgotHexZef}%Opydfq7|Z03Dgz}ppa(F zN+iKVhl`GK6zDJa81xG&qm)x{r&;E$`#;Q=ID&w>5Y$UF*2*3g-5c*C&Y#Gsj;a2O z5Ae_>a^f*+h_OlXRMtak=oiY{KK*XJi!Yfi(--p>pZ~KEF-(y#f5##I)rHrvvt{X2 zDR@s3Of#lV8s|@qMS=sdpbm+S<>e(-217>9GwfRKVuiQg@qWI<0@7}4HC$CyHO3}; zNMvtSl&3dsJci`V4g&>B2Zd`$sf|&LQB(s;O_6wxc1rG~j(2rOEJ^+30ToO1`5Z@h z>w&-JD|VT>6VN0u8m?f2Ckv3En4k!jh@;=HxPAXuxO;wqzKaZ|mD}x6e*cbl@i`6= zsk9ufsB>y;X7@;*?j4OD+scPC-2k|+plM9YLQ@9rwS=Bv%9(^J<(CF1LyHVjqX${$ zf8Fr`4u*MF^MYh!iyBXe4Igo&nTh3npuaZ4t3jrx=(XTZj`7Z0-^U#sVnD4PuOh*a znmv*wdxxVzGP7yZV_NxerW=4ZDcLj}=Obvws5clqQ9}`GF1X~PaPXEp%;xPo{+CQ= zHMkx>plF$By>Ln&7WB{6GJwo~qwKJUEk@3@1*1iTts zsV3goT=tNey=%iYw`q1`ot&1Ke{csdp7Q6>mNVM`IG&+9wHtO)K_B^wfbzJp-B2!(BMm35WvFwq|?p+hbg^KHtE*R7B!M9 z7~MX#RWEa!^?asunpU(V0gM`#?l#UM);Mtudfync-aUNcb^N!R`{pl}`?>x_zSgpC z0AOr_O~Izu8<%V1S|K-`*s@(sldf9RR%24NB$|W*=N5K8d34~BcG{z-qlFS9~_Xlfs`P8bnO@EpgY1l}d!8@ZqF)AWPU{7Z4UZT1X z{mERkr&6<=N;vT^N5G>k=A^5gbpe}9bvJ-bchl-B?XJ@5dh)K4wUn&o$y-X+Qe)EH zGp$(+xUOq8FL}a>y}y-z{I@^0c7Sg{Ij($zp+(B3)&?Bbbt64YZb`eVbh=8r zrQ|J5T&rwJ>-w(ikYe1HbecA#&#x}Ol&(7+s>VD@1DD7&z|i*-Bn#(E4 zqxEhVP%PX_*HKtukUhXjl!{t03eDHVADz?<@)Jrn?V`_KLf z0N}<90Gt^D06duh0G4BJmoneK4M<~INio3pe|lkWMan-5h=a3&8puqsNA|x3g{!!h ztErKz8IOsx**^hbWoG4MVCG<8W>sV6UKX2;TqbDj?MV+XoZ?07d&h{{MXc)1>~5f9U^~L@Lkh0Dy>~w3x7( z=lW%@M-REA+w&*C`V#-?(UkOjowEoIGGr(-sR^0$sD!^QS}ajWa~xR$80RiD(s;dH zu$@pOJSSudxD@qq&yOv6t|>W15B0p~gsaYH`@|OQu&uvyYl?p67FVHX0{uL0&V%1R zht*@6pxyB18G}8444JVt`LDidIty;O3Diw%#^8bw3n5D&7g#bY)F#^#z;>xp-gNm9 zR}raq5k@tMSM8Z==#VcG0>?lc)l#ZP0geP1_gN_bKV)48W-tuE6Xf6lfZJL+bK|+b z(9~a<{|TfJQdKRXpuP<-c0m6XRVZ-(ot=E@_1M7#I11VAefNEG;!%+nBeZ`#6p8)HzIECFl4c2IkOB)9r^i3q;-)D z8;LT|i_>Le@W7RPt`DAT)G+o`u$>e%ITt=oZ#J^Z4qQ@oj2rm8QSWWw<8^=yG{Kmq zq3j z_94#){eTiI8r@Mw3iSI83i2YkyH-3J!Xx#VHTErc+^Oj0wV+6$k^;gEQ@0ID3MnhF zcN!PN_xe&`m*0H@K~N?qs=0y1f6CC>tUY7-t{-ez zTdbdEP)+sdfy=R7DgDMdG^Zf>jgfi?sIL}8Gx0S@CMS_st>ON;#n=2!SO4v2;SHCp z1)tKvW0jpK6WyAg>bz(tVy)f5ELWnH-Sbe@f0FKG&6OP490l>H{8%4UP{vLbKuRA{ zLI{Y~7Uy@wyon;0HdaPYKJH}4KIwgI?JpDcww?0G?pR0WzePVR{J{y14-p=Wj6qbC zC(qX0Jt6cwyl#{Kg~#)&DIYs&aapeZH|Y(`uC0uf%c296BribDte#0@i7s$(kq5#g zTucAs%;u|-+v~Pd-aMNgo3LXrqymVw_9Hw?o-pXT1e#vlnI$^N#$9?oE!0scGWXo^o)`5Vcgu# zfO34kdg2HxGE54M*#O8LS+FAph}1@_MRjFy}izf9&BWP^h6Avy0*n zyH_H>Cw%d-WvaQ@|>JM{*V!aIUTH03_t%j#X7=>zz7bxX5h`7_b;cZNeT2-EO* zxz|-zzm{Ol5w`Q+onzNXAiIALS z2ZUv}G_bq$>8_$jH2epD&6v1|qr~E{Go$WrWlJ1r_j`z7tJix2^R809Ei;`fJa z02w~7y9C*-n=Siqvc1wIDRvn#;$_EIY^pfjRnJewPi@E8zw(&4H8es99r)bk*$2ul z1_|j=PZ+h7W{&1Rkcm0s%l4YEKHdGN#}ysItVH(-7(vDM!LGiM6qHHBrf779je@kO zw)lUeNif;=o;|c5yQM=FEkhkOS=&$f9r=napdbOjj0d7ga9=dxj(_I1F9J=Z3|#ll zd1ttv#pP4lE7wS3yCg4~iUXgZ42un8AYVQIoK7&>3)qcJ@WfL@BmOLLb6CuS^VL-^ z5e5n;cp~G^0V?;qo_ErO{;& z-5%{F!2{?Zze|XA9G#TDn2^0eau$+tC%UdZw}`S`ovGzTya$k;N1jPozKCfURMH*yMqzGoa!7-VP!XNYkmm~$e z(dZ2s3P90EhQUM;u;-@-95iod74SSQn$Ojtu?JNrJGh^0CPs9A3UEV*hVqzqjXQnS zE>Fz7jBGZ}LaC%EAw?~Y#b(cdk>MB7m`SdOzR_sH`oeO9-G~e=|0;gTuIMX!ue~>z zkIoY=wjpf==ikgIL{w$Be8hA-J9!1lYV;TDSUBOgz}YIY)mK-5e7DU!60o?If)p0a zKRyrKlX!bw}RZ9CsT(>(n4_2ItYhV;e%w{Inthq1lb{jwn`z;Eb&S(HvJI{! zhYmrr_}C3JLroHlXJ6|RI}UmR>E(~$0J>e+N{BzmSD#0xl8N{sW7hOTJ=4az(HKh3 zp}0yGsbWiu6!SSKIHu~?O&OnEZNG|n#APZ} zS;s7Kn%nO$?!lC+re?auq8>zY=;aK7^{EKrfumXkT-4wxXh_2BV`uGmpuxPM$dnT8l zKHf9Pl=_YLeN!=*3OUCRUfnw-Mf z)!5vk!6T|Ls2_~d(aX<)#7xRpInoJCV1t)Od2@3w2k@tfUbMrE>#|aKTRrvl$TqH| zfuL{8ty2d;$?D_DL+$ShLKIgeL-B8jF@cKD@Qj|4bW^xII55kv0s9|b13Kg_8$oZ0 zgR#>u0WXII5B6J6ml_FH=%S0@;_NH=VpeP@&*W$uEk4UuitHok<)^sM{a<0$OYg9N zPb~Q?DUqy{#B6X2>!Z??mCX06j+$3Uenj1~P1CC2s&v{P}dH)DGLsBDCk-?&}a z`7k{0_RwWfBBCwbI!|W)r8?bdYQ8kDinG(U@plrC@7_ptsxaxQpyy_!n z2zU)1Tqj{87iNL`x$Lun=US36^FR+G^@uXPi!&i z3|aKilki-4>y<0NytGQqR*v#a)E>P4MtxgD0)l`$i@bRW_$f*0}y zXV=p9Ez>X3wSZS(V1?I>3tph4&=0W8H0+YzwL32I&x(R?oH02vB~K?-r8E{M-mS#r{?R{0-`E(c43UCH{nEI$?&p`W&a9;Z$*icHC-+)=EtNq6C$+!iEf z{?;cwId~*dLV=bp#X*$})~)6|Y8h9(-S(~gJZ-bs1M!BF3p}bR1&$IT%csgU6sEoV z)DS`x2vk(%;wl%#5TZr=Tkm4l;RR&bZ?GF65)g{SCtSErv_WByF`jP^EKFb~FsqrYzA+k4wRzJAOQWM;#{FC)C#pD6rg zhmyF6#u$4e+P-6GL{~|V=WcgjDBrJbo{o~|-IdcIQ>T%aWupqa%Ak$FfE|P^rq)Mm z;d{&L}Z`FBp9 zOi^MfyvufU%!Y&4BN4l|Pj)(Y;AqpPg~kx3Co{~fCWy#io$KMe;dRg3BE?T-|CM~A zR#cD?B}@LkGmGtcuhW^Y`GIA5HeJV`bv?$Y^Bgo6f|pbo_w*DEIfa$E_?| z3++Tali&p088He1o4Akm891z{+Y@jh7*H4Lf*KaUXcIqp-&%n+Uj>Gapr0pd30Owjc;le&^bG&8V6= zk0L1|if#hwI!LVCEgl@f&2wiwHgF88?Z3|7-{$ww8Qeww$>ow@LhG)m>!&?01364< zi4xVQ0&a0V*n=}OLCg4UXkI^DNz9!qdy$+L^XYf)0GHCm3qpllLd+EUqBq;B{S)%j zM>k&O)VBj~cnETUZwPK!V}%AXDKd!zyf27ZOOZj^G8>ofuD$O~aVUC@E!$sPN?wI$ z=>7Kg3$@wT~Lb0 zRys8}UlTIL#5>?Cf+&hEBY!?K`wX>*nGS?}8gw8`JL?rLl0)k_Qp;sCifZKCz7LYf z2QmeXo$J|7Z>*|D;T&N#X!sarlzoDhJczZY%*C*dPnEW5#SA7|tuaJ;Y`i+hNq!DDWq!U?$ z9EUm9W5qn+o~eKA&Cx~g#K`WKVbf&)XTYbu{~3&;eVBf9<&ccFI#~KnhFB5Xl@p0@ z95R9-Y4l)tXwYb)p7(`Jz$XJ2Ye~0UVO;WB>-qIPRi2}M1M7Zm{H$Ej)+s3`>F9KM z3Y=0pqQ(kq_nnCqdDS3zOeha$3pO5(JbQs7=9>5WxWaL`8~G%cg4Nl>S;BE7~T3nXXk}?OV;4V1=w>* z4jIAn{^XCT8#o;gipId|0EY@*f{8K2ViVu~XueNI8fT4bN6ijiP@MhE4IIH#c;3|pcr7e6D>wcjMV0f1tsH#gM09@ow#Wb!*#t_5^A z(qMCyjq&O5&0X&s{U3x2@G&+cr6pG3)h(C)OVeNL;J-Kf*6M#(tp}k)Pq9EvNq-(C zd;|Sn5x!T~hs>ps;W?)H_Qo%F-lv`yDMy{=xEd%scWgYF0fD>SAaKs}Fk{(vcAzg+qj+&35*oNz+Xf6AOG;(kYnhJIOTzsgsm37r!D+D;U4e;DY57e!LIw} zOGV$udR#W!=D1-MF>dpR#p(C23lm0nD3y{j`#Yh09;_l>{lrN+#x)&KAzBzS)kd*t z-gnTezRPmve7lxJ6Kd1TLk9On1h+8>1;v?V9P zrG?PpBfzCz!PmTgqn5^M`w!&m@mkzlA;3v2R>wPt5KQpAKG!-iq=|yyLFvnZjejYd zT+ZD|5Kgn#GbScNej-8pU1-a1XF2-E9P7Aihra3VfwfEtE6Fsym>y#BxVb&?@snTd z-DdZX<>FgM>rwf$H@_(6h80m-6-&6yV+20N9Z%^s zQKpoMB%a-VzJ6Mbo|Ektmd2t46|6b6O@h!EX}wR8Yc2oYOKQqxSfkk?v!zwF^W1!{ zq)6E~l{`7~9VFK`x6JJP79?du*9ZaTvNO*0p)mwc}jyTvNj)sl8 zs_Gg+4~9U-o*Hoz;c=o{YYntY#KE@0Paq{#yIYGwizpSfcwf{fVZaOR+6q$vU}EU~|tB zS+v>pjIAR+!{Qc_St~&RMC^+{aMi~3>#+^4lr*~$B;R8R+8pIMd>mxUkux$_Tk6}r z6qmiD3YXG$YtZDh(r7JtmH0Ab=f=w!hdYbdBz(VM1gvzs9UwuPuZk~%E|vG~78lqU zJe_&8tfTQ;u|vUBSJIS4OX2hs5Q$O;^ndin%x;}JvHUR96W&3kahh#E2&+|foM*AX z9k+Q!(6MhpA?Iq4tw_Gqad(~Jdv#s7fX~c!K#oPORddP4yVnhN85c_{-e9t5$F>%i zk%u&Ujb1PtI?CG`Z{WB*4W$N8y;trUct*qkj{ptymsybwOyE3!$uw!UJX~F0%k%i! zH{d>nFYo1t;Mfo`sk$LHx4%eh^CG4zEH#9S9%Z+0!4vcv5p?bITR4V-EibiKDK6)G zg~@0MI1l(%H?fv9;(!*f7n%>Hb_q6kc1fJ%zt#b{0-=pP-rOuJC|qlK;7NMQ*H!rO z7rxnMMWNs5+56lMD{jGbL~fq2;3U`QSD5rROY!ujU<8zmY5ucENg}xH_B0BYrDm;m zoekG^wvYL|l%|N43m;SmM8~6&(2WwvZ2cB5)=M#nCOY&wJA=aM=UL8n2_0tM`fuJ~ zCxrD&{1o;mGw$<&q0R4|;EAL?7=dR4BCCMY>Hw?dsPausyjpEv?_;EZYloCXu4L_b zQ1xu!vh9s4C-l$|*g)UnHNA0PQ~x&q<4|4E`q7-U2-*8*LQ)ZmNMcCO-KS(yOQ+E#*LuOr z+fIcDm6L{2D?Deq+4bi{fKfwZ4`Vj!T_8(1xilg&f50K2usZV(h7FJ+T#5~t)12>E zt?#nsAyTB;_ET}Zm&-$8la30=&4A|`Gta(Ay`|Uq5L9?S%C}VkI&kqVE{!JIeENG` z6`4;o1TF;v7`CQ&&@MgNf~J31k! z(~Utt#BGE>zW(a%zo#O+A3j>F6SB66WFRx4xPRVOiM{InbyOUKgaL5r1%Fo;Dx03S z=A2wR&c~?ld9yD6Y`H~8m)qFj+CnYpxyuq~L!_`Wh871oW1%EPH75&pDe-1(#1~5q z&cq^zL{$~_i=&9qEJYRZm>8DOnQctUui#rgst8n6kvR=14(Yt>%OC|1nbeUKgFRFo z^Og8qWUEj4aBc~0#Ro~Kk->b2hH?JI=g3a z@>(_5ebo!T)LfMv_cUS?;L7&Ep^x~^ih zIw|b((Lz{S4plnglKaP&-ecY!2P2l!H2jm~gCN3SRA$#3Ih(;)vAZwHx1QIMXidLu z0#?A=`<$=W>J z)lQDIK}MrGy3r?v`VuYJyE8VU)H+Waqa&D+m(BQsw@@qk$m4UDJosi5EmO0x@h1-_ zzTeG8eEBuMPdgKFZTfohopzz9It`kdV-SEP>uNpjN z3)Z}*IH51DZt%4Y+apn9>^SZ|_Fl{P8+bDV9%2lamEDiF9pD_jWOK|rwRlCke@oqH zkuqpgC&f0&e&a)%j0709N##a{-g!kJl9`9{J5@xRlga@k`ks23I5Oh%X1~I?`kGsP z-t7-;W5%mETg?xOT&___Q7S2BuP_!zLCv{uS{(uyzTc4gQp-c+?{E@MkP)Q7$5rPct~qY+^RVhpd7kN`O9e>wLmE z!kXo{BXP^>De5>Iz3(?0Y{zzE<&-1NHK2%;=C@D>qb>%n?Ff=c9P6iOox&us%PXsU z_vU|ZA_?klPOW4I(ZJ97UceDqBQj}kdwo&VV`pZa?BPCs&JPi>9clJ!qMe+vb8Zc_ z*S{KH-#Pe^2T9Z1L0X0^Y_fG><=??`v2!QO$;P^p?@Ml0PeZUxIk)XTIG>C+%{G?mbW{L z?rYf?2{U!iaopY5g^C$qnJUwRCVQ{-hbL*nod}5wGie>C8%vj@^quX`1YNh*Yp2$` zl47l}d@FRDjb;X%%uM6n=?WWt49fdy8&tcgYo4;SN78$&KDwYa3$Y7Znh^p-c< zk9A4>HG{!mst5JY{~SA_G>AJ^UKn2hy6!4DtR%*J#jZaevAed5Gu!kDYUP7i z;DBa^$+nV012s}48M|u>-va+$G+N_n8~NC0JsEIGOLAx^t!^tkMP_J7x(l4(zW_S&83Rr{1Tu@^1$q>euuiH9ukyE^ zPqM?P4om*A!LkCZ>D3P)2Bb+gU~e)!xXaSM$wb2H~M68xO+^?F}wi{wR6QF1lk z8d1A(`=khiCuYN=yK6 zo735Ozl8U_2H{@zBToxA$~EX1#N(Gf>teDkWt* z#lf@PslYuB6LX$BGiJoIQ$WGc$MpqSA+EW;%&PDXvyF5L_%#_&d>AR<_B*tu&5w

@!Tezhh%fHA;dpF!$X$%zg#y>=zVWVyB}rJJ&gcLPr~nouT#VS|g}a(vZm zKBXWTy;m-mB^AWH8a#!&9@8QqA(S5)@W7V#R$zmuP1&W|ktD+OT@XOq=W_n{H1#SG zIn2B%mnGgo@c1Hw3p2b-qXNPBs$y_lpGW95eBN$LaJak$DmoJ_C0MC|rq5;Q`0i47 z!@60%`z4V)3XbIq@y6(=CkQDDk%NdBR3Yt}#GT^g^$Z%9*F1d7>Y}B)CY{K{C(jUd zWmtkM=B&?PZMOazZL-I2{rBcQYqV`3?jeWEJj)mxM_(sbmV-PggiNXr*VbjYWcF6G zq99vbZ{z~&CvT?K(P4}l&K5%4h6fRy)3?8h&}3u!DfBkLUe@zE`Z% zQu{RU38|*sF#Hv-K{O^=>&rPYAO2x**n>!NYWHgr$TWX6+AI#bKm9bMAP#WuPn0y_ z<@-y|{v_QD??*xzm*^T`kXU;rh5bJX<8NlOz8wKdTe2pDzBo~eBaS`AeG=>&>v&rY z1Xs1X?sC;5f!M$d{gj`!&sO@zVuFH(1xu(9$g;S29hR5bCK_)!E8DwaeB+sWJGtYHPk z(;|=uXICQ@{UVT`)!zF$T94{lyy9m5OXmV1eXPIfePi6b(DC-8Ek#sJ~6d} zb`R%l9yn@!K^>-5{;4JUWPt<}lBP$_)dMo3n|{+81$J#U9Bc3{Yp)Vm*D8#_qm>EC z3+EyPUg?Q15q&0}T)+@4`O&Tv4Xrnt{w+SZ$7}P&G8#Q{9d{em{~WqLhd9pFp~u!v zv~f_42hyHRH6(V;I8Mq-v|a#vB{ z{!?qyQ)J;Vojlz|Jf->|rr{dt0hrXOV-+Q#ydf$Mvq+O18^3m*ed%(=~%t9tUwArWMh4 zHt~{sDU{*#=7Lu57^*l7C9>SGj-v9$-0Mt^z#(M^Zx~;CzD*Wren=DI2r81_qaYsu zdY68g+s*YCJTdvcGYxA!n@9Be*YzD8v;>560T&AT=v*nI&l3%{$ zk@gU7*f2B+WcDM(xRRgp`}S5lrGCW-pqEe9zW?CqqN3o@)~dbt@{zcTqS?^95+F1{ z8NBRl>gw_F`)>eB-S$Twdj;4W@_}KG#Eh z2RWuP4%`j$O6AwIrI(QrOpvZ~o(v~&Yn9i3>Zftl#@z=&3{V?*p@U710b0%A+vYiJ zS#=a$#cE?J6%IM3Ti@K>UDM3LfgSv$)$iiR%C>N-?|bV~n>mawV0cv_bT|k=rkF1& z?4v%3U<&ZK9pdfRk2xeS7cb&q)cU%3IyF&rKs+^0sZ5O2sM$`_?h(oY^#=fyWUxhX zs8wh%R`SPB%DV6C4L-kL^)}bxFXjx5s~%t+us90955SKtYC?#70IA+RhA77}^1P_x zyB_A~G;>lnMJC>{6==L|ZY%gcwQfd>+=7vD6wvTx>DxQQ=0Nbg9o?cP>|qn~ zq3Xb8M@kkd{O)kK=eh~dpV@PxF&P^x+kb~C@~CqC?AI^BY2Y}K-~+St_;nlbD=BK* zAy`pgH`@jEKgL>#q<|0Ph2X%(`TPa{qn}K&P+erw4D5f5FaKOJz|Nr){}`Nn<$ZdT z$fnhSMF~dnoj1yM+xvqju(5$&PjGV~k%T;G<+VLP6yj8QTON&?eynvaDh28z2AEx0 zmH&wkjtnQJj?qecWE0s9*rx%1#Nl6<^61(-(z4i_m9ByTGcF-vNkcD0H_`qH;<9}s z)lep337ytaTWqERMlYYT+N{9Ow(UG4FCO8Z%%Wh^K(nIn0@UmEc6(kmqbeVi#o$?L zVl*NItn<3)I+{g!mnqf2cxI$jENpfkhkpzicqXVnWir~SNZ=fFT)E5ywBp3dS~J=t zSJu?xfvx^=zO9U+03`lVL5qcyqv@;(%SoMVhY;_QbkKT!e7d}JX!pKAHYrBhReOp4 zg@@i+rgTvdxP7grEuA%n2)M^3j}eNEgrsKED^=O-lUu~%G5ZNScyQT!aK1I4l)^KS zQK!JWke^m)*Vgp;ELpIs?4ZssaqN!L;asY zcE{&-B0-4_!Oh+?Kh80nMg~~oo;)+U=-8T!%Lc?63;*(o{+)-68KyKtiz6icp+Od1 zh8D`0{|5TE?o!Zpr{Qs8iZKT$gA$CO5Y=Az28zPKCdh6rn8Apu1T!2lM}BB@0&r2r zn1jZZDFf1mW3e~?34po7O$-u>jBeFwk85_cb#gfUeMkO)&zQcylEbY-L$56_cZ6@Q zeVNkeT=m4vMR}1)XTQp^owX*XG8Nx3jMY1e!ul~s_5rkxdNpNZz#ulj>-;u znFoTkWvl5_CGKk%p5(A#6-P)IDcO z1JZJRSY^vbBT8)sMY7eZ`m9xC0h-T$Nig2)vAN;1u38}6 z%V}zo$tDOC@xhm4SEph^ii^ZK8+{IV$os0(+mW_GABHBw$D7f5Xt}DY$zT3cp)v=W z9VZ-o&Fj+Q?YgAfO6ycW=Z_+CI->-&PM=U^)t1%x?B4J888J!ju}oYEiyJ4lD^9&K z(K8(1;XrXRG#TRgqW9~m)&2G{p|_$caXWTs>IsJCe$ z5yUp|R1Za2wB^TktC1nk*TnJmb-m8>qxPUZBo08^dw(`84{qAip3Ge$Hbx%xAhM50 zFB1%~N}FUdouJek(rIGK5Ixjw6}<<1ZLj-MNKZl? zz=f#K(n^d3n7ym(VV6F1)rx0QH3FuMvpXfPhwT-i&*nI#9ej3A#=-D@%LCFw+PdXc z|8Vz3vc@uDxr!tQiM-@wwYtsZ6#?27L9d-vg0waF)tYm`eco*6?gv$Quf1ltHis{k zx%=P4Fe)5pc1#T4Q{M0Pm(2vh-Bf9-c_D1WIR5_6NjQCVo2L0!cdG-uN!ukym}M`3 zVI9Zh=8y0)Ry_6J(eOHO^9$dlKgr}Y~mrB&7QYSVm_o%?2fcrtxNKM1NB=v zubF^gF~Sp!eTQDrvQU><6?t_YoBlS0C*%-%sHmNLSLYXwB}@GGu?q{N35is4*Jo*4 zW8vm6SC5(x0(Y%~(zwZZ&|2EH>GwP{eAgU|8*GV)9Oc@{g4;2bs10>2yXxA2&{CPobiIO#lr1^b+AhdF4&g!Z{}ZVEUhf%`J!ijQ-c+v z|AmW)pz-EM*q4VM$zXo74O5pei4Sidq;PI+;~h42cor zlrG}#G_(9|WzhUSF~!L%&n{3|9pWgD{B4|ujUG2NM3!yQD;f8izzUFIS*_)gI-}{F zF}uB^5bw_MljrDDnKeqyOj(Q5;rbK3XVPS5LZ`AoCtj=38~kj2!@QHis$-+MjqgAl zN%y)Nr2nTF0xr2x9M0Q@Ylkeq?Xn?6YQz6~V+UrY>kuM8laeh3r@I^P)4>1X^5V{e z*9HvLrnIZn^UBJBUW0SSW@MT_+R~xY|D-UN+&DNC+1JDLKn#q|^-Wwf6sfqF2?7{no@@&;O zj!mj`+^tV_j{?hd28*!APP)!RD8(42=;__?8>DpFE>Urj!|Qb0LRNvHu}ot$d74Ah zhf6kg3v(_050X}KpwIguN1NfV#hVs4*3KhIuA_{;3l;PI*q-B%exf!rt_sd6t4vHv zdT1<0PkHydU<>#}E~n(wK(@y0A>9gv7$8p`YtA_}WiXA9Xx4cqxo62?9DnS2LYG0u zUP#+e{Gu!q<^zB=^cbw&EH7U?iUmBF>4^vJR_Fj4azHl+tI$;=l3F=$fO3}*LqEUE zn;24>dUG`HJeqA;7uiHAcZSbu{@0j)%I24RK2)G}z@p53zASCkQ8A`>yqRo9H-GmS z?}qoe>P+aO`0DmrTD-&BT<=kOP3KX*!%_nqH$107p+&4f^XJ2Y{#sKW%ADmN@Hqdh zyvgOO^nT^eO4p|cW@_H>BlQI+NviYYiUstk%iimqI|nC8e-ALcR=f>AbYJs)5Ybg3m8Ri9bNpkK27sA6)~l&Rk^H8U*>yyjgw_q+>I8MrVxoOQA*c6~G6U8IfjZ1Igvx06re z7X4j&RE-=NsG>W4f(;x^f&g%GWO?FjsrH-9K_NTarkBwKfvlZ{-aZIn2sA!^sH10L z!QTQjdV(x~4x;G5m=h0DZ~S4Gkher@WB1T0Y0e}!MLoZuysY@qF5E~pZzY^JjkGl* zLgJ17Nf8Y(REg}E$vtDs6BkJMa0lU8Fg zJGp}zqst9%#JUPE(m8y|9KYSxb0Daei*8^Y)~VO{F@^4%sbf7(tR1fs5AH6AVF7>nWn$H93ZTHW<{XT`w z+8ktnKQiGH5YXH0Uh^;K)7gO}{^a_ue{4QMT~ta?vO6q~wL1lf0oBtAteQthqU1n| zQnwg_o6Uw(sLL8o|5n8Aym=VRbG{Kj63iJKeB8`w?@qv*7OP(Y9k*|3c!%9NW%uFB zfxFOMa?sm}E0UZcC2secp8wQ)N;jAO3J$KlMn%-*4Aw#6$L=RszKm6(F=ckGZT`9= zJ%{M2%$SJZsYPU+{{beRG!V%s|0KcqY019S!_k7 z`>1Z0>)Nkd1&>i}l66t(BcITdh62LA!xxjGC!dwBvI&h%_LQj}$`R>sYhG7ZD36ss z_k#-4@-_;(3v%V=P66Jx0jh{=w#U-Ek$|-a1sXHj(e-}Iqes&F_>}u)&gH4 zWkdeHUOvXCq1nuMh{CHxwF0vX2%LuZT~i=086{TKdSjn2R;P8+Qd1?@@b`-|t0!BkHZO9$yvmEF3x)2a z7Po17Ig=-P+V~YGKhq+DB69MBqKB;dYeKI303gV}#jhp&R5`bo2KWTBfr=r`iNEAP ze@E_h$t(Q4=ApWx`!=r1 zJO|5&eGJf{sqqe(l9s%8{5xfEW;gC&=RT#8NS~V5`wIB={$m(6Uor;q9kT)H5efDK zWA_}HK*h7QyVHBWX3Amfy;EVujRUBIA06Xgw|&j5f=*42Y@Oo0&_&17-rm0*>l(_v zA$Kkq)Sk9N8KHMEQ$dCRxTn~!3EW`r$ZQdfcs!~(7ufFb`slu-VT&inA$h7kFhfET zkE-+xwo)zSU0d&K{S?#@-1@y{U3>~ojqk|&r>44wcM~;0kY^qMa3PSUL}48HQ%8FK z(}c%~+NxV|=XK@OuGhi6tCe6?&AdC5AD_oGUTT;!$kKxi#lb4zeOj^nPpm9F%P>xi z8CNlrglRDkpfLdV$ky+0ubj*X5vur0!x1Y;lQ=W#a9DZpBxw?G&g-kn`)` zOL8)`lM*?h(}HPN)%#=4*V@H?9sB&;rfD=qVGroO9==$8{*bujzsgxq>&+^v{9B;* z{F~W<%6XI#F$d2yFz)+h@BKi+#jozsK8yODdd{E2*XNVPf9&sxbw$c6mddXhUl3``(+M0|jKB zYj*|RNj#_K29I-3g+HLJd;+&pwig~x?U4-#MemszhMkvuf^QEQsbnoyOU}D?`VO3R zN^&IFaOf)ZkvwS{`eYRSU)oMh#3a!GfZ#}Ol-H!l9%*rT#@>^xSx%27rtj@{*FW|r zVXoPeit`gbmFYQ=)>)c6L@0T7Q*~zs3Z5wOvlWs(_{F}-J<~in0 zl<7KX8Bup&b20}789hz?DSQ46PMNx5l6e1a5)@|@YA>P~y2wPNK3Xf?U9Ycng1Rqr zPE0`f#*rb^8f9W+Xht$b`PX{A&ni-ro-8(DVmKMsxf3E~!uiC&Tc3)GDPD|EXbjkY zC69%%yWESPFxubT**u~Tf5<&T>)ZQ$KcSjubK%>*gv9Tm#*rI`*%Nkp_t4hN>#Q;4 zP~;z!9UDzQh+IM;JPBb5fPlas4tq=hO;Eo0|&?08}?!GU|Q-6mE>c{gLnR{}oJ ztJAUQcu&COPWv-XG-Mbb)?J1~)H&#C)hZ&v)9Q@9cfjXZN`c)*66dH`F?caULQ$)h zwH7WmemeMIHmEH*_RVOa^l+SOr_=fI23M?sGMwD{qKuG}STi996T|}A6007IMyro@ z;M1S%z&=pa<0FE~aFJQBxtk#|Nj?B!rZIYt_=o%MJoRKGOR_AlL^svz{v(kr=cMk! zX{Q}}a@tsT4XR1M&DbW%H0mD-EM=GAtRg%22BWj1X@;Esf|j*pAwoEV$e^|$S(>T7 zkj0k--6+RYFhHhFnm^dh8+M8E(yHZu1rP)8{4{iu`)Zee|9#ROzNaV6KrDpl3qs7u z@XVkDJUtZ69i}JPkYQ?5_`%J+Z`|@3nTXqKiAmInjb4L^=<9*&4LEa9KK>(@`S6ng z0GP83J`eml;JV#zNJ(`qS2sR;K2k|!yaz*u953KYZp`O2e>9FSnK3tlYDcr9(x)NBbs!t5~AQrQ& zyCsQj-#z(+6K&p(rYloiv*|x+%QjF?lf@k0Jd1(aAjzUm`0g!V&TgIg;Xq&p!3Q)t z;KLDqSN7BROHRu^V?X}O{fxs*KPeKRPkqbat-v=BT+rMHX5^~zFE+n-*JnCrVXiU= zJ?%m)ur|e#Qya3_;h@*t{oT&plh-u^6GZ2IBsxX^J8FEhL5|qC{-M%O8UW@u1AirI z?f~Z?3%QJ&Z{Gc>#tmD()$S#`Fa&j2l2G92siqlsZM(UB?dI<_CKxwh0wFlyPKd9Z zRpwBhg++EsPvNt0GLZD+XH$jG48<_Q|L_G!@cgS*Z*s}OYiQ~>LMu#844!I zjN9D){@Smm+gaz7ES8Oa`~-wcf!)j=!gMsT_x}NUfZF+fua-+F#kM!Nm@uLVW0|87 zoH$LzXpJ;98O!R7s--^PoAVsX?tac-c(5{&y(e~%<8gX;^dQX>`icF&Ot~!-BBCOq z#yB;`s53^LL7g#b%a%_?_1-rFdollU033mI5ZyESAb2lj5oS>Wz{~@H=>woJCG+3c z|Lpvu-4BZW2g~@!0r1GsK>%Q`a}#{Nk^sd408msC;0x7z%giz!2fz_c2iZfX&%Xf? zxxNB{7b#mrTf|q7Hy9YKT40-fng56Y;Guuxiw%lWV{c8dCVWT$m)tM z2W0-^05}5aA$HNS)$2bcBAs~>plgw*+OqAVy+7tZ4uB(&9%>u4Dy0k&d6kIlvdAur kysApqb`Qk-pF{xs|A-WJa&a8;=>Px#07*qoM6N<$f~dd2Z~y=R literal 0 HcmV?d00001 diff --git a/resources/light/bot.svg b/resources/light/bot.svg new file mode 100644 index 00000000..812ca349 --- /dev/null +++ b/resources/light/bot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/@types/api.ts b/src/@types/api.ts index 68d71339..d5311029 100644 --- a/src/@types/api.ts +++ b/src/@types/api.ts @@ -13,6 +13,7 @@ export interface ApiVscodeUser { customdomains: string[] locale: string plan: string + planDataEnd?: string | null ramUsedMb: number subdomains: string[] totalRamMb: number @@ -35,3 +36,57 @@ export interface ApiVscodeApp extends BaseApiApp { type: AppType version: string } + +export interface ApiSubdomain { + date: number + id: string + status: number + userID: string +} + +export interface RESTGetApiSubdomainResult extends RESTApiBaseResult { + subdomain?: ApiSubdomain +} + +export interface RESTPostApiSubdomainResult extends RESTApiBaseResult { + subdomain?: ApiSubdomain +} + +export interface RESTDeleteApiSubdomainResult extends RESTApiBaseResult {} + +export interface ApiSnapshotVersion { + date: number | string + size: number | string + version: string +} + +export interface RESTGetApiSnapshotVersionsResult extends RESTApiBaseResult { + app?: { + id: string + } + versions?: ApiSnapshotVersion[] +} + +export interface RESTGetApiSnapshotDownloadResult extends RESTApiBaseResult { + app?: { + id: string + } + download?: { + expiresAt: string + size: number + url: string + version: string + } +} + +export interface RESTPostApiSnapshotResult extends RESTApiBaseResult { + app?: { + id: string + } + snapshot?: { + allVersions?: ApiSnapshotVersion[] + size?: number | string + url?: string + version: string + } +} diff --git a/src/@types/structures.ts b/src/@types/structures.ts index 5cb8dba4..5137bdc5 100644 --- a/src/@types/structures.ts +++ b/src/@types/structures.ts @@ -88,6 +88,21 @@ export interface UserTreeItemData extends BaseTreeItemData { tooltip?: string } +export interface SnapshotAppTreeItemData extends BaseTreeItemData { + appId: string + appName?: string + description?: string + snapshotCount?: number + type?: number +} + +export interface SnapshotVersionTreeItemData extends BaseChildTreeItemData { + appId: string + version: string + date?: number | string + size?: number | string +} + export interface Events { activate: [context: ExtensionContext] appUpdate: [oldApp: UserAppTreeItem, newApp: UserAppTreeItem] diff --git a/src/commands.ts b/src/commands.ts index 1f256862..2a5570ff 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -62,8 +62,15 @@ export async function commandsRegister(core: ExtensionCore) { commandModuleRegister(core, "domain/refresh", await import("./commands/domain/refresh")); // subdomain + commandModuleRegister(core, "subdomain/create", await import("./commands/subdomain/create")); + commandModuleRegister(core, "subdomain/delete", await import("./commands/subdomain/delete")); commandModuleRegister(core, "subdomain/refresh", await import("./commands/subdomain/refresh")); + // snapshot + commandModuleRegister(core, "snapshot/create", await import("./commands/snapshot/create")); + commandModuleRegister(core, "snapshot/download", await import("./commands/snapshot/download")); + commandModuleRegister(core, "snapshot/refresh", await import("./commands/snapshot/refresh")); + // team commandModuleRegister(core, "team/backup", await import("./commands/team/backup")); commandModuleRegister(core, "team/commit", await import("./commands/team/commit")); diff --git a/src/commands/snapshot/create.ts b/src/commands/snapshot/create.ts new file mode 100644 index 00000000..ee9caaef --- /dev/null +++ b/src/commands/snapshot/create.ts @@ -0,0 +1,29 @@ +import { t } from "@vscode/l10n"; +import { ProgressLocation, window } from "vscode"; +import { type RESTPostApiSnapshotResult, type TaskData } from "../../@types"; +import type ExtensionCore from "../../core/extension"; +import Command from "../../structures/Command"; +import type SnapshotAppTreeItem from "../../structures/SnapshotAppTreeItem"; +import type UserAppTreeItem from "../../structures/UserAppTreeItem"; + +type Item = Pick | Pick + +export default class extends Command { + constructor(core: ExtensionCore) { + super(core, { + progress: { + location: ProgressLocation.Notification, + title: t("progress.snapshot.create.title"), + }, + }); + } + + async run(_: TaskData, item: Item) { + const response = await this.core.api.post(`/snapshot/${item.appId}`); + if (!response) return; + + void window.showInformationMessage(response.message ?? t("done")); + + await this.core.snapshotTree.refreshApp(item.appId); + } +} diff --git a/src/commands/snapshot/download.ts b/src/commands/snapshot/download.ts new file mode 100644 index 00000000..5b157914 --- /dev/null +++ b/src/commands/snapshot/download.ts @@ -0,0 +1,29 @@ +import { t } from "@vscode/l10n"; +import { env, ProgressLocation, Uri } from "vscode"; +import { type RESTGetApiSnapshotDownloadResult, type TaskData } from "../../@types"; +import type ExtensionCore from "../../core/extension"; +import Command from "../../structures/Command"; +import type SnapshotVersionTreeItem from "../../structures/SnapshotVersionTreeItem"; + +export default class extends Command { + constructor(core: ExtensionCore) { + super(core, { + progress: { + location: ProgressLocation.Notification, + title: t("progress.snapshot.download.title"), + }, + }); + } + + async run(_: TaskData, itemOrAppId: SnapshotVersionTreeItem | string, maybeVersion?: string) { + const appId = typeof itemOrAppId === "string" ? itemOrAppId : itemOrAppId.appId; + const version = typeof itemOrAppId === "string" ? maybeVersion : itemOrAppId.version; + + if (!version) throw Error(t("missing.snapshot.version")); + + const response = await this.core.api.get(`/snapshot/${appId}/versions/${version}`); + if (!response?.download?.url) return; + + await env.openExternal(Uri.parse(response.download.url)); + } +} diff --git a/src/commands/snapshot/refresh.ts b/src/commands/snapshot/refresh.ts new file mode 100644 index 00000000..723795bb --- /dev/null +++ b/src/commands/snapshot/refresh.ts @@ -0,0 +1,12 @@ +import type ExtensionCore from "../../core/extension"; +import Command from "../../structures/Command"; + +export default class extends Command { + constructor(core: ExtensionCore) { + super(core); + } + + async run() { + await this.core.snapshotTree.fetch(); + } +} diff --git a/src/commands/subdomain/create.ts b/src/commands/subdomain/create.ts new file mode 100644 index 00000000..9bbdff6b --- /dev/null +++ b/src/commands/subdomain/create.ts @@ -0,0 +1,39 @@ +import { t } from "@vscode/l10n"; +import { ProgressLocation, window } from "vscode"; +import { type RESTPostApiSubdomainResult, type TaskData } from "../../@types"; +import type ExtensionCore from "../../core/extension"; +import Command from "../../structures/Command"; + +const SUBDOMAIN_NAME_REGEXP = /^[a-z0-9-]{2,20}$/; + +export default class extends Command { + constructor(core: ExtensionCore) { + super(core, { + progress: { + location: ProgressLocation.Notification, + title: t("progress.subdomain.create.title"), + }, + }); + } + + async run(_: TaskData, subdomainName?: string) { + if (typeof subdomainName !== "string" || !SUBDOMAIN_NAME_REGEXP.test(subdomainName)) { + subdomainName = await window.showInputBox({ + prompt: t("input.subdomain.prompt"), + validateInput(value) { + if (!SUBDOMAIN_NAME_REGEXP.test(value)) + return t("input.subdomain.validate"); + }, + }); + } + + if (!subdomainName) throw Error(t("missing.subdomain")); + + const response = await this.core.api.post(`/subdomain/${subdomainName}`); + if (!response) return; + + void window.showInformationMessage(response.message ?? t("done")); + + await this.core.user.fetch(true); + } +} diff --git a/src/commands/subdomain/delete.ts b/src/commands/subdomain/delete.ts new file mode 100644 index 00000000..51b67b66 --- /dev/null +++ b/src/commands/subdomain/delete.ts @@ -0,0 +1,35 @@ +import { t } from "@vscode/l10n"; +import { ProgressLocation, window } from "vscode"; +import { type RESTDeleteApiSubdomainResult, type TaskData } from "../../@types"; +import type ExtensionCore from "../../core/extension"; +import Command from "../../structures/Command"; +import type SubDomainTreeItem from "../../structures/SubDomainTreeItem"; + +export default class extends Command { + constructor(core: ExtensionCore) { + super(core, { + progress: { + location: ProgressLocation.Notification, + title: t("progress.subdomain.delete.title"), + }, + }); + } + + async run(_: TaskData, item: SubDomainTreeItem) { + const subdomainName = item.subdomain; + + await this.confirmAction({ + action: subdomainName, + throwOnReject: true, + title: "action.title", + type: "showWarningMessage", + }); + + const response = await this.core.api.delete(`/subdomain/${subdomainName}`); + if (!response) return; + + void window.showInformationMessage(response.message ?? t("done")); + + await this.core.user.fetch(true); + } +} diff --git a/src/core/extension.ts b/src/core/extension.ts index 140defde..d980a05d 100644 --- a/src/core/extension.ts +++ b/src/core/extension.ts @@ -8,6 +8,7 @@ import { commandsRegister } from "../commands"; import { loadEvents } from "../events"; import DiscloudLogOutputChannel from "../output/LogOutputChannel"; import CustomDomainTreeDataProvider from "../providers/CustomDomainTreeDataProvider"; +import SnapshotTreeDataProvider from "../providers/SnapshotTreeDataProvider"; import SubDomainTreeDataProvider from "../providers/SubDomainTreeDataProvider"; import TeamAppTreeDataProvider from "../providers/TeamAppTreeDataProvider"; import UserAppTreeDataProvider from "../providers/UserAppTreeDataProvider"; @@ -39,6 +40,7 @@ export default class ExtensionCore extends EventEmitter implements Dispo declare readonly statusBar: DiscloudStatusBarItem; declare readonly customDomainTree: CustomDomainTreeDataProvider; + declare readonly snapshotTree: SnapshotTreeDataProvider; declare readonly subDomainTree: SubDomainTreeDataProvider; declare readonly teamAppTree: TeamAppTreeDataProvider; declare readonly userAppTree: UserAppTreeDataProvider; @@ -194,6 +196,7 @@ export default class ExtensionCore extends EventEmitter implements Dispo await commandsRegister(this); const customDomainTree = new CustomDomainTreeDataProvider(context); + const snapshotTree = new SnapshotTreeDataProvider(this); const subDomainTree = new SubDomainTreeDataProvider(context); const teamAppTree = new TeamAppTreeDataProvider(this); const userAppTree = new UserAppTreeDataProvider(this); @@ -201,6 +204,7 @@ export default class ExtensionCore extends EventEmitter implements Dispo Object.defineProperties(this, { customDomainTree: { value: customDomainTree }, + snapshotTree: { value: snapshotTree }, subDomainTree: { value: subDomainTree }, teamAppTree: { value: teamAppTree }, userAppTree: { value: userAppTree }, diff --git a/src/events/activate.ts b/src/events/activate.ts index f3a10eea..63f1805b 100644 --- a/src/events/activate.ts +++ b/src/events/activate.ts @@ -52,6 +52,10 @@ core.on("activate", async function (context) { core.logger.debug("Activate: done"); + await commands.executeCommand("setContext", "discloudInitialized", true); + await commands.executeCommand("setContext", "discloudHasSubdomainsAccess", false); + await commands.executeCommand("setContext", "discloudHasCustomDomainsAccess", false); + await migrateAuthenticationProvider(core); const session = await core.auth.getSession(); @@ -61,8 +65,6 @@ core.on("activate", async function (context) { } else { core.statusBar.reset(); } - - await commands.executeCommand("setContext", "discloudInitialized", true); }); async function migrateAuthenticationProvider(core: ExtensionCore) { diff --git a/src/events/missingToken.ts b/src/events/missingToken.ts index 933cfc37..63a84851 100644 --- a/src/events/missingToken.ts +++ b/src/events/missingToken.ts @@ -1,16 +1,23 @@ import { t } from "@vscode/l10n"; import { commands } from "vscode"; import core from "../extension"; +import { localize } from "../localize"; core.on("missingToken", async function () { await Promise.all([ commands.executeCommand("setContext", "discloudAuthorized", false), commands.executeCommand("setContext", "discloudUnauthorized", false), + commands.executeCommand("setContext", "discloudHasSubdomainsAccess", false), + commands.executeCommand("setContext", "discloudHasCustomDomainsAccess", false), + localize(core.context), ]); core.api.authorized = false; core.userTree.clear(); + core.snapshotTree.clear(); + core.subDomainTree.update([]); + core.customDomainTree.update([]); core.statusBar.setLogin(); core.logger.warn(t("missing.token")); diff --git a/src/events/unauthorized.ts b/src/events/unauthorized.ts index 52101eee..7f547ea6 100644 --- a/src/events/unauthorized.ts +++ b/src/events/unauthorized.ts @@ -1,15 +1,22 @@ import { commands } from "vscode"; import core from "../extension"; +import { localize } from "../localize"; core.on("unauthorized", async function () { await Promise.all([ commands.executeCommand("setContext", "discloudAuthorized", false), commands.executeCommand("setContext", "discloudUnauthorized", true), + commands.executeCommand("setContext", "discloudHasSubdomainsAccess", false), + commands.executeCommand("setContext", "discloudHasCustomDomainsAccess", false), + localize(core.context), ]); core.api.authorized = false; core.userTree.clear(); + core.snapshotTree.clear(); + core.subDomainTree.update([]); + core.customDomainTree.update([]); core.statusBar.setLogin(); diff --git a/src/events/vscode.ts b/src/events/vscode.ts index 6b75f848..8b08e819 100644 --- a/src/events/vscode.ts +++ b/src/events/vscode.ts @@ -1,19 +1,34 @@ +import { commands } from "vscode"; import core from "../extension"; +import { localize } from "../localize"; +import { canAccessCustomDomains, canAccessSubdomains } from "../utils/plans"; core.on("vscode", async function (user) { if (!user) return; + const hasSubdomainsAccess = canAccessSubdomains(user.plan); + const hasCustomDomainsAccess = canAccessCustomDomains(user.plan); + + await Promise.all([ + commands.executeCommand("setContext", "discloudHasSubdomainsAccess", hasSubdomainsAccess), + commands.executeCommand("setContext", "discloudHasCustomDomainsAccess", hasCustomDomainsAccess), + localize(core.context, user.locale || undefined), + ]); + core.userTree.set(user); if ("appsStatus" in user) core.userAppTree.setRawApps(user.appsStatus); + if ("appsStatus" in user) + core.snapshotTree.setRawApps(user.appsStatus); + if ("appsTeam" in user) core.teamAppTree.setRawApps(user.appsTeam.map(id => ({ id }))); if ("subdomains" in user) - core.subDomainTree.update(user.subdomains); + core.subDomainTree.update(hasSubdomainsAccess ? user.subdomains : []); if ("customdomains" in user) - core.customDomainTree.update(user.customdomains); + core.customDomainTree.update(hasCustomDomainsAccess ? user.customdomains : []); }); diff --git a/src/localize.ts b/src/localize.ts index 38a24add..94342230 100644 --- a/src/localize.ts +++ b/src/localize.ts @@ -3,6 +3,8 @@ import { open } from "fs/promises"; import { join } from "path"; import { env, type ExtensionContext } from "vscode"; +const localizationContentsCache = new Map(); + async function importJSON(path: string): Promise { try { const fileHandle = await open(path); @@ -14,19 +16,42 @@ async function importJSON(path: string): Promise { return {}; } -export async function localize(context: ExtensionContext) { - const firstLanguagePart = env.language.split(/\W+/)[0]; +function getLocaleCandidates(locale = env.language) { + const normalizedLocale = locale.trim(); + const lowerCasedLocale = normalizedLocale.toLowerCase(); + const firstLanguagePart = lowerCasedLocale.split(/\W+/)[0]; + + return { + cacheKey: lowerCasedLocale || "default", + locale: lowerCasedLocale, + firstLanguagePart, + }; +} + +async function getLocalizationContents(context: ExtensionContext, locale = env.language) { + const { cacheKey, locale: normalizedLocale, firstLanguagePart } = getLocaleCandidates(locale); + const cached = localizationContentsCache.get(cacheKey); + + if (cached) return cached; + const bundleDir: string = context.extension.packageJSON.l10n; + const contents = Object.assign({}, ...await Promise.all([ + importJSON(context.asAbsolutePath("package.nls.json")), + importJSON(context.asAbsolutePath(`package.nls.${firstLanguagePart}.json`)), + importJSON(context.asAbsolutePath(`package.nls.${normalizedLocale}.json`)), + ].concat(bundleDir ? [ + importJSON(context.asAbsolutePath(join(bundleDir, "bundle.l10n.json"))), + importJSON(context.asAbsolutePath(join(bundleDir, `bundle.l10n.${firstLanguagePart}.json`))), + importJSON(context.asAbsolutePath(join(bundleDir, `bundle.l10n.${normalizedLocale}.json`))), + ] : []))); + + localizationContentsCache.set(cacheKey, contents); + + return contents; +} +export async function localize(context: ExtensionContext, locale = env.language) { config({ - contents: Object.assign({}, ...await Promise.all([ - importJSON(context.asAbsolutePath("package.nls.json")), - importJSON(context.asAbsolutePath(`package.nls.${firstLanguagePart}.json`)), - importJSON(context.asAbsolutePath(`package.nls.${env.language}.json`)), - ].concat(bundleDir ? [ - importJSON(context.asAbsolutePath(join(bundleDir, "bundle.l10n.json"))), - importJSON(context.asAbsolutePath(join(bundleDir, `bundle.l10n.${firstLanguagePart}.json`))), - importJSON(context.asAbsolutePath(join(bundleDir, `bundle.l10n.${env.language}.json`))), - ] : []))), + contents: await getLocalizationContents(context, locale), }); } diff --git a/src/providers/SnapshotTreeDataProvider.ts b/src/providers/SnapshotTreeDataProvider.ts new file mode 100644 index 00000000..613339b1 --- /dev/null +++ b/src/providers/SnapshotTreeDataProvider.ts @@ -0,0 +1,70 @@ +import { t } from "@vscode/l10n"; +import { type ProviderResult, window } from "vscode"; +import { type ApiVscodeApp } from "../@types"; +import type ExtensionCore from "../core/extension"; +import EmptyAppListTreeItem from "../structures/EmptyAppListTreeItem"; +import SnapshotAppTreeItem from "../structures/SnapshotAppTreeItem"; +import { EMPTY_TREE_ITEM_ID, TreeViewIds } from "../utils/constants"; +import BaseTreeDataProvider from "./BaseTreeDataProvider"; + +type Item = SnapshotAppTreeItem + +export default class SnapshotTreeDataProvider extends BaseTreeDataProvider { + constructor(readonly core: ExtensionCore) { + super(core.context, TreeViewIds.discloudSnapshots); + } + + getChildren(element?: SnapshotAppTreeItem): ProviderResult { + if (element) { + return element.fetch(this.core).then(children => { + this.refresh(element); + return children; + }); + } + + return this.children.values().toArray(); + } + + refresh(data?: Item | Item[] | null) { + super.refresh(data); + } + + clear() { + this.children.dispose(); + this.refresh(); + } + + setRawApps(data: ApiVscodeApp[]) { + this.children.dispose(); + + if (!data.length) { + this.children.set(EMPTY_TREE_ITEM_ID, new EmptyAppListTreeItem() as Item); + this.refresh(); + return; + } + + for (const app of data) { + this.children.set(app.id, SnapshotAppTreeItem.fromApp(app)); + } + + this.refresh(); + } + + async fetch() { + await window.withProgress({ + location: { viewId: this.viewId }, + title: t("refreshing"), + }, async () => { + this.core.statusBar.setLoading(); + await this.core.user.fetch(true); + this.core.statusBar.reset(); + }); + } + + async refreshApp(appId: string) { + const item = this.children.get(appId); + if (!item) return; + await item.fetch(this.core, true); + this.refresh(item); + } +} diff --git a/src/structures/BaseChildTreeItem.ts b/src/structures/BaseChildTreeItem.ts index c37ce5af..ca2d83bc 100644 --- a/src/structures/BaseChildTreeItem.ts +++ b/src/structures/BaseChildTreeItem.ts @@ -2,7 +2,7 @@ import { type Disposable, TreeItem, type TreeItemCollapsibleState, type TreeItem import { type BaseChildTreeItemData } from "../@types"; export default abstract class BaseChildTreeItem extends TreeItem implements Disposable { - readonly contextKey = "ChildTreeItem"; + readonly contextKey: string = "ChildTreeItem"; contextValue = this.contextKey; constructor(label: string | TreeItemLabel, collapsibleState?: TreeItemCollapsibleState) { diff --git a/src/structures/SnapshotAppTreeItem.ts b/src/structures/SnapshotAppTreeItem.ts new file mode 100644 index 00000000..78111697 --- /dev/null +++ b/src/structures/SnapshotAppTreeItem.ts @@ -0,0 +1,143 @@ +import path from "path"; +import { type AppType } from "../@enum"; +import { + type ApiVscodeApp, + type RESTGetApiSnapshotVersionsResult, + type SnapshotAppTreeItemData, +} from "../@types"; +import type ExtensionCore from "../core/extension"; +import DiscloudAPIError from "../services/discloud/errors/api"; +import BaseTreeItem from "./BaseTreeItem"; +import SnapshotInfoTreeItem from "./SnapshotInfoTreeItem"; +import SnapshotVersionTreeItem from "./SnapshotVersionTreeItem"; +import { t } from "@vscode/l10n"; +import { ThemeIcon, TreeItemCollapsibleState, Uri } from "vscode"; + +function getAppSnapshotLabel(app: Partial) { + return app.type === 0 && app.name + ? `${app.name} (${app.id})` + : (app.id ?? app.name ?? t("loading")); +} + +export default class SnapshotAppTreeItem extends BaseTreeItem< + SnapshotVersionTreeItem | SnapshotInfoTreeItem +> { + readonly contextKey = "SnapshotAppTreeItem"; + readonly appId: string; + declare readonly type: AppType | undefined; + #loaded = false; + + constructor(readonly data: SnapshotAppTreeItemData) { + super( + data.label, + data.collapsibleState ?? TreeItemCollapsibleState.Collapsed, + ); + + this.appId = data.appId; + this._patch(data); + } + + get contextJSON() { + return { + appId: this.appId, + type: this.type ?? null, + }; + } + + async fetch(core: ExtensionCore, force = false) { + if (this.#loaded && !force) return this.children.values().toArray(); + + this.children.dispose(); + + try { + const response = + await core.api.queueGet( + `/snapshot/${this.appId}`, + ); + const versions = response?.versions ?? []; + + if (!versions.length) { + this.children.set( + "empty", + new SnapshotInfoTreeItem(t("no.snapshot.found")), + ); + } else { + for (const version of versions) { + this.children.set( + version.version, + new SnapshotVersionTreeItem({ + appId: this.appId, + command: { + arguments: [this.appId, version.version], + command: "discloud.snapshot.download", + title: t("command.snapshot.download"), + }, + date: version.date, + label: version.version, + size: version.size, + version: version.version, + }), + ); + } + } + + this.#loaded = true; + this.description = `${versions.length}`; + } catch (error) { + if (error instanceof DiscloudAPIError && error.code === 404) { + this.children.set( + "empty", + new SnapshotInfoTreeItem(t("no.snapshot.found")), + ); + this.#loaded = true; + this.description = "0"; + } else { + throw error; + } + } + + return this.children.values().toArray(); + } + + private getTypeIcon() { + if (this.type === 1) { + return new ThemeIcon("globe"); + } + + return { + light: Uri.file(path.join(__dirname, "../resources/light/bot.svg")), + dark: Uri.file(path.join(__dirname, "../resources/dark/bot.svg")), + }; + } + _patch(data: Partial) { + if (!data) return this; + + super._patch(data); + + if (data.type !== undefined) + Object.defineProperty(this, "type", { + value: data.type, + configurable: true, + }); + + this.label = data.label ?? this.label; + this.description = + data.snapshotCount !== undefined + ? `${data.snapshotCount}` + : (this.description ?? data.description); + this.tooltip = data.tooltip ?? `${this.label}`; + this.iconPath = this.getTypeIcon(); + this.contextValue = `${this.contextKey}.${JSON.stringify(this.contextJSON)}`; + + return this; + } + + static fromApp(app: ApiVscodeApp) { + return new SnapshotAppTreeItem({ + appId: app.id, + description: t("view.snapshot.title"), + label: getAppSnapshotLabel(app), + type: app.type, + }); + } +} \ No newline at end of file diff --git a/src/structures/SnapshotInfoTreeItem.ts b/src/structures/SnapshotInfoTreeItem.ts new file mode 100644 index 00000000..68dae756 --- /dev/null +++ b/src/structures/SnapshotInfoTreeItem.ts @@ -0,0 +1,15 @@ +import { ThemeIcon } from "vscode"; +import BaseChildTreeItem from "./BaseChildTreeItem"; + +export default class SnapshotInfoTreeItem extends BaseChildTreeItem { + readonly contextKey = "SnapshotInfoTreeItem"; + + constructor(label: string, description?: string) { + super(label); + this._patch({ + description, + iconPath: new ThemeIcon("info"), + label, + }); + } +} diff --git a/src/structures/SnapshotVersionTreeItem.ts b/src/structures/SnapshotVersionTreeItem.ts new file mode 100644 index 00000000..5d3be09b --- /dev/null +++ b/src/structures/SnapshotVersionTreeItem.ts @@ -0,0 +1,63 @@ +import bytes from "bytes"; +import { t } from "@vscode/l10n"; +import { ThemeIcon } from "vscode"; +import { type SnapshotVersionTreeItemData } from "../@types"; +import BaseChildTreeItem from "./BaseChildTreeItem"; + +function formatSnapshotDate(value?: number | string) { + if (typeof value === "number" || typeof value === "string") { + const date = new Date(value); + if (!Number.isNaN(date.valueOf())) return date.toLocaleString(); + } + + return value ? `${value}` : undefined; +} + +function formatSnapshotSize(value?: number | string) { + if (typeof value === "number") + return bytes.format(value, { unitSeparator: " " }) ?? `${value} B`; + + return value ? `${value}` : undefined; +} + +export default class SnapshotVersionTreeItem extends BaseChildTreeItem { + readonly contextKey = "SnapshotVersionTreeItem"; + readonly appId: string; + declare readonly version: string; + + constructor(readonly data: SnapshotVersionTreeItemData) { + super(data.label ?? data.version, data.collapsibleState); + + this.appId = data.appId; + this.version = data.version; + + this._patch(data); + } + + get contextJSON() { + return { + appId: this.appId, + version: this.version, + }; + } + + _patch(data: Partial) { + if (!data) return this; + + super._patch(data); + + if (data.version !== undefined) + Object.defineProperty(this, "version", { value: data.version, configurable: true }); + + this.label = data.version ?? this.label; + this.description = formatSnapshotSize(data.size) ?? this.description; + this.tooltip = [ + `${t("snapshot.version")}: ${this.label}`, + formatSnapshotDate(data.date) ? `${t("snapshot.created.at")}: ${formatSnapshotDate(data.date)}` : null, + this.description ? `${t("snapshot.size")}: ${this.description}` : null, + ].filter(Boolean).join("\n"); + this.iconPath = new ThemeIcon("history"); + + return this; + } +} diff --git a/src/structures/SubDomainTreeItem.ts b/src/structures/SubDomainTreeItem.ts index 143b3ae9..6c80e5ab 100644 --- a/src/structures/SubDomainTreeItem.ts +++ b/src/structures/SubDomainTreeItem.ts @@ -6,6 +6,7 @@ import { getIconName, getIconPath } from "../utils/utils"; import BaseTreeItem from "./BaseTreeItem"; export default class SubDomainTreeItem extends BaseTreeItem { + readonly contextKey = "SubDomainTreeItem"; declare subdomain: string; declare iconName: string; @@ -31,6 +32,7 @@ export default class SubDomainTreeItem extends BaseTreeItem { this.iconPath = getIconPath(this.iconName); this.tooltip = t(`app.status.${this.iconName}`) + " - " + this.label; + this.contextValue = this.contextKey; this.collapsibleState = this.children.size ? diff --git a/src/structures/UserAppTreeItem.ts b/src/structures/UserAppTreeItem.ts index 40dd0ce6..a620d7c9 100644 --- a/src/structures/UserAppTreeItem.ts +++ b/src/structures/UserAppTreeItem.ts @@ -1,7 +1,7 @@ import { type ApiStatusApp } from "@discloudapp/api-types/v2"; import { calculatePercentage } from "@discloudapp/util"; import { t } from "@vscode/l10n"; -import { type LogOutputChannel, TreeItemCollapsibleState, Uri } from "vscode"; +import { type LogOutputChannel, ThemeIcon, TreeItemCollapsibleState, Uri } from "vscode"; import { AppType } from "../@enum"; import { type ApiVscodeApp, type UserAppChildTreeItemData, type UserAppTreeItemData } from "../@types"; import core from "../extension"; @@ -104,6 +104,7 @@ export default class UserAppTreeItem extends BaseTreeItem label: data.clusterName, description: t("cluster"), iconName: "container", + iconPath: new ThemeIcon("server"), }); if (data.memory) diff --git a/src/structures/UserAppTypeTreeItemView.ts b/src/structures/UserAppTypeTreeItemView.ts index b2be9239..25f9dd15 100644 --- a/src/structures/UserAppTypeTreeItemView.ts +++ b/src/structures/UserAppTypeTreeItemView.ts @@ -1,17 +1,31 @@ import { t } from "@vscode/l10n"; -import { TreeItemCollapsibleState } from "vscode"; +import { ThemeIcon, TreeItemCollapsibleState, Uri } from "vscode"; import { AppType } from "../@enum"; import BaseTreeItem from "./BaseTreeItem"; import type UserAppTreeItem from "./UserAppTreeItem"; +import path from "path"; export default class AppTypeTreeItemView extends BaseTreeItem { constructor(readonly type: AppType) { super(t(AppType[type]), TreeItemCollapsibleState.Expanded); this.contextValue = this.contextKey; + this.iconPath = this.getTypeIcon(); + this.refresh(); } readonly contextKey = "TreeView"; + private getTypeIcon() { + if (this.type === AppType.site) { + return new ThemeIcon("globe"); + } + + return { + light: Uri.file(path.join(__dirname, "../resources/light/bot.svg")), + dark: Uri.file(path.join(__dirname, "../resources/dark/bot.svg")), + }; + } + dispose(): void; dispose(key: string): boolean; dispose(key?: string) { @@ -24,7 +38,9 @@ export default class AppTypeTreeItemView extends BaseTreeItem { } refresh() { - this.label = `${t(AppType[this.type])} (${this.children.size})`; + this.label = t(AppType[this.type]); + this.description = `${this.children.size}`; + this.iconPath = this.getTypeIcon(); } set(key: string, app: UserAppTreeItem) { diff --git a/src/structures/UserTreeItem.ts b/src/structures/UserTreeItem.ts index 23f1f988..62afcb6e 100644 --- a/src/structures/UserTreeItem.ts +++ b/src/structures/UserTreeItem.ts @@ -1,9 +1,55 @@ import { t } from "@vscode/l10n"; -import { TreeItemCollapsibleState, Uri } from "vscode"; +import { ThemeIcon, TreeItemCollapsibleState, Uri } from "vscode"; import { type ApiVscodeUser, type UserTreeItemData } from "../@types"; +import { canAccessCustomDomains, canAccessSubdomains, formatPlanLabel, getPlanIconPath } from "../utils/plans"; +import { getIconPath, getThemedResourceIconPath } from "../utils/utils"; import BaseTreeItem from "./BaseTreeItem"; import UserChildTreeItem from "./UserChildTreeItem"; +function getUserFallbackIconPath() { + return getThemedResourceIconPath( + "resources/icons/discloud_white_icon.svg", + "resources/icons/discloud_white_icon.svg", + ); +} + +function formatRamValue(value: number, locale?: string) { + return `${new Intl.NumberFormat(locale || "pt-BR").format(value)} MB`; +} + +function capitalizeFirstLetter(value: string) { + return value ? value.charAt(0).toUpperCase() + value.slice(1) : value; +} + +function formatLocaleLabel(locale: string) { + const normalizedLocale = locale.replace("_", "-"); + const [languageCode = normalizedLocale, regionCode] = normalizedLocale.split("-"); + + try { + const languageLabel = new Intl.DisplayNames([normalizedLocale], { type: "language" }).of(languageCode); + + if (!languageLabel) return locale; + + return regionCode + ? `${capitalizeFirstLetter(languageLabel)} ${regionCode.toUpperCase()}` + : capitalizeFirstLetter(languageLabel); + } catch { + return locale; + } +} + +function getUserDetailsIcons() { + return { + apps: getIconPath("container"), + domains: new ThemeIcon("globe"), + locale: new ThemeIcon("globe"), + planDataEnd: new ThemeIcon("calendar"), + ram: getIconPath("ram"), + subdomains: new ThemeIcon("link"), + team: new ThemeIcon("organization"), + }; +} + export default class UserTreeItem extends BaseTreeItem { iconName?: string; readonly userID: string; @@ -21,6 +67,10 @@ export default class UserTreeItem extends BaseTreeItem { protected _patch(data: Partial): this { if (!data) return this; + const userDetailsIcons = getUserDetailsIcons(); + + this.iconPath = getUserFallbackIconPath(); + if (data.avatar) try { this.iconPath = Uri.parse(data.avatar); } catch { } @@ -37,15 +87,17 @@ export default class UserTreeItem extends BaseTreeItem { if (typeof data.ramUsedMb === "number" && typeof data.totalRamMb === "number") this._addChild("ram", { - label: `${data.ramUsedMb}/${data.totalRamMb}`, + label: `${formatRamValue(data.ramUsedMb, data.locale)}/${formatRamValue(data.totalRamMb, data.locale)}`, description: t("label.available.ram"), + iconPath: userDetailsIcons.ram, userID: this.userID, }); if (data.plan) this._addChild("plan", { - label: data.plan, + label: formatPlanLabel(data.plan), description: t("plan"), + iconPath: getPlanIconPath(data.plan), userID: this.userID, }); @@ -55,13 +107,15 @@ export default class UserTreeItem extends BaseTreeItem { new Date(data.planDataEnd).toLocaleDateString() : data.planDataEnd, description: t("label.plan.expiration"), + iconPath: userDetailsIcons.planDataEnd, userID: this.userID, }); if (data.locale) this._addChild("locale", { - label: data.locale, + label: formatLocaleLabel(data.locale), description: t("locale"), + iconPath: userDetailsIcons.locale, userID: this.userID, }); @@ -69,6 +123,7 @@ export default class UserTreeItem extends BaseTreeItem { this._addChild("apps", { label: `${data.apps.length}`, description: t("label.apps.amount"), + iconPath: userDetailsIcons.apps, userID: this.userID, }); @@ -76,22 +131,29 @@ export default class UserTreeItem extends BaseTreeItem { this._addChild("team", { label: `${data.appsTeam.length}`, description: t("label.team.apps.amount"), + iconPath: userDetailsIcons.team, userID: this.userID, }); - if (data.customdomains) + if (data.plan && data.customdomains && canAccessCustomDomains(data.plan)) this._addChild("domains", { label: `${data.customdomains.length}`, description: t("label.domains.amount"), + iconPath: userDetailsIcons.domains, userID: this.userID, }); + else + this.children.delete("domains"); - if (data.subdomains) + if (data.plan && data.subdomains && canAccessSubdomains(data.plan)) this._addChild("subdomains", { label: `${data.subdomains.length}`, description: t("label.subdomains.amount"), + iconPath: userDetailsIcons.subdomains, userID: this.userID, }); + else + this.children.delete("subdomains"); this.collapsibleState = this.children.size ? diff --git a/src/structures/VSUser.ts b/src/structures/VSUser.ts index dc5b29fc..372c773b 100644 --- a/src/structures/VSUser.ts +++ b/src/structures/VSUser.ts @@ -12,7 +12,7 @@ export default class VSUser implements ApiVscodeUser { declare avatar: string | null; declare locale: string; declare readonly plan: string; - declare readonly planDataEnd: string; + declare readonly planDataEnd: string | null | undefined; declare readonly ramUsedMb: number; declare readonly totalRamMb: number; declare readonly userID: string; @@ -67,8 +67,11 @@ export default class VSUser implements ApiVscodeUser { const response = await core.api.put(Routes.locale(locale)); if (!response) return null; - if ("locale" in response) + if ("locale" in response) { this.locale = response.locale; + await core.globalStorage.update("user", this); + core.emit("vscode", this); + } return "body" in response ? response.body : diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 685baaa3..d44940ed 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -57,6 +57,7 @@ const CONFIG_KEYS = Object.freeze([ const TREE_VIEW_IDS = Object.freeze([ "discloudUserApps", "discloudTeamApps", + "discloudSnapshots", "discloudSubdomains", "discloudDomains", "discloudUser", diff --git a/src/utils/plans.ts b/src/utils/plans.ts new file mode 100644 index 00000000..b960a45e --- /dev/null +++ b/src/utils/plans.ts @@ -0,0 +1,75 @@ +import { existsSync } from "fs"; +import { join } from "path"; +import { type TreeItem, Uri } from "vscode"; +import core from "../extension"; +import { RESOURCES_DIR } from "./constants"; + +interface PlanDefinition { + aliases: string[] + iconName: string + label: string + level: number +} + +const PLAN_DEFINITIONS: PlanDefinition[] = [ + { aliases: ["free", "gratis", "gratuito"], iconName: "free", label: "Free", level: 0 }, + { aliases: ["carbon", "carbono"], iconName: "carbon", label: "Carbon", level: 1 }, + { aliases: ["gold", "ouro"], iconName: "gold", label: "Gold", level: 2 }, + { aliases: ["platinum", "platina"], iconName: "platinum", label: "Platinum", level: 3 }, + { aliases: ["diamond", "diamante"], iconName: "diamond", label: "Diamond", level: 4 }, + { aliases: ["ruby", "rubi"], iconName: "ruby", label: "Ruby", level: 5 }, + { aliases: ["sapphire", "safira"], iconName: "sapphire", label: "Sapphire", level: 6 }, + { aliases: ["krypton", "cripton", "kryptonita", "criptonita"], iconName: "krypton", label: "Krypton", level: 7 }, + { aliases: ["vibranium"], iconName: "vibranium", label: "Vibranium", level: 8 }, +]; + +function normalizePlanValue(plan: string) { + return plan + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .toLowerCase() + .replace(/[^a-z]/g, ""); +} + +function getPlanDefinition(plan: string) { + const normalizedPlan = normalizePlanValue(plan); + + if (!normalizedPlan) return null; + + return PLAN_DEFINITIONS.find(({ aliases }) => + aliases.some(alias => normalizedPlan === alias || normalizedPlan.includes(alias)), + ) ?? null; +} + +export function formatPlanLabel(plan: string) { + return plan; +} + +export function canAccessSubdomains(plan?: string | null) { + const planLevel = plan ? (getPlanDefinition(plan)?.level ?? -1) : -1; + return planLevel >= 3; +} + +export function canAccessCustomDomains(plan?: string | null) { + const planLevel = plan ? (getPlanDefinition(plan)?.level ?? -1) : -1; + return planLevel >= 4; +} + +export function getPlanIconPath(plan: string): TreeItem["iconPath"] | undefined { + const iconName = getPlanDefinition(plan)?.iconName; + + if (!iconName) return undefined; + + const iconPath = ["png", "svg"] + .map(ext => core.context.asAbsolutePath(join(RESOURCES_DIR, "icons", `${iconName}.${ext}`))) + .find(candidate => existsSync(candidate)); + + if (!iconPath) return undefined; + + const iconUri = Uri.file(iconPath); + + return { + dark: iconUri, + light: iconUri, + }; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index ee9208db..879d59ee 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -11,6 +11,17 @@ export function getIconPath(iconName: string, iconExt = "svg"): TreeItem["iconPa }; } +export function getResourceUri(...pathSegments: string[]) { + return Uri.file(core.context.asAbsolutePath(join(...pathSegments))); +} + +export function getThemedResourceIconPath(lightPath: string, darkPath = lightPath): TreeItem["iconPath"] { + return { + dark: getResourceUri(darkPath), + light: getResourceUri(lightPath), + }; +} + export function compareBooleans(a: boolean, b: boolean) { let i = 0; if (a) i--; From 61cbd827799a7fe0bd939a9a1447f8c429a7c37a Mon Sep 17 00:00:00 2001 From: ThisPythonJS Date: Sat, 2 May 2026 07:04:52 -0300 Subject: [PATCH 02/22] feat: feat: add icons, snapshots, UI improvements and more --- CHANGELOG.md | 4 ++-- package.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7ff070d..ad1a66fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Seja Bem-Vindo a nossa página e atualização da Extensão da Discloud. Aqui vo --- -## 2.31.0 +## 2.29.7 - Adição de ícones na interface da extensão, presentes em praticamente todas as seções, incluindo Apps (ao lado de Bot e Site), User e Snapshots. - Correção de bugs no sistema de tradução, que anteriormente não aplicava grande parte dos textos. @@ -17,7 +17,7 @@ Seja Bem-Vindo a nossa página e atualização da Extensão da Discloud. Aqui vo - Visualização do plano com suporte a português/inglês, acompanhado de ícone - Identificação do idioma mais clara (ex: de pt-BR para Português (BR)) -## 2.30.0 +## 2.29.6 - Correção no sistema de autenticação, e orquestração de sessão. diff --git a/package.json b/package.json index 848adeef..b1a2b562 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Discloud", "description": "Somos uma plataforma de nuvem baseada em contêiner que nasceu com a vontade de oferecer hospedagem fácil, rápida, gratuita e de qualidade.", "publisher": "discloud", - "version": "2.29.5", + "version": "2.29.7", "engines": { "vscode": "^1.116.0" }, @@ -1405,8 +1405,8 @@ "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.5.2", "esbuild": "^0.28.0", - "eslint": "^10.2.1", - "globals": "^17.5.0", + "eslint": "^10.3.0", + "globals": "^17.6.0", "mocha": "^11.7.5", "npm-run-all": "^4.1.5", "typescript": "^5.9.3" From e2fdabf8c0464a35404f3e658efa3baa9b2130ef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 2 May 2026 10:05:23 +0000 Subject: [PATCH 03/22] style: fix linter issues --- src/authentication/pat/provider.ts | 8 +++--- yarn.lock | 41 ++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/authentication/pat/provider.ts b/src/authentication/pat/provider.ts index 191a0aa1..c44f9abc 100644 --- a/src/authentication/pat/provider.ts +++ b/src/authentication/pat/provider.ts @@ -31,7 +31,7 @@ const defaultSessionAccount: AuthenticationSessionAccountInformation = { }; export default class DiscloudPatAuthenticationProvider - implements IPatAuthenticationProvider, AuthenticationProvider +implements IPatAuthenticationProvider, AuthenticationProvider { constructor( protected readonly emitter: EventEmitter, @@ -255,9 +255,9 @@ export default class DiscloudPatAuthenticationProvider : Promise.resolve(), currentSessionId === sessionId ? this.storage.update( - GlobalStorageKeys.currentAutenticationProviderId, - undefined, - ) + GlobalStorageKeys.currentAutenticationProviderId, + undefined, + ) : Promise.resolve(), ]); diff --git a/yarn.lock b/yarn.lock index 9861ae21..481e3ba2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1135,10 +1135,10 @@ eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be" integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA== -eslint@^10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.2.1.tgz#224b2a6caeb34473eddcf918762363e2e063222a" - integrity sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q== +eslint@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.3.0.tgz#ed5b810eb8e0191bf24bddcf9cdb45b974e0a16d" + integrity sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw== dependencies: "@eslint-community/eslint-utils" "^4.8.0" "@eslint-community/regexpp" "^4.12.2" @@ -1404,10 +1404,10 @@ glob@^13.0.6: minipass "^7.1.3" path-scurry "^2.0.2" -globals@^17.5.0: - version "17.5.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-17.5.0.tgz#a82c641d898f8dfbe0e81f66fdff7d0de43f88c6" - integrity sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g== +globals@^17.6.0: + version "17.6.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-17.6.0.tgz#0f0be018d5cca8690e6375ead1f65c4bb96191fc" + integrity sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA== globalthis@^1.0.4: version "1.0.4" @@ -1557,6 +1557,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" @@ -2259,6 +2264,14 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== + dependencies: + process "^0.11.1" + util "^0.10.3" + picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" @@ -2299,6 +2312,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.1: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + punycode@^2.1.0, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -2955,6 +2973,13 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + v8-to-istanbul@^9.0.0: version "9.3.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" From 3d49e4090ac1e2837394b6732c1f8850a722d4ef Mon Sep 17 00:00:00 2001 From: ThisPythonJS Date: Sun, 3 May 2026 20:16:42 -0300 Subject: [PATCH 04/22] a --- yarn.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/yarn.lock b/yarn.lock index 481e3ba2..b5a868ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -369,10 +369,10 @@ dependencies: undici-types "~6.21.0" -"@types/vscode@^1.116.0": - version "1.116.0" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.116.0.tgz#88e90907200b5d2776a2ebfae5fb791833193d79" - integrity sha512-sYHp4MO6BqJ2PD7Hjt0hlIS3tMaYsVPJrd0RUjDJ8HtOYnyJIEej0bLSccM8rE77WrC+Xox/kdBwEFDO8MsxNA== +"@types/vscode@^1.118.0": + version "1.118.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.118.0.tgz#4a226ddf8faa11a9e6b338555431c4edd3230e4a" + integrity sha512-Ah6eTlqDcwIMELEVwQMO++rJAFBRz/oLluLD/vWdYrH1KuI9kfpaM+7pg0OvvascgcJy+ghLCERAYouM4QbzGw== "@types/ws@^8.18.1": version "8.18.1" @@ -529,9 +529,9 @@ agent-base@^7.1.0, agent-base@^7.1.2: integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== ajv@^6.14.0: - version "6.14.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.14.0.tgz#fd067713e228210636ebb08c60bd3765d6dbe73a" - integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw== + version "6.15.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.15.0.tgz#07e982c74626167aa7a2495c53817892d7139492" + integrity sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -958,12 +958,12 @@ emoji-regex@^9.2.2: integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== enhanced-resolve@^5.18.3: - version "5.20.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz#eeeb3966bea62c348c40a0cc9e7912e2557d0be0" - integrity sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA== + version "5.21.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.21.0.tgz#bb8e6fabaf74930de70e61397798750429e5b1ae" + integrity sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA== dependencies: graceful-fs "^4.2.4" - tapable "^2.3.0" + tapable "^2.3.3" error-ex@^1.3.1: version "1.3.4" @@ -2803,7 +2803,7 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -tapable@^2.3.0: +tapable@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.3.tgz#5da7c9992c46038221267985ab28421a8879f160" integrity sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A== @@ -3160,6 +3160,6 @@ zod-validation-error@^5.0.0: integrity sha512-hmk+pkyKq7Q71PiWVSDUc3VfpzpvcRHZ3QPw9yEMVvmtCekaMeOHnbr3WbxfrgEnQTv6haGP4cmv0Ojmihzsxw== zod@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.6.tgz#89c56e0aa7d2b05107d894412227087885ab112a" - integrity sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg== + version "4.4.2" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.4.2.tgz#5e53a8c23fc7050b9960d441002e9c9fca33c99e" + integrity sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw== From 688979f199f69f45d2791d2c7212d7384a990e82 Mon Sep 17 00:00:00 2001 From: ThisPythonJS Date: Sun, 3 May 2026 20:20:58 -0300 Subject: [PATCH 05/22] =?UTF-8?q?chore:=20mudan=C3=A7a=20no=20action.title?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n/bundle.l10n.json | 2 +- l10n/bundle.l10n.pt.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index bbce7d90..b62e7279 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -2,7 +2,7 @@ "action.cancel": "Cancel", "action.cancelled": "Action cancelled", "action.ok": "Yes", - "action.title": "Are you sure that you want to do {action}?", + "action.title": "Are you sure you want to perform this action?", "app.status.errorCode": "Code error", "app.status.off": "Off", "app.status.on": "On", diff --git a/l10n/bundle.l10n.pt.json b/l10n/bundle.l10n.pt.json index 0f4365f4..206ffc8f 100644 --- a/l10n/bundle.l10n.pt.json +++ b/l10n/bundle.l10n.pt.json @@ -2,7 +2,7 @@ "action.cancel": "Cancelar", "action.cancelled": "Ação cancelada", "action.ok": "Ok", - "action.title": "Are you sure you want to perform this action?", + "action.title": "Você tem certeza que quer fazer essa ação?", "app.status.errorCode": "Erro de código", "app.status.off": "Desligado", "app.status.on": "Ligado", From 58ce6ee84f6958ce88f85685e64c3b6ff0d79e40 Mon Sep 17 00:00:00 2001 From: ThisPythonJS Date: Sat, 30 May 2026 13:10:35 -0300 Subject: [PATCH 06/22] feat: improve dashboard experience and localization --- CHANGELOG.md | 3 +- discloudconfigschema.json | 3 + l10n/bundle.l10n.json | 8 -- l10n/bundle.l10n.pt.json | 10 +- package.json | 51 ++------ package.nls.json | 4 - package.nls.pt.json | 4 - src/@types/api.ts | 39 +----- src/@types/structures.ts | 15 --- src/commands.ts | 7 +- src/commands/snapshot/create.ts | 29 ----- src/commands/snapshot/download.ts | 29 ----- src/commands/snapshot/refresh.ts | 12 -- src/core/extension.ts | 4 - src/events/missingToken.ts | 2 +- src/events/unauthorized.ts | 1 - src/events/vscode.ts | 3 - src/providers/SnapshotTreeDataProvider.ts | 70 ----------- src/structures/SnapshotAppTreeItem.ts | 143 ---------------------- src/structures/SnapshotInfoTreeItem.ts | 15 --- src/structures/SnapshotVersionTreeItem.ts | 63 ---------- 21 files changed, 15 insertions(+), 500 deletions(-) delete mode 100644 src/commands/snapshot/create.ts delete mode 100644 src/commands/snapshot/download.ts delete mode 100644 src/commands/snapshot/refresh.ts delete mode 100644 src/providers/SnapshotTreeDataProvider.ts delete mode 100644 src/structures/SnapshotAppTreeItem.ts delete mode 100644 src/structures/SnapshotInfoTreeItem.ts delete mode 100644 src/structures/SnapshotVersionTreeItem.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index ad1a66fa..997590a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,8 @@ Seja Bem-Vindo a nossa página e atualização da Extensão da Discloud. Aqui vo ## 2.29.7 -- Adição de ícones na interface da extensão, presentes em praticamente todas as seções, incluindo Apps (ao lado de Bot e Site), User e Snapshots. +- Adição de ícones na interface da extensão, presentes em praticamente todas as seções, incluindo Apps (ao lado de Bot e Site), User. - Correção de bugs no sistema de tradução, que anteriormente não aplicava grande parte dos textos. -- Implementação do novo sistema de Snapshots da Discloud: agora é possível selecionar seu app, visualizar os snapshots disponíveis e salvá-los diretamente no seu computador. - Melhoria no gerenciamento de subdomínios, permitindo criar e deletar diretamente pela extensão, sem precisar acessar o dashboard. - Atualizações na interface de User: - Exibição da RAM em MB de forma mais organizada diff --git a/discloudconfigschema.json b/discloudconfigschema.json index 8eb9538b..0871f744 100644 --- a/discloudconfigschema.json +++ b/discloudconfigschema.json @@ -12,8 +12,11 @@ "ffmpeg", "java", "libgl", + "mysql", "openssl", "puppeteer", + "selenium", + "tesseract", "tools" ] } diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index b62e7279..3fa7a301 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -68,7 +68,6 @@ "invalid.token": "Invalid token.", "label.user": "User", "label.customdomain": "Custom Domains", - "label.snapshot": "Snapshot", "label.teamapps": "Team Apps", "label.subdomain": "Subdomains", "label.apps.amount": "Amount of Apps", @@ -88,7 +87,6 @@ "missing.discloud.config.main": "The {file} file was not found in the list to ZIP.", "missing.input": "Missing input", "missing.locale": "Missing locale", - "missing.snapshot.version": "Missing snapshot version", "missing.subdomain": "Missing subdomain", "missing.moderator": "Missing mod", "missing.moderator.id": "Missing mod ID", @@ -100,7 +98,6 @@ "no.app.found": "No app found.", "no.apps.found.to.choose": "No apps found, please upload before that.", "no.backup.found": "No backup found", - "no.snapshot.found": "No snapshots found.", "no.folder.found": "No folder found", "no.log.found": "No log found", "no.workspace.folder.found": "No workspace folder found", @@ -133,8 +130,6 @@ "progress.mod.rem.title": "Remove MOD", "progress.ram.title": "RAM", "progress.restart.title": "Restart", - "progress.snapshot.create.title": "Create snapshot", - "progress.snapshot.download.title": "Download snapshot", "progress.start.title": "Start", "progress.status.title": "Status", "progress.stop.title": "Stop", @@ -146,9 +141,6 @@ "readdocs": "Read the [documentation](https://docs.discloud.com/en).", "refreshing": "Refreshing...", "rejected.action": "Rejected action", - "snapshot.created.at": "Created at", - "snapshot.size": "Size", - "snapshot.version": "Version", "see.also.your.apps": "See also your apps", "see.also.your.n.apps": "See also your {n} apps", "see.also.your.n.team.apps": "See also the {n} apps of their teams", diff --git a/l10n/bundle.l10n.pt.json b/l10n/bundle.l10n.pt.json index 206ffc8f..217bc013 100644 --- a/l10n/bundle.l10n.pt.json +++ b/l10n/bundle.l10n.pt.json @@ -2,7 +2,7 @@ "action.cancel": "Cancelar", "action.cancelled": "Ação cancelada", "action.ok": "Ok", - "action.title": "Você tem certeza que quer fazer essa ação?", + "action.title": "Tem certeza de que deseja realizar esta ação?", "app.status.errorCode": "Erro de código", "app.status.off": "Desligado", "app.status.on": "Ligado", @@ -62,23 +62,15 @@ "input.set.locale.validate": "Idioma deve ser como pt-BR.", "input.subdomain.prompt": "Digite o nome do subdominio.", "input.subdomain.validate": "O subdominio deve usar 2-20 letras minusculas, numeros ou hifens.", - "missing.snapshot.version": "Versao do snapshot nao encontrada", "missing.subdomain": "Subdominio nao encontrado", - "no.snapshot.found": "Nenhum snapshot encontrado.", - "progress.snapshot.create.title": "Criar snapshot", - "progress.snapshot.download.title": "Baixar snapshot", "progress.subdomain.create.title": "Criar subdominio", "progress.subdomain.delete.title": "Remover subdominio", - "snapshot.created.at": "Criado em", - "snapshot.size": "Tamanho", - "snapshot.version": "Versao", "invalid.discloud.config": "O arquivo discloud.config é inválido ou não existe.", "invalid.discloud.config.main": "O arquivo {file} especificado no escopo principal não existe.", "invalid.input": "Entrada inválida", "invalid.token": "Token inválido.", "label.user": "Usuário", "label.customdomain": "Domínios Customizados", - "label.snapshot": "Snapshot", "label.teamapps": "Apps de Equipe", "label.subdomain": "Subdomínios", "label.apps.amount": "Quant. de apps", diff --git a/package.json b/package.json index b1a2b562..cf1933ee 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,13 @@ "discloud.app", "discloudbot", "discord", - "host" + "host", + "hospedagem", + "host free", + "discloud.com", + "discloudbot.com", + "hosting", + "discord" ], "categories": [ "Other" @@ -254,21 +260,6 @@ "title": "%command.subdomain.delete%", "icon": "$(trash)" }, - { - "command": "discloud.snapshot.refresh", - "title": "%command.snapshot.refresh%", - "icon": "$(refresh)" - }, - { - "command": "discloud.snapshot.download", - "title": "%command.snapshot.download%", - "icon": "$(cloud-download)" - }, - { - "command": "discloud.snapshot.create", - "title": "%command.snapshot.create%", - "icon": "$(history)" - }, { "command": "discloud.team.backup", "title": "%command.team.backup%", @@ -1035,21 +1026,6 @@ "group": "inline", "when": "view == discloudSubdomains && viewItem =~ /^SubDomainTreeItem/" }, - { - "command": "discloud.snapshot.create", - "group": "1", - "when": "view == discloudUserApps && discloudAppLength && viewItem =~ /^TreeItem/" - }, - { - "command": "discloud.snapshot.create", - "group": "1", - "when": "view == discloudSnapshots && viewItem =~ /^SnapshotAppTreeItem/" - }, - { - "command": "discloud.snapshot.download", - "group": "inline", - "when": "view == discloudSnapshots && viewItem =~ /^SnapshotVersionTreeItem/" - }, { "command": "discloud.logout", "group": "inline", @@ -1098,11 +1074,6 @@ "when": "view == discloudSubdomains", "group": "navigation" }, - { - "command": "discloud.snapshot.refresh", - "when": "view == discloudSnapshots && discloudAuthorized", - "group": "navigation" - }, { "command": "discloud.team.refresh", "when": "view == discloudTeamApps", @@ -1286,14 +1257,6 @@ "visibility": "collapsed", "when": "discloudAuthorized" }, - { - "type": "tree", - "id": "discloudSnapshots", - "icon": "resources/icons/discloud_white_icon.svg", - "name": "%view.snapshot.title%", - "visibility": "collapsed", - "when": "discloudAuthorized" - }, { "type": "tree", "id": "discloudSubdomains", diff --git a/package.nls.json b/package.nls.json index d3ee3ec0..c354dd17 100644 --- a/package.nls.json +++ b/package.nls.json @@ -25,9 +25,6 @@ "command.login": "Login Discloud", "command.logout": "Logout Discloud", "command.logs": "Get app logs", - "command.snapshot.create": "Create snapshot", - "command.snapshot.download": "Download snapshot", - "command.snapshot.refresh": "Refresh snapshot list", "command.subdomain.create": "Create subdomain", "command.subdomain.delete": "Delete subdomain", "command.subdomain.refresh": "Refresh subdomain list", @@ -105,7 +102,6 @@ "submenu.team.sort.by": "Sort team apps by", "view.apps.title": "Apps", "view.domain.title": "Custom domains", - "view.snapshot.title": "Snapshots", "view.subdomain.title": "Subdomains", "view.team.title": "Team apps", "view.user.title": "User", diff --git a/package.nls.pt.json b/package.nls.pt.json index eb5034f0..7ab42076 100644 --- a/package.nls.pt.json +++ b/package.nls.pt.json @@ -25,9 +25,6 @@ "command.login": "Login Discloud", "command.logout": "Logout Discloud", "command.logs": "Obter logs do app", - "command.snapshot.create": "Criar snapshot", - "command.snapshot.download": "Baixar snapshot", - "command.snapshot.refresh": "Atualizar lista de snapshots", "command.subdomain.create": "Criar subdominio", "command.subdomain.delete": "Remover subdominio", "command.subdomain.refresh": "Atualizar lista de subdomínios", @@ -104,7 +101,6 @@ "submenu.manage.mods": "Gerenciar equipe", "submenu.team.sort.by": "Ordenar apps de equipe por", "view.apps.title": "Apps", - "view.snapshot.title": "Snapshots", "view.domain.title": "Domínios personalizados", "view.subdomain.title": "Subdomínios", "view.team.title": "Apps de equipe", diff --git a/src/@types/api.ts b/src/@types/api.ts index d5311029..dfa2ed1d 100644 --- a/src/@types/api.ts +++ b/src/@types/api.ts @@ -52,41 +52,4 @@ export interface RESTPostApiSubdomainResult extends RESTApiBaseResult { subdomain?: ApiSubdomain } -export interface RESTDeleteApiSubdomainResult extends RESTApiBaseResult {} - -export interface ApiSnapshotVersion { - date: number | string - size: number | string - version: string -} - -export interface RESTGetApiSnapshotVersionsResult extends RESTApiBaseResult { - app?: { - id: string - } - versions?: ApiSnapshotVersion[] -} - -export interface RESTGetApiSnapshotDownloadResult extends RESTApiBaseResult { - app?: { - id: string - } - download?: { - expiresAt: string - size: number - url: string - version: string - } -} - -export interface RESTPostApiSnapshotResult extends RESTApiBaseResult { - app?: { - id: string - } - snapshot?: { - allVersions?: ApiSnapshotVersion[] - size?: number | string - url?: string - version: string - } -} +export interface RESTDeleteApiSubdomainResult extends RESTApiBaseResult {} \ No newline at end of file diff --git a/src/@types/structures.ts b/src/@types/structures.ts index 5137bdc5..5cb8dba4 100644 --- a/src/@types/structures.ts +++ b/src/@types/structures.ts @@ -88,21 +88,6 @@ export interface UserTreeItemData extends BaseTreeItemData { tooltip?: string } -export interface SnapshotAppTreeItemData extends BaseTreeItemData { - appId: string - appName?: string - description?: string - snapshotCount?: number - type?: number -} - -export interface SnapshotVersionTreeItemData extends BaseChildTreeItemData { - appId: string - version: string - date?: number | string - size?: number | string -} - export interface Events { activate: [context: ExtensionContext] appUpdate: [oldApp: UserAppTreeItem, newApp: UserAppTreeItem] diff --git a/src/commands.ts b/src/commands.ts index 2a5570ff..e5ef08b5 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -65,12 +65,7 @@ export async function commandsRegister(core: ExtensionCore) { commandModuleRegister(core, "subdomain/create", await import("./commands/subdomain/create")); commandModuleRegister(core, "subdomain/delete", await import("./commands/subdomain/delete")); commandModuleRegister(core, "subdomain/refresh", await import("./commands/subdomain/refresh")); - - // snapshot - commandModuleRegister(core, "snapshot/create", await import("./commands/snapshot/create")); - commandModuleRegister(core, "snapshot/download", await import("./commands/snapshot/download")); - commandModuleRegister(core, "snapshot/refresh", await import("./commands/snapshot/refresh")); - + // team commandModuleRegister(core, "team/backup", await import("./commands/team/backup")); commandModuleRegister(core, "team/commit", await import("./commands/team/commit")); diff --git a/src/commands/snapshot/create.ts b/src/commands/snapshot/create.ts deleted file mode 100644 index ee9caaef..00000000 --- a/src/commands/snapshot/create.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { t } from "@vscode/l10n"; -import { ProgressLocation, window } from "vscode"; -import { type RESTPostApiSnapshotResult, type TaskData } from "../../@types"; -import type ExtensionCore from "../../core/extension"; -import Command from "../../structures/Command"; -import type SnapshotAppTreeItem from "../../structures/SnapshotAppTreeItem"; -import type UserAppTreeItem from "../../structures/UserAppTreeItem"; - -type Item = Pick | Pick - -export default class extends Command { - constructor(core: ExtensionCore) { - super(core, { - progress: { - location: ProgressLocation.Notification, - title: t("progress.snapshot.create.title"), - }, - }); - } - - async run(_: TaskData, item: Item) { - const response = await this.core.api.post(`/snapshot/${item.appId}`); - if (!response) return; - - void window.showInformationMessage(response.message ?? t("done")); - - await this.core.snapshotTree.refreshApp(item.appId); - } -} diff --git a/src/commands/snapshot/download.ts b/src/commands/snapshot/download.ts deleted file mode 100644 index 5b157914..00000000 --- a/src/commands/snapshot/download.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { t } from "@vscode/l10n"; -import { env, ProgressLocation, Uri } from "vscode"; -import { type RESTGetApiSnapshotDownloadResult, type TaskData } from "../../@types"; -import type ExtensionCore from "../../core/extension"; -import Command from "../../structures/Command"; -import type SnapshotVersionTreeItem from "../../structures/SnapshotVersionTreeItem"; - -export default class extends Command { - constructor(core: ExtensionCore) { - super(core, { - progress: { - location: ProgressLocation.Notification, - title: t("progress.snapshot.download.title"), - }, - }); - } - - async run(_: TaskData, itemOrAppId: SnapshotVersionTreeItem | string, maybeVersion?: string) { - const appId = typeof itemOrAppId === "string" ? itemOrAppId : itemOrAppId.appId; - const version = typeof itemOrAppId === "string" ? maybeVersion : itemOrAppId.version; - - if (!version) throw Error(t("missing.snapshot.version")); - - const response = await this.core.api.get(`/snapshot/${appId}/versions/${version}`); - if (!response?.download?.url) return; - - await env.openExternal(Uri.parse(response.download.url)); - } -} diff --git a/src/commands/snapshot/refresh.ts b/src/commands/snapshot/refresh.ts deleted file mode 100644 index 723795bb..00000000 --- a/src/commands/snapshot/refresh.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type ExtensionCore from "../../core/extension"; -import Command from "../../structures/Command"; - -export default class extends Command { - constructor(core: ExtensionCore) { - super(core); - } - - async run() { - await this.core.snapshotTree.fetch(); - } -} diff --git a/src/core/extension.ts b/src/core/extension.ts index d980a05d..140defde 100644 --- a/src/core/extension.ts +++ b/src/core/extension.ts @@ -8,7 +8,6 @@ import { commandsRegister } from "../commands"; import { loadEvents } from "../events"; import DiscloudLogOutputChannel from "../output/LogOutputChannel"; import CustomDomainTreeDataProvider from "../providers/CustomDomainTreeDataProvider"; -import SnapshotTreeDataProvider from "../providers/SnapshotTreeDataProvider"; import SubDomainTreeDataProvider from "../providers/SubDomainTreeDataProvider"; import TeamAppTreeDataProvider from "../providers/TeamAppTreeDataProvider"; import UserAppTreeDataProvider from "../providers/UserAppTreeDataProvider"; @@ -40,7 +39,6 @@ export default class ExtensionCore extends EventEmitter implements Dispo declare readonly statusBar: DiscloudStatusBarItem; declare readonly customDomainTree: CustomDomainTreeDataProvider; - declare readonly snapshotTree: SnapshotTreeDataProvider; declare readonly subDomainTree: SubDomainTreeDataProvider; declare readonly teamAppTree: TeamAppTreeDataProvider; declare readonly userAppTree: UserAppTreeDataProvider; @@ -196,7 +194,6 @@ export default class ExtensionCore extends EventEmitter implements Dispo await commandsRegister(this); const customDomainTree = new CustomDomainTreeDataProvider(context); - const snapshotTree = new SnapshotTreeDataProvider(this); const subDomainTree = new SubDomainTreeDataProvider(context); const teamAppTree = new TeamAppTreeDataProvider(this); const userAppTree = new UserAppTreeDataProvider(this); @@ -204,7 +201,6 @@ export default class ExtensionCore extends EventEmitter implements Dispo Object.defineProperties(this, { customDomainTree: { value: customDomainTree }, - snapshotTree: { value: snapshotTree }, subDomainTree: { value: subDomainTree }, teamAppTree: { value: teamAppTree }, userAppTree: { value: userAppTree }, diff --git a/src/events/missingToken.ts b/src/events/missingToken.ts index 63a84851..61eba2a5 100644 --- a/src/events/missingToken.ts +++ b/src/events/missingToken.ts @@ -15,7 +15,7 @@ core.on("missingToken", async function () { core.api.authorized = false; core.userTree.clear(); - core.snapshotTree.clear(); + core.subDomainTree.update([]); core.customDomainTree.update([]); core.statusBar.setLogin(); diff --git a/src/events/unauthorized.ts b/src/events/unauthorized.ts index 7f547ea6..d8f8252a 100644 --- a/src/events/unauthorized.ts +++ b/src/events/unauthorized.ts @@ -14,7 +14,6 @@ core.on("unauthorized", async function () { core.api.authorized = false; core.userTree.clear(); - core.snapshotTree.clear(); core.subDomainTree.update([]); core.customDomainTree.update([]); diff --git a/src/events/vscode.ts b/src/events/vscode.ts index 8b08e819..23a0b0da 100644 --- a/src/events/vscode.ts +++ b/src/events/vscode.ts @@ -20,9 +20,6 @@ core.on("vscode", async function (user) { if ("appsStatus" in user) core.userAppTree.setRawApps(user.appsStatus); - if ("appsStatus" in user) - core.snapshotTree.setRawApps(user.appsStatus); - if ("appsTeam" in user) core.teamAppTree.setRawApps(user.appsTeam.map(id => ({ id }))); diff --git a/src/providers/SnapshotTreeDataProvider.ts b/src/providers/SnapshotTreeDataProvider.ts deleted file mode 100644 index 613339b1..00000000 --- a/src/providers/SnapshotTreeDataProvider.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { t } from "@vscode/l10n"; -import { type ProviderResult, window } from "vscode"; -import { type ApiVscodeApp } from "../@types"; -import type ExtensionCore from "../core/extension"; -import EmptyAppListTreeItem from "../structures/EmptyAppListTreeItem"; -import SnapshotAppTreeItem from "../structures/SnapshotAppTreeItem"; -import { EMPTY_TREE_ITEM_ID, TreeViewIds } from "../utils/constants"; -import BaseTreeDataProvider from "./BaseTreeDataProvider"; - -type Item = SnapshotAppTreeItem - -export default class SnapshotTreeDataProvider extends BaseTreeDataProvider { - constructor(readonly core: ExtensionCore) { - super(core.context, TreeViewIds.discloudSnapshots); - } - - getChildren(element?: SnapshotAppTreeItem): ProviderResult { - if (element) { - return element.fetch(this.core).then(children => { - this.refresh(element); - return children; - }); - } - - return this.children.values().toArray(); - } - - refresh(data?: Item | Item[] | null) { - super.refresh(data); - } - - clear() { - this.children.dispose(); - this.refresh(); - } - - setRawApps(data: ApiVscodeApp[]) { - this.children.dispose(); - - if (!data.length) { - this.children.set(EMPTY_TREE_ITEM_ID, new EmptyAppListTreeItem() as Item); - this.refresh(); - return; - } - - for (const app of data) { - this.children.set(app.id, SnapshotAppTreeItem.fromApp(app)); - } - - this.refresh(); - } - - async fetch() { - await window.withProgress({ - location: { viewId: this.viewId }, - title: t("refreshing"), - }, async () => { - this.core.statusBar.setLoading(); - await this.core.user.fetch(true); - this.core.statusBar.reset(); - }); - } - - async refreshApp(appId: string) { - const item = this.children.get(appId); - if (!item) return; - await item.fetch(this.core, true); - this.refresh(item); - } -} diff --git a/src/structures/SnapshotAppTreeItem.ts b/src/structures/SnapshotAppTreeItem.ts deleted file mode 100644 index 78111697..00000000 --- a/src/structures/SnapshotAppTreeItem.ts +++ /dev/null @@ -1,143 +0,0 @@ -import path from "path"; -import { type AppType } from "../@enum"; -import { - type ApiVscodeApp, - type RESTGetApiSnapshotVersionsResult, - type SnapshotAppTreeItemData, -} from "../@types"; -import type ExtensionCore from "../core/extension"; -import DiscloudAPIError from "../services/discloud/errors/api"; -import BaseTreeItem from "./BaseTreeItem"; -import SnapshotInfoTreeItem from "./SnapshotInfoTreeItem"; -import SnapshotVersionTreeItem from "./SnapshotVersionTreeItem"; -import { t } from "@vscode/l10n"; -import { ThemeIcon, TreeItemCollapsibleState, Uri } from "vscode"; - -function getAppSnapshotLabel(app: Partial) { - return app.type === 0 && app.name - ? `${app.name} (${app.id})` - : (app.id ?? app.name ?? t("loading")); -} - -export default class SnapshotAppTreeItem extends BaseTreeItem< - SnapshotVersionTreeItem | SnapshotInfoTreeItem -> { - readonly contextKey = "SnapshotAppTreeItem"; - readonly appId: string; - declare readonly type: AppType | undefined; - #loaded = false; - - constructor(readonly data: SnapshotAppTreeItemData) { - super( - data.label, - data.collapsibleState ?? TreeItemCollapsibleState.Collapsed, - ); - - this.appId = data.appId; - this._patch(data); - } - - get contextJSON() { - return { - appId: this.appId, - type: this.type ?? null, - }; - } - - async fetch(core: ExtensionCore, force = false) { - if (this.#loaded && !force) return this.children.values().toArray(); - - this.children.dispose(); - - try { - const response = - await core.api.queueGet( - `/snapshot/${this.appId}`, - ); - const versions = response?.versions ?? []; - - if (!versions.length) { - this.children.set( - "empty", - new SnapshotInfoTreeItem(t("no.snapshot.found")), - ); - } else { - for (const version of versions) { - this.children.set( - version.version, - new SnapshotVersionTreeItem({ - appId: this.appId, - command: { - arguments: [this.appId, version.version], - command: "discloud.snapshot.download", - title: t("command.snapshot.download"), - }, - date: version.date, - label: version.version, - size: version.size, - version: version.version, - }), - ); - } - } - - this.#loaded = true; - this.description = `${versions.length}`; - } catch (error) { - if (error instanceof DiscloudAPIError && error.code === 404) { - this.children.set( - "empty", - new SnapshotInfoTreeItem(t("no.snapshot.found")), - ); - this.#loaded = true; - this.description = "0"; - } else { - throw error; - } - } - - return this.children.values().toArray(); - } - - private getTypeIcon() { - if (this.type === 1) { - return new ThemeIcon("globe"); - } - - return { - light: Uri.file(path.join(__dirname, "../resources/light/bot.svg")), - dark: Uri.file(path.join(__dirname, "../resources/dark/bot.svg")), - }; - } - _patch(data: Partial) { - if (!data) return this; - - super._patch(data); - - if (data.type !== undefined) - Object.defineProperty(this, "type", { - value: data.type, - configurable: true, - }); - - this.label = data.label ?? this.label; - this.description = - data.snapshotCount !== undefined - ? `${data.snapshotCount}` - : (this.description ?? data.description); - this.tooltip = data.tooltip ?? `${this.label}`; - this.iconPath = this.getTypeIcon(); - this.contextValue = `${this.contextKey}.${JSON.stringify(this.contextJSON)}`; - - return this; - } - - static fromApp(app: ApiVscodeApp) { - return new SnapshotAppTreeItem({ - appId: app.id, - description: t("view.snapshot.title"), - label: getAppSnapshotLabel(app), - type: app.type, - }); - } -} \ No newline at end of file diff --git a/src/structures/SnapshotInfoTreeItem.ts b/src/structures/SnapshotInfoTreeItem.ts deleted file mode 100644 index 68dae756..00000000 --- a/src/structures/SnapshotInfoTreeItem.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ThemeIcon } from "vscode"; -import BaseChildTreeItem from "./BaseChildTreeItem"; - -export default class SnapshotInfoTreeItem extends BaseChildTreeItem { - readonly contextKey = "SnapshotInfoTreeItem"; - - constructor(label: string, description?: string) { - super(label); - this._patch({ - description, - iconPath: new ThemeIcon("info"), - label, - }); - } -} diff --git a/src/structures/SnapshotVersionTreeItem.ts b/src/structures/SnapshotVersionTreeItem.ts deleted file mode 100644 index 5d3be09b..00000000 --- a/src/structures/SnapshotVersionTreeItem.ts +++ /dev/null @@ -1,63 +0,0 @@ -import bytes from "bytes"; -import { t } from "@vscode/l10n"; -import { ThemeIcon } from "vscode"; -import { type SnapshotVersionTreeItemData } from "../@types"; -import BaseChildTreeItem from "./BaseChildTreeItem"; - -function formatSnapshotDate(value?: number | string) { - if (typeof value === "number" || typeof value === "string") { - const date = new Date(value); - if (!Number.isNaN(date.valueOf())) return date.toLocaleString(); - } - - return value ? `${value}` : undefined; -} - -function formatSnapshotSize(value?: number | string) { - if (typeof value === "number") - return bytes.format(value, { unitSeparator: " " }) ?? `${value} B`; - - return value ? `${value}` : undefined; -} - -export default class SnapshotVersionTreeItem extends BaseChildTreeItem { - readonly contextKey = "SnapshotVersionTreeItem"; - readonly appId: string; - declare readonly version: string; - - constructor(readonly data: SnapshotVersionTreeItemData) { - super(data.label ?? data.version, data.collapsibleState); - - this.appId = data.appId; - this.version = data.version; - - this._patch(data); - } - - get contextJSON() { - return { - appId: this.appId, - version: this.version, - }; - } - - _patch(data: Partial) { - if (!data) return this; - - super._patch(data); - - if (data.version !== undefined) - Object.defineProperty(this, "version", { value: data.version, configurable: true }); - - this.label = data.version ?? this.label; - this.description = formatSnapshotSize(data.size) ?? this.description; - this.tooltip = [ - `${t("snapshot.version")}: ${this.label}`, - formatSnapshotDate(data.date) ? `${t("snapshot.created.at")}: ${formatSnapshotDate(data.date)}` : null, - this.description ? `${t("snapshot.size")}: ${this.description}` : null, - ].filter(Boolean).join("\n"); - this.iconPath = new ThemeIcon("history"); - - return this; - } -} From 8712f4111a29b81deb5c504844b1ea77748a5003 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 30 May 2026 16:11:12 +0000 Subject: [PATCH 07/22] style: fix linter issues --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index b5a868ab..60ae5773 100644 --- a/yarn.lock +++ b/yarn.lock @@ -369,10 +369,10 @@ dependencies: undici-types "~6.21.0" -"@types/vscode@^1.118.0": - version "1.118.0" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.118.0.tgz#4a226ddf8faa11a9e6b338555431c4edd3230e4a" - integrity sha512-Ah6eTlqDcwIMELEVwQMO++rJAFBRz/oLluLD/vWdYrH1KuI9kfpaM+7pg0OvvascgcJy+ghLCERAYouM4QbzGw== +"@types/vscode@^1.116.0": + version "1.120.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.120.0.tgz#af36ef6e9952aa643e3682468197e319be80b4ae" + integrity sha512-feaT4Rst+FkTch5zz/ZbNCxoIvo55YU80Be2kiL7OJcod4+CUYf2lUBPdIJzozNnSEMq1VRTGrWEcCGFB3fBmA== "@types/ws@^8.18.1": version "8.18.1" From 1a600191fb4d4b8d159ae333fd094a2c45280b60 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 30 May 2026 16:22:10 +0000 Subject: [PATCH 08/22] style: fix linter issues --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 1395e2eb..30640886 100644 --- a/yarn.lock +++ b/yarn.lock @@ -369,7 +369,7 @@ dependencies: undici-types "~6.21.0" -"@types/vscode@^1.116.0": +"@types/vscode@^1.118.0": version "1.120.0" resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.120.0.tgz#af36ef6e9952aa643e3682468197e319be80b4ae" integrity sha512-feaT4Rst+FkTch5zz/ZbNCxoIvo55YU80Be2kiL7OJcod4+CUYf2lUBPdIJzozNnSEMq1VRTGrWEcCGFB3fBmA== From b8f3f4bcea91e8f78a04373c74e234fbd62342a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:25:35 -0300 Subject: [PATCH 09/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 011c276c..30f278ba 100644 --- a/package.json +++ b/package.json @@ -601,7 +601,7 @@ ".discloudignore" ], "icon": { - "dark": "resources/icons/discloud_white_icon.svg", + "dark": "resources/icons/discloud_icon.svg", "light": "resources/icons/discloud_white_icon.svg" } }, From f080c363d393d44ce5b204bab57b259a9fe37fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:25:58 -0300 Subject: [PATCH 10/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30f278ba..29b7bd4f 100644 --- a/package.json +++ b/package.json @@ -602,7 +602,7 @@ ], "icon": { "dark": "resources/icons/discloud_icon.svg", - "light": "resources/icons/discloud_white_icon.svg" + "light": "resources/icons/discloud_icon.svg" } }, { From ca826d870ef85465edce7a61f6948974f7fbbb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:26:27 -0300 Subject: [PATCH 11/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29b7bd4f..0f722060 100644 --- a/package.json +++ b/package.json @@ -1244,7 +1244,7 @@ { "type": "tree", "id": "discloudUserApps", - "icon": "resources/icons/discloud_white_icon.svg", + "icon": "resources/icons/discloud_icon.svg", "name": "%view.apps.title%", "visibility": "visible", "when": "discloudAuthorized" From f233eab22f2e4a127f0abbc7f00a623459267baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:26:39 -0300 Subject: [PATCH 12/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f722060..b4c0d3dd 100644 --- a/package.json +++ b/package.json @@ -1252,7 +1252,7 @@ { "type": "tree", "id": "discloudTeamApps", - "icon": "resources/icons/discloud_white_icon.svg", + "icon": "resources/icons/discloud_icon.svg", "name": "%view.team.title%", "visibility": "collapsed", "when": "discloudAuthorized" From 1dd05230c79b6b47c11675aafb8ad71ce7236091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:27:03 -0300 Subject: [PATCH 13/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b4c0d3dd..b994f16f 100644 --- a/package.json +++ b/package.json @@ -1287,7 +1287,7 @@ { "id": "discloudActivityBar", "title": "Discloud", - "icon": "resources/icons/discloud_white_icon.svg" + "icon": "resources/icons/discloud_icon.svg" } ] }, From 271ab28548419a1b24cd30a05e12ac2843c90027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:27:24 -0300 Subject: [PATCH 14/22] Update src/events/vscode.ts Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- src/events/vscode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/vscode.ts b/src/events/vscode.ts index 23a0b0da..7f2ff178 100644 --- a/src/events/vscode.ts +++ b/src/events/vscode.ts @@ -24,7 +24,7 @@ core.on("vscode", async function (user) { core.teamAppTree.setRawApps(user.appsTeam.map(id => ({ id }))); if ("subdomains" in user) - core.subDomainTree.update(hasSubdomainsAccess ? user.subdomains : []); + core.subDomainTree.update(user.subdomains); if ("customdomains" in user) core.customDomainTree.update(hasCustomDomainsAccess ? user.customdomains : []); From 83780f32c42eccceb45a6249aff7cda4232c5e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:27:38 -0300 Subject: [PATCH 15/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b994f16f..2817d66b 100644 --- a/package.json +++ b/package.json @@ -1268,7 +1268,7 @@ { "type": "tree", "id": "discloudDomains", - "icon": "resources/icons/discloud_white_icon.svg", + "icon": "resources/icons/discloud_icon.svg", "name": "%view.domain.title%", "visibility": "collapsed", "when": "discloudAuthorized && discloudHasCustomDomainsAccess" From 8895e0d0e3363f158500c09e2ee25dbc9c8b3876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:27:50 -0300 Subject: [PATCH 16/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2817d66b..07150cc6 100644 --- a/package.json +++ b/package.json @@ -1260,7 +1260,7 @@ { "type": "tree", "id": "discloudSubdomains", - "icon": "resources/icons/discloud_white_icon.svg", + "icon": "resources/icons/discloud_icon.svg", "name": "%view.subdomain.title%", "visibility": "collapsed", "when": "discloudAuthorized && discloudHasSubdomainsAccess" From 805e6cf560fd15eebf1fa085d30eb7982f10dff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:29:43 -0300 Subject: [PATCH 17/22] Update src/structures/UserTreeItem.ts Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- src/structures/UserTreeItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/UserTreeItem.ts b/src/structures/UserTreeItem.ts index 62afcb6e..3df324bf 100644 --- a/src/structures/UserTreeItem.ts +++ b/src/structures/UserTreeItem.ts @@ -9,7 +9,7 @@ import UserChildTreeItem from "./UserChildTreeItem"; function getUserFallbackIconPath() { return getThemedResourceIconPath( "resources/icons/discloud_white_icon.svg", - "resources/icons/discloud_white_icon.svg", + "resources/icons/discloud_icon.svg", ); } From 696a477a5423794fd7e49faf3028528ba6250061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:30:02 -0300 Subject: [PATCH 18/22] Update src/events/vscode.ts Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- src/events/vscode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/vscode.ts b/src/events/vscode.ts index 7f2ff178..8b4f91b6 100644 --- a/src/events/vscode.ts +++ b/src/events/vscode.ts @@ -27,5 +27,5 @@ core.on("vscode", async function (user) { core.subDomainTree.update(user.subdomains); if ("customdomains" in user) - core.customDomainTree.update(hasCustomDomainsAccess ? user.customdomains : []); + core.customDomainTree.update(user.customdomains); }); From 974ec0731ce8d13589ec364dae6aeb6aa91e95b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B4nio=20Vinicius?= Date: Mon, 1 Jun 2026 13:30:09 -0300 Subject: [PATCH 19/22] Update package.json Co-authored-by: Gorniaky <30408913+Gorniaky@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07150cc6..c5044396 100644 --- a/package.json +++ b/package.json @@ -1276,7 +1276,7 @@ { "type": "tree", "id": "discloudUser", - "icon": "resources/icons/discloud_white_icon.svg", + "icon": "resources/icons/discloud_icon.svg", "name": "%view.user.title%", "visibility": "collapsed" } From d54d3d2b3fd25b42df189e43b26cb10864aee9f3 Mon Sep 17 00:00:00 2001 From: Gorniaky <30408913+Gorniaky@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:36:52 -0300 Subject: [PATCH 20/22] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c5044396..54f3e101 100644 --- a/package.json +++ b/package.json @@ -612,7 +612,7 @@ ], "icon": { "dark": "resources/icons/discloud_white_icon.svg", - "light": "resources/icons/discloud_white_icon.svg" + "light": "resources/icons/discloud_icon.svg" } } ], From 8e94b4dd4b366c85268600a94e1775435d3aa7fe Mon Sep 17 00:00:00 2001 From: Gorniaky <30408913+Gorniaky@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:37:06 -0300 Subject: [PATCH 21/22] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 54f3e101..aab4de8c 100644 --- a/package.json +++ b/package.json @@ -611,7 +611,7 @@ "discloud.config" ], "icon": { - "dark": "resources/icons/discloud_white_icon.svg", + "dark": "resources/icons/discloud_icon.svg", "light": "resources/icons/discloud_icon.svg" } } From 0ccf4db8dea4305d2a9c14fe35fa997f86b2fbba Mon Sep 17 00:00:00 2001 From: Gorniaky <30408913+Gorniaky@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:37:22 -0300 Subject: [PATCH 22/22] Update src/structures/UserTreeItem.ts --- src/structures/UserTreeItem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/UserTreeItem.ts b/src/structures/UserTreeItem.ts index 3df324bf..eca7769b 100644 --- a/src/structures/UserTreeItem.ts +++ b/src/structures/UserTreeItem.ts @@ -8,7 +8,7 @@ import UserChildTreeItem from "./UserChildTreeItem"; function getUserFallbackIconPath() { return getThemedResourceIconPath( - "resources/icons/discloud_white_icon.svg", + "resources/icons/discloud_icon.svg", "resources/icons/discloud_icon.svg", ); }