Mercurial > libervia-backend
annotate sat_frontends/jp/cmd_account.py @ 3404:26a0af6e32c1
plugin XEP-0166: new trigger point + coroutines + helper methods:
- a new `XEP-0166_initiate` async trigger point is available
- `initate` is now a coroutine
- `jingleSessionInit` in applications and transports handlers are now called using
`utils.adDeferred`
- new `getApplication` helper method, to retrieve application from its namespace
- new `getContentData` helper method to retrieve application and its argument from content
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 12 Nov 2020 14:53:15 +0100 |
parents | 559a625a236b |
children | df775db4c49b |
rev | line source |
---|---|
3137 | 1 #!/usr/bin/env python3 |
2 | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
3 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
4 # jp: a SAT command line tool |
3136 | 5 # Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
6 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
7 # This program is free software: you can redistribute it and/or modify |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
8 # it under the terms of the GNU Affero General Public License as published by |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
9 # the Free Software Foundation, either version 3 of the License, or |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
10 # (at your option) any later version. |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
11 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
12 # This program is distributed in the hope that it will be useful, |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
15 # GNU Affero General Public License for more details. |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
16 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
17 # You should have received a copy of the GNU Affero General Public License |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
19 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
20 """This module permits to manage XMPP accounts using in-band registration (XEP-0077)""" |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
21 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
22 from sat_frontends.jp.constants import Const as C |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
23 from sat.core.log import getLogger |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
24 |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
25 log = getLogger(__name__) |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
26 from sat.core.i18n import _ |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
27 from sat_frontends.jp import base |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
28 from sat_frontends.tools import jid |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
29 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
30 __commands__ = ["Account"] |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
31 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
32 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
33 class AccountCreate(base.CommandBase): |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
34 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
35 super(AccountCreate, self).__init__( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
36 host, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
37 "create", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
38 use_profile=False, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
39 use_verbose=True, |
3028 | 40 help=_("create a XMPP account"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
41 ) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
42 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
43 def add_parser_options(self): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
44 self.parser.add_argument( |
3028 | 45 "jid", help=_("jid to create") |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
46 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
47 self.parser.add_argument( |
3028 | 48 "password", help=_("password of the account") |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
49 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
50 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
51 "-p", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
52 "--profile", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
53 help=_( |
3028 | 54 "create a profile to use this account (default: don't create profile)" |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
55 ), |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
56 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
57 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
58 "-e", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
59 "--email", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
60 default="", |
3028 | 61 help=_("email (usage depends of XMPP server)"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
62 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
63 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
64 "-H", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
65 "--host", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
66 default="", |
3028 | 67 help=_("server host (IP address or domain, default: use localhost)"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
68 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
69 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
70 "-P", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
71 "--port", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
72 type=int, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
73 default=0, |
3040 | 74 help=_(f"server port (default: {C.XMPP_C2S_PORT})"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
75 ) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
76 |
3040 | 77 async def start(self): |
78 try: | |
79 await self.host.bridge.inBandAccountNew( | |
80 self.args.jid, | |
81 self.args.password, | |
82 self.args.email, | |
83 self.args.host, | |
84 self.args.port, | |
85 ) | |
86 except Exception as e: | |
87 self.disp( | |
88 f"can't create account on {self.args.host or 'localhost'!r} with jid " | |
89 f"{self.args.jid!r} using In-Band Registration: {e}", error=True) | |
90 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
91 |
3040 | 92 self.disp(_("XMPP account created"), 1) |
93 | |
94 if self.args.profile is None: | |
95 self.host.quit() | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
96 |
3040 | 97 |
98 self.disp(_("creating profile"), 2) | |
99 try: | |
100 await self.host.bridge.profileCreate( | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
101 self.args.profile, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
102 self.args.password, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
103 "", |
3040 | 104 ) |
105 except Exception as e: | |
106 self.disp( | |
107 _(f"Can't create profile {self.args.profile} to associate with jid " | |
108 f"{self.args.jid}: {e}"), | |
109 error=True, | |
110 ) | |
111 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
112 | |
113 self.disp(_("profile created"), 1) | |
114 try: | |
115 await self.host.bridge.profileStartSession( | |
116 self.args.password, | |
117 self.args.profile, | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
118 ) |
3040 | 119 except Exception as e: |
120 self.disp(f"can't start profile session: {e}", error=True) | |
121 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
122 |
3040 | 123 try: |
124 await self.host.bridge.setParam( | |
125 "JabberID", | |
126 self.args.jid, | |
127 "Connection", | |
128 profile_key=self.args.profile, | |
129 ) | |
130 except Exception as e: | |
131 self.disp(f"can't set JabberID parameter: {e}", error=True) | |
132 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
133 | |
134 try: | |
135 await self.host.bridge.setParam( | |
136 "Password", | |
137 self.args.password, | |
138 "Connection", | |
139 profile_key=self.args.profile, | |
140 ) | |
141 except Exception as e: | |
142 self.disp(f"can't set Password parameter: {e}", error=True) | |
143 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
144 | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
145 self.disp( |
3040 | 146 f"profile {self.args.profile} successfully created and associated to the new " |
147 f"account", 1) | |
148 self.host.quit() | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
149 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
150 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
151 class AccountModify(base.CommandBase): |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
152 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
153 super(AccountModify, self).__init__( |
3028 | 154 host, "modify", help=_("change password for XMPP account") |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
155 ) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
156 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
157 def add_parser_options(self): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
158 self.parser.add_argument( |
3028 | 159 "password", help=_("new XMPP password") |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
160 ) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
161 |
3040 | 162 async def start(self): |
163 try: | |
164 await self.host.bridge.inBandPasswordChange( | |
165 self.args.password, | |
166 self.args.profile, | |
167 ) | |
168 except Exception as e: | |
169 self.disp(f"can't change XMPP password: {e}", error=True) | |
170 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
171 else: | |
172 self.host.quit() | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
173 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
174 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
175 class AccountDelete(base.CommandBase): |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
176 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
177 super(AccountDelete, self).__init__( |
3028 | 178 host, "delete", help=_("delete a XMPP account") |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
179 ) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
180 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
181 def add_parser_options(self): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
182 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
183 "-f", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
184 "--force", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
185 action="store_true", |
3028 | 186 help=_("delete account without confirmation"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
187 ) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
188 |
3040 | 189 async def start(self): |
190 try: | |
191 jid_str = await self.host.bridge.asyncGetParamA( | |
192 "JabberID", | |
193 "Connection", | |
194 profile_key=self.profile, | |
195 ) | |
196 except Exception as e: | |
197 self.disp(f"can't get JID of the profile: {e}", error=True) | |
198 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
199 | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
200 jid_ = jid.JID(jid_str) |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
201 if not self.args.force: |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
202 message = ( |
3040 | 203 f"You are about to delete the XMPP account with jid {jid_!r}\n" |
204 f"This is the XMPP account of profile {self.profile!r}\n" | |
205 f"Are you sure that you want to delete this account?" | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
206 ) |
3040 | 207 await self.host.confirmOrQuit(message, _("Account deletion cancelled")) |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
208 |
3040 | 209 try: |
210 await self.host.bridge.inBandUnregister(jid_.domain, self.args.profile) | |
211 except Exception as e: | |
212 self.disp(f"can't delete XMPP account with jid {jid_!r}: {e}", error=True) | |
213 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
214 | |
215 self.host.quit() | |
2180
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
216 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
217 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
218 class Account(base.CommandBase): |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
219 subcommands = (AccountCreate, AccountModify, AccountDelete) |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
220 |
be54e1c3394c
jp (account): command to handle XMPP account creation/password change/deletion using in-band registration
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
221 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
222 super(Account, self).__init__( |
3028 | 223 host, "account", use_profile=False, help=("XMPP account management") |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
224 ) |