Mercurial > libervia-backend
annotate sat_frontends/jp/cmd_ticket.py @ 3243:f2e30aa031e9
bridge (pb): fixed conversions of Failure to BridgeException in non-AIO bridge
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 01 Apr 2020 15:40:29 +0200 |
parents | 559a625a236b |
children | 71761e9fb984 |
rev | line source |
---|---|
3137 | 1 #!/usr/bin/env python3 |
2 | |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
3 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
4 # jp: a SàT command line tool |
3136 | 5 # Copyright (C) 2009-2020 Jérôme Poisson (goffi@goffi.org) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
6 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
7 # This program is free software: you can redistribute it and/or modify |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
8 # it under the terms of the GNU Affero General Public License as published by |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
9 # the Free Software Foundation, either version 3 of the License, or |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
10 # (at your option) any later version. |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
11 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
12 # This program is distributed in the hope that it will be useful, |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
15 # GNU Affero General Public License for more details. |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
16 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
17 # You should have received a copy of the GNU Affero General Public License |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
19 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
20 |
3028 | 21 from . import base |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
22 from sat.core.i18n import _ |
2602
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
23 from sat_frontends.jp import common |
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
24 from sat_frontends.jp.constants import Const as C |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
25 import json |
2602
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
26 import os |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
27 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
28 __commands__ = ["Ticket"] |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
29 |
3028 | 30 FIELDS_MAP = "mapping" |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
31 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
32 |
2602
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
33 class Get(base.CommandBase): |
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
34 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
35 base.CommandBase.__init__( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
36 self, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
37 host, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
38 "get", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
39 use_verbose=True, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
40 use_pubsub=True, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
41 pubsub_flags={C.MULTI_ITEMS}, |
3028 | 42 pubsub_defaults={"service": _("auto"), "node": _("auto")}, |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
43 use_output=C.OUTPUT_LIST_XMLUI, |
3028 | 44 help=_("get tickets"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
45 ) |
2602
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
46 |
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
47 def add_parser_options(self): |
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
48 pass |
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
49 |
3040 | 50 async def start(self): |
51 await common.fill_well_known_uri(self, os.getcwd(), "tickets", meta_map={}) | |
52 try: | |
53 tickets_data = await self.host.bridge.ticketsGet( | |
54 self.args.service, | |
55 self.args.node, | |
56 self.args.max, | |
57 self.args.items, | |
58 "", | |
59 self.getPubsubExtra(), | |
60 self.profile, | |
61 ) | |
62 except Exception as e: | |
63 self.disp(f"can't get tickets: {e}", error=True) | |
64 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
65 else: | |
66 await self.output(tickets_data[0]) | |
67 self.host.quit(C.EXIT_OK) | |
2602
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
68 |
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
69 |
3040 | 70 class Import(base.CommandBase): |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
71 # TODO: factorize with blog/import |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
72 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
73 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
74 super(Import, self).__init__( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
75 host, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
76 "import", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
77 use_progress=True, |
3040 | 78 use_verbose=True, |
3028 | 79 help=_("import tickets from external software/dataset"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
80 ) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
81 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
82 def add_parser_options(self): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
83 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
84 "importer", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
85 nargs="?", |
3028 | 86 help=_("importer name, nothing to display importers list"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
87 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
88 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
89 "-o", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
90 "--option", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
91 action="append", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
92 nargs=2, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
93 default=[], |
3028 | 94 metavar=("NAME", "VALUE"), |
95 help=_("importer specific options (see importer description)"), | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
96 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
97 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
98 "-m", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
99 "--map", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
100 action="append", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
101 nargs=2, |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
102 default=[], |
3028 | 103 metavar=("IMPORTED_FIELD", "DEST_FIELD"), |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
104 help=_( |
3040 | 105 "specified field in import data will be put in dest field (default: use " |
106 "same field name, or ignore if it doesn't exist)" | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
107 ), |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
108 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
109 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
110 "-s", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
111 "--service", |
3028 | 112 default="", |
113 metavar="PUBSUB_SERVICE", | |
114 help=_("PubSub service where the items must be uploaded (default: server)"), | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
115 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
116 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
117 "-n", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
118 "--node", |
3028 | 119 default="", |
120 metavar="PUBSUB_NODE", | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
121 help=_( |
3040 | 122 "PubSub node where the items must be uploaded (default: tickets' " |
123 "defaults)" | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
124 ), |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
125 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
126 self.parser.add_argument( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
127 "location", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
128 nargs="?", |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
129 help=_( |
3040 | 130 "importer data location (see importer description), nothing to show " |
131 "importer description" | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
132 ), |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
133 ) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
134 |
3040 | 135 async def onProgressStarted(self, metadata): |
3028 | 136 self.disp(_("Tickets upload started"), 2) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
137 |
3040 | 138 async def onProgressFinished(self, metadata): |
3028 | 139 self.disp(_("Tickets uploaded successfully"), 2) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
140 |
3040 | 141 async def onProgressError(self, error_msg): |
142 self.disp(_(f"Error while uploading tickets: {error_msg}"), error=True) | |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
143 |
3040 | 144 async def start(self): |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
145 if self.args.location is None: |
3040 | 146 # no location, the list of importer or description is requested |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
147 for name in ("option", "service", "node"): |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
148 if getattr(self.args, name): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
149 self.parser.error( |
3040 | 150 _(f"{name} argument can't be used without location argument")) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
151 if self.args.importer is None: |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
152 self.disp( |
3028 | 153 "\n".join( |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
154 [ |
3040 | 155 f"{name}: {desc}" |
156 for name, desc in await self.host.bridge.ticketsImportList() | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
157 ] |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
158 ) |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
159 ) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
160 else: |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
161 try: |
3040 | 162 short_desc, long_desc = await self.host.bridge.ticketsImportDesc( |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
163 self.args.importer |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
164 ) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
165 except Exception as e: |
3040 | 166 self.disp(f"can't get importer description: {e}", error=True) |
167 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
168 else: |
3040 | 169 self.disp(f"{name}: {short_desc}\n\n{long_desc}") |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
170 self.host.quit() |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
171 else: |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
172 # we have a location, an import is requested |
3040 | 173 |
174 if self.args.progress: | |
175 # we use a custom progress bar template as we want a counter | |
176 self.pbar_template = [ | |
177 _("Progress: "), ["Percentage"], " ", ["Bar"], " ", | |
178 ["Counter"], " ", ["ETA"] | |
179 ] | |
180 | |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
181 options = {key: value for key, value in self.args.option} |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
182 fields_map = dict(self.args.map) |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
183 if fields_map: |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
184 if FIELDS_MAP in options: |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
185 self.parser.error( |
3040 | 186 _("fields_map must be specified either preencoded in --option or " |
187 "using --map, but not both at the same time") | |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
188 ) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
189 options[FIELDS_MAP] = json.dumps(fields_map) |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
190 |
3040 | 191 try: |
192 progress_id = await self.host.bridge.ticketsImport( | |
193 self.args.importer, | |
194 self.args.location, | |
195 options, | |
196 self.args.service, | |
197 self.args.node, | |
198 self.profile, | |
199 ) | |
200 except Exception as e: | |
201 self.disp( | |
202 _(f"Error while trying to import tickets: {e}"), | |
203 error=True, | |
204 ) | |
205 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
206 else: | |
207 await self.set_progress_id(progress_id) | |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
208 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
209 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
210 class Ticket(base.CommandBase): |
2602
41db2f58c753
jp (ticket): new "get" subcommand, to retrieve ticket(s)
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
211 subcommands = (Get, Import) |
2374
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
212 |
686f84ebb670
jp (ticket): ticket command first draft:
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
213 def __init__(self, host): |
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
214 super(Ticket, self).__init__( |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
215 host, "ticket", use_profile=False, help=_("tickets handling") |
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2602
diff
changeset
|
216 ) |