Mercurial > dive4elements > river
comparison gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ParameterMatrix.java @ 9390:f575ff573cbb
"Name der Peilung" columname minfo.
author | gernotbelger |
---|---|
date | Thu, 09 Aug 2018 15:22:31 +0200 |
parents | 5e38e2924c07 |
children | 2da486c7c05f |
comparison
equal
deleted
inserted
replaced
9389:63c086139391 | 9390:f575ff573cbb |
---|---|
6 * documentation coming with Dive4Elements River for details. | 6 * documentation coming with Dive4Elements River for details. |
7 */ | 7 */ |
8 | 8 |
9 package org.dive4elements.river.client.client.ui; | 9 package org.dive4elements.river.client.client.ui; |
10 | 10 |
11 import java.io.Serializable; | |
12 import java.util.ArrayList; | |
13 import java.util.HashMap; | |
14 import java.util.List; | |
15 import java.util.Map; | |
16 | |
17 import org.dive4elements.river.client.client.FLYSConstants; | |
18 import org.dive4elements.river.client.shared.model.DataItem; | |
19 import org.dive4elements.river.client.shared.model.IntegerOptionsData; | |
20 import org.dive4elements.river.client.shared.model.MultiAttributeData; | |
21 import org.dive4elements.river.client.shared.model.MultiDataItem; | |
22 import org.dive4elements.river.client.shared.model.StringOptionsData; | |
23 | |
11 import com.google.gwt.core.client.GWT; | 24 import com.google.gwt.core.client.GWT; |
12 import com.google.gwt.event.dom.client.ClickEvent; | 25 import com.google.gwt.event.dom.client.ClickEvent; |
13 import com.google.gwt.event.dom.client.ClickHandler; | 26 import com.google.gwt.event.dom.client.ClickHandler; |
14 import com.google.gwt.user.client.ui.CheckBox; | 27 import com.google.gwt.user.client.ui.CheckBox; |
15 import com.google.gwt.user.client.ui.Grid; | 28 import com.google.gwt.user.client.ui.Grid; |
16 import com.google.gwt.user.client.ui.Widget; | 29 import com.google.gwt.user.client.ui.Widget; |
17 | |
18 import com.smartgwt.client.types.ListGridFieldType; | 30 import com.smartgwt.client.types.ListGridFieldType; |
19 import com.smartgwt.client.widgets.Canvas; | 31 import com.smartgwt.client.widgets.Canvas; |
20 import com.smartgwt.client.widgets.Label; | 32 import com.smartgwt.client.widgets.Label; |
21 import com.smartgwt.client.widgets.grid.ListGrid; | 33 import com.smartgwt.client.widgets.grid.ListGrid; |
22 import com.smartgwt.client.widgets.grid.ListGridField; | 34 import com.smartgwt.client.widgets.grid.ListGridField; |
23 import com.smartgwt.client.widgets.grid.ListGridRecord; | 35 import com.smartgwt.client.widgets.grid.ListGridRecord; |
24 | |
25 import org.dive4elements.river.client.client.FLYSConstants; | |
26 import org.dive4elements.river.client.shared.model.DataItem; | |
27 import org.dive4elements.river.client.shared.model.IntegerOptionsData; | |
28 import org.dive4elements.river.client.shared.model.MultiAttributeData; | |
29 import org.dive4elements.river.client.shared.model.MultiDataItem; | |
30 import org.dive4elements.river.client.shared.model.StringOptionsData; | |
31 | |
32 import java.io.Serializable; | |
33 import java.util.ArrayList; | |
34 import java.util.HashMap; | |
35 import java.util.List; | |
36 import java.util.Map; | |
37 | |
38 | 36 |
39 /** | 37 /** |
40 * Some parameters take the form of on/off options that can also be seen | 38 * Some parameters take the form of on/off options that can also be seen |
41 * as a matrix. | 39 * as a matrix. |
42 * | 40 * |
50 | 48 |
51 public static class Column implements Serializable { | 49 public static class Column implements Serializable { |
52 | 50 |
53 private static final long serialVersionUID = -3493426383086860118L; | 51 private static final long serialVersionUID = -3493426383086860118L; |
54 | 52 |
55 protected String name; | 53 protected String name; |
56 protected Map<String, String> values; | 54 protected Map<String, String> values; |
57 | 55 |
58 private Column() { | 56 private Column() { |
59 this.values = new HashMap<String, String>(); | 57 this.values = new HashMap<String, String>(); |
60 } | 58 } |
61 | 59 |
62 public Column(String name) { | 60 public Column(final String name) { |
63 this(); | 61 this(); |
64 this.name = name; | 62 this.name = name; |
65 } | 63 } |
66 | 64 |
67 public void addValue(String label, String value) { | 65 public void addValue(final String label, final String value) { |
68 values.put(label, value); | 66 this.values.put(label, value); |
69 } | 67 } |
70 | 68 |
71 public String getValue(String label) { | 69 public String getValue(final String label) { |
72 return values.get(label); | 70 return this.values.get(label); |
73 } | 71 } |
74 } // end of class Column | 72 } // end of class Column |
75 | 73 |
76 /** The message class that provides i18n strings.*/ | 74 /** The message class that provides i18n strings. */ |
77 protected FLYSConstants MESSAGE = GWT.create(FLYSConstants.class); | 75 protected FLYSConstants MESSAGE = GWT.create(FLYSConstants.class); |
78 | 76 |
79 public static final int CELL_HEIGHT = 25; | 77 public static final int CELL_HEIGHT = 25; |
80 | 78 |
81 private Map<String, Column> columns; | 79 private final Map<String, Column> columns; |
82 private List<String> columnNames; | 80 private final List<String> columnNames; |
83 private List<String> valueNames; | 81 private final List<String> valueNames; |
84 private Map<String, List<String>> attributes; | 82 private final Map<String, List<String>> attributes; |
85 | 83 |
86 /** Maps column names to list of rows' first fields. */ | 84 /** Maps column names to list of rows' first fields. */ |
87 private Map<String, List<String>> selected; | 85 private final Map<String, List<String>> selected; |
88 | 86 private final String itemname; |
89 public ParameterMatrix() { | 87 |
88 public ParameterMatrix(final String itemnameColTitle) { | |
90 super(); | 89 super(); |
91 this.columns = new HashMap<String, Column>(); | 90 this.itemname = itemnameColTitle; |
91 this.columns = new HashMap<String, Column>(); | |
92 this.columnNames = new ArrayList<String>(); | 92 this.columnNames = new ArrayList<String>(); |
93 this.valueNames = new ArrayList<String>(); | 93 this.valueNames = new ArrayList<String>(); |
94 this.selected = new HashMap<String, List<String>>(); | 94 this.selected = new HashMap<String, List<String>>(); |
95 this.attributes = new HashMap<String, List<String>>(); | 95 this.attributes = new HashMap<String, List<String>>(); |
96 } | 96 } |
97 | 97 |
98 | 98 public void addColumn(final IntegerOptionsData group) { |
99 public void addColumn(IntegerOptionsData group) { | 99 final String groupTitle = group.getLabel(); |
100 String groupTitle = group.getLabel(); | 100 |
101 | 101 final Column col = new Column(groupTitle); |
102 Column col = new Column(groupTitle); | 102 final DataItem[] items = group.getItems(); |
103 DataItem[] items = group.getItems(); | |
104 | 103 |
105 if (items == null) { | 104 if (items == null) { |
106 GWT.log("No items found in StringOptionsData '" + groupTitle + "'"); | 105 GWT.log("No items found in StringOptionsData '" + groupTitle + "'"); |
107 return; | 106 return; |
108 } | 107 } |
109 | 108 |
110 for (DataItem item: items) { | 109 for (final DataItem item : items) { |
111 String title = item.getLabel(); | 110 final String title = item.getLabel(); |
112 | 111 |
113 if (valueNames.indexOf(title) < 0) { | 112 if (this.valueNames.indexOf(title) < 0) { |
114 valueNames.add(title); | 113 this.valueNames.add(title); |
115 } | 114 } |
116 | 115 |
117 col.addValue(item.getLabel(), item.getStringValue()); | 116 col.addValue(item.getLabel(), item.getStringValue()); |
118 } | 117 } |
119 | 118 |
120 columnNames.add(groupTitle); | 119 this.columnNames.add(groupTitle); |
121 columns.put(groupTitle, col); | 120 this.columns.put(groupTitle, col); |
122 } | 121 } |
123 | |
124 | 122 |
125 public List<String> getColumnNames() { | 123 public List<String> getColumnNames() { |
126 return columnNames; | 124 return this.columnNames; |
127 } | 125 } |
128 | 126 |
129 | 127 public void addColumn(final StringOptionsData options) { |
130 public void addColumn(StringOptionsData options) { | 128 final String groupTitle = options.getLabel(); |
131 String groupTitle = options.getLabel(); | 129 |
132 | 130 final Column col = new Column(groupTitle); |
133 Column col = new Column(groupTitle); | 131 final DataItem[] items = options.getItems(); |
134 DataItem[] items = options.getItems(); | |
135 | 132 |
136 if (items == null) { | 133 if (items == null) { |
137 GWT.log("No items found in StringOptionsData '" | 134 GWT.log("No items found in StringOptionsData '" + groupTitle + "'"); |
138 + groupTitle + "'"); | |
139 return; | 135 return; |
140 } | 136 } |
141 | 137 |
142 for (DataItem item: items) { | 138 for (final DataItem item : items) { |
143 String title = item.getLabel(); | 139 final String title = item.getLabel(); |
144 | 140 |
145 if (valueNames.indexOf(title) < 0) { | 141 if (this.valueNames.indexOf(title) < 0) { |
146 valueNames.add(title); | 142 this.valueNames.add(title); |
147 } | 143 } |
148 | 144 |
149 col.addValue(item.getLabel(), item.getStringValue()); | 145 col.addValue(item.getLabel(), item.getStringValue()); |
150 } | 146 } |
151 | 147 |
152 columnNames.add(groupTitle); | 148 this.columnNames.add(groupTitle); |
153 columns.put(groupTitle, col); | 149 this.columns.put(groupTitle, col); |
154 } | 150 } |
155 | 151 |
156 public void addColumn(MultiAttributeData options) { | 152 public void addColumn(final MultiAttributeData options) { |
157 GWT.log("Add Columns for MultiAttribute data"); | 153 GWT.log("Add Columns for MultiAttribute data"); |
158 String groupTitle = options.getLabel(); | 154 final String groupTitle = options.getLabel(); |
159 | 155 |
160 Column col = new Column(groupTitle); | 156 final Column col = new Column(groupTitle); |
161 DataItem[] items = options.getItems(); | 157 final DataItem[] items = options.getItems(); |
162 | 158 |
163 if (items == null) { | 159 if (items == null) { |
164 GWT.log("No items found in StringOptionsData '" | 160 GWT.log("No items found in StringOptionsData '" + groupTitle + "'"); |
165 + groupTitle + "'"); | |
166 return; | 161 return; |
167 } | 162 } |
168 | 163 |
169 MultiDataItem mItem = (MultiDataItem)items[0]; | 164 final MultiDataItem mItem = (MultiDataItem) items[0]; |
170 for (Map.Entry<String, String> entry: mItem.getValue().entrySet()) { | 165 for (final Map.Entry<String, String> entry : mItem.getValue().entrySet()) { |
171 if (entry.getKey().equals("art:value") || | 166 if (entry.getKey().equals("art:value") || entry.getKey().equals("art:label")) { |
172 entry.getKey().equals("art:label")) { | |
173 continue; | 167 continue; |
174 } | 168 } |
175 attributes.put(entry.getKey(), new ArrayList<String>()); | 169 this.attributes.put(entry.getKey(), new ArrayList<String>()); |
176 } | 170 } |
177 for (DataItem item: items) { | 171 for (final DataItem item : items) { |
178 GWT.log("multidataitem: " + item.getLabel()); | 172 GWT.log("multidataitem: " + item.getLabel()); |
179 String title = item.getLabel(); | 173 final String title = item.getLabel(); |
180 | 174 |
181 if (valueNames.indexOf(title) < 0) { | 175 if (this.valueNames.indexOf(title) < 0) { |
182 valueNames.add(title); | 176 this.valueNames.add(title); |
183 } | 177 } |
184 MultiDataItem mi = (MultiDataItem)item; | 178 final MultiDataItem mi = (MultiDataItem) item; |
185 Map<String, String> vs = mi.getValue(); | 179 final Map<String, String> vs = mi.getValue(); |
186 for (Map.Entry<String, String>e: vs.entrySet()) { | 180 for (final Map.Entry<String, String> e : vs.entrySet()) { |
187 if (e.getKey().equals("art:value") || | 181 if (e.getKey().equals("art:value") || e.getKey().equals("art:label")) { |
188 e.getKey().equals("art:label")) { | |
189 continue; | 182 continue; |
190 } | 183 } |
191 List<String> data = attributes.get(e.getKey()); | 184 final List<String> data = this.attributes.get(e.getKey()); |
192 data.add(e.getValue()); | 185 data.add(e.getValue()); |
193 } | 186 } |
194 col.addValue(item.getLabel(), mi.getValue().get("art:value")); | 187 col.addValue(item.getLabel(), mi.getValue().get("art:value")); |
195 } | 188 } |
196 | 189 |
197 columnNames.add(groupTitle); | 190 this.columnNames.add(groupTitle); |
198 columns.put(groupTitle, col); | 191 this.columns.put(groupTitle, col); |
199 } | 192 } |
200 | 193 |
201 public Widget createParameterGrid() { | 194 public Widget createParameterGrid() { |
202 listGrid = new ListGrid(); | 195 this.listGrid = new ListGrid(); |
203 listGrid.setShowAllRecords(true); | 196 this.listGrid.setShowAllRecords(true); |
204 listGrid.setWrapCells(true); | 197 this.listGrid.setWrapCells(true); |
205 listGrid.setShowHeaderContextMenu(false); | 198 this.listGrid.setShowHeaderContextMenu(false); |
206 listGrid.setCanReorderFields(false); | 199 this.listGrid.setCanReorderFields(false); |
207 // listGrid.setCanSort(false); | 200 // listGrid.setCanSort(false); |
208 //listGrid.setAutoFitData(Autofit.VERTICAL); | 201 // listGrid.setAutoFitData(Autofit.VERTICAL); |
209 listGrid.setFixedRecordHeights(false); | 202 this.listGrid.setFixedRecordHeights(false); |
210 // TODO: Then also need "autofit" (when wrapping) | 203 // TODO: Then also need "autofit" (when wrapping) |
211 | 204 |
212 ListGridField itemNameField = new ListGridField("itemname", " "); | 205 final ListGridField itemNameField = new ListGridField("itemname", this.itemname); |
213 ArrayList<ListGridField> fields = new ArrayList<ListGridField>(); | 206 final ArrayList<ListGridField> fields = new ArrayList<ListGridField>(); |
214 fields.add(itemNameField); | 207 fields.add(itemNameField); |
215 | 208 |
216 for (Map.Entry<String, List<String>> entry: attributes.entrySet()) { | 209 for (final Map.Entry<String, List<String>> entry : this.attributes.entrySet()) { |
217 ListGridField attrField = new ListGridField( | 210 final ListGridField attrField = new ListGridField(entry.getKey(), this.MESSAGE.getString(entry.getKey())); |
218 entry.getKey(), MESSAGE.getString(entry.getKey())); | |
219 fields.add(attrField); | 211 fields.add(attrField); |
220 } | 212 } |
221 | 213 |
222 for (int i = 0, n = columnNames.size(); i < n; i++) { | 214 for (int i = 0, n = this.columnNames.size(); i < n; i++) { |
223 ListGridField field = new ListGridField( | 215 final ListGridField field = new ListGridField(this.columnNames.get(i), this.MESSAGE.getString(this.columnNames.get(i))); |
224 columnNames.get(i), MESSAGE.getString(columnNames.get(i))); | |
225 field.setType(ListGridFieldType.BOOLEAN); | 216 field.setType(ListGridFieldType.BOOLEAN); |
226 field.setCanEdit(true); | 217 field.setCanEdit(true); |
227 fields.add(field); | 218 fields.add(field); |
228 selected.put(columnNames.get(i), new ArrayList<String>()); | 219 this.selected.put(this.columnNames.get(i), new ArrayList<String>()); |
229 } | 220 } |
230 | 221 |
231 ListGridField[] fieldsArray = fields.toArray( | 222 final ListGridField[] fieldsArray = fields.toArray(new ListGridField[fields.size()]); |
232 new ListGridField[fields.size()]); | 223 this.listGrid.setFields(fieldsArray); |
233 listGrid.setFields(fieldsArray); | 224 |
234 | 225 final int nVals = this.valueNames.size(); |
235 int nVals = valueNames.size(); | 226 |
236 | 227 final ArrayList<ListGridRecord> records = new ArrayList<ListGridRecord>(); |
237 ArrayList<ListGridRecord> records = new ArrayList<ListGridRecord>(); | |
238 for (int j = 0; j < nVals; j++) { | 228 for (int j = 0; j < nVals; j++) { |
239 String valueName = valueNames.get(j); | 229 final String valueName = this.valueNames.get(j); |
240 ListGridRecord record = new ListGridRecord(); | 230 final ListGridRecord record = new ListGridRecord(); |
241 record.setAttribute("itemname", valueName); | 231 record.setAttribute("itemname", valueName); |
242 for (int i = 0, n = columnNames.size(); i < n; i++) { | 232 for (int i = 0, n = this.columnNames.size(); i < n; i++) { |
243 String columnName = columnNames.get(i); | 233 final String columnName = this.columnNames.get(i); |
244 Column col = columns.get(columnName); | 234 final Column col = this.columns.get(columnName); |
245 String value = col.getValue(valueName); | 235 final String value = col.getValue(valueName); |
246 record.setAttribute(columnName, false); | 236 record.setAttribute(columnName, false); |
247 record.setAttribute(columnName+"-value", value); | 237 record.setAttribute(columnName + "-value", value); |
248 } | 238 } |
249 for (Map.Entry<String, List<String>> entry: attributes.entrySet()) { | 239 for (final Map.Entry<String, List<String>> entry : this.attributes.entrySet()) { |
250 record.setAttribute(entry.getKey(), entry.getValue().get(j)); | 240 record.setAttribute(entry.getKey(), entry.getValue().get(j)); |
251 } | 241 } |
252 records.add(record); | 242 records.add(record); |
253 } | 243 } |
254 | 244 |
255 listGrid.setData(records.toArray(new ListGridRecord[records.size()])); | 245 this.listGrid.setData(records.toArray(new ListGridRecord[records.size()])); |
256 | 246 |
257 return listGrid; | 247 return this.listGrid; |
258 | 248 |
259 } | 249 } |
260 | |
261 | 250 |
262 /** | 251 /** |
263 * Returns a widget with matrix of checkboxes and labels. | 252 * Returns a widget with matrix of checkboxes and labels. |
264 * @param asListGrid if true, use a ListGrid (for inclusion in SmartGWT | 253 * |
265 * containers, avoiding scrollbar-issues. | 254 * @param asListGrid |
255 * if true, use a ListGrid (for inclusion in SmartGWT | |
256 * containers, avoiding scrollbar-issues. | |
266 */ | 257 */ |
267 public Widget create(boolean asListGrid) { | 258 public Widget create(final boolean asListGrid) { |
268 if (asListGrid) { | 259 if (asListGrid) { |
269 return createParameterGrid(); | 260 return createParameterGrid(); |
270 } | 261 } |
271 Grid grid = new Grid(valueNames.size() + 1, columnNames.size() + 1); | 262 final Grid grid = new Grid(this.valueNames.size() + 1, this.columnNames.size() + 1); |
272 | 263 |
273 for (int i = 0, n = columnNames.size(); i < n; i++) { | 264 for (int i = 0, n = this.columnNames.size(); i < n; i++) { |
274 String columnName = columnNames.get(i); | 265 final String columnName = this.columnNames.get(i); |
275 Column col = columns.get(columnName); | 266 final Column col = this.columns.get(columnName); |
276 | 267 |
277 selected.put(columnName, new ArrayList<String>()); | 268 this.selected.put(columnName, new ArrayList<String>()); |
278 | 269 |
279 grid.setWidget(0, i+1, createLabel(MESSAGE.getString(columnName))); | 270 grid.setWidget(0, i + 1, createLabel(this.MESSAGE.getString(columnName))); |
280 | 271 |
281 for (int j = 0, o = valueNames.size(); j < o; j++) { | 272 for (int j = 0, o = this.valueNames.size(); j < o; j++) { |
282 String valueName = valueNames.get(j); | 273 final String valueName = this.valueNames.get(j); |
283 String value = col.getValue(valueName); | 274 final String value = col.getValue(valueName); |
284 | 275 |
285 if (i == 0) { | 276 if (i == 0) { |
286 grid.setWidget(j+1, 0, createLabel(valueName)); | 277 grid.setWidget(j + 1, 0, createLabel(valueName)); |
287 } | 278 } |
288 | 279 |
289 if (value != null && value.length() > 0) { | 280 if (value != null && value.length() > 0) { |
290 grid.setWidget(j+1, i+1, createCheckBox(columnName, value)); | 281 grid.setWidget(j + 1, i + 1, createCheckBox(columnName, value)); |
291 } | 282 } |
292 } | 283 } |
293 } | 284 } |
294 | 285 |
295 return grid; | 286 return grid; |
296 } | 287 } |
297 | 288 |
298 | |
299 /** Creates label with given text. */ | 289 /** Creates label with given text. */ |
300 protected Label createLabel(String text) { | 290 protected Label createLabel(final String text) { |
301 Label label = new Label(text); | 291 final Label label = new Label(text); |
302 label.setHeight(CELL_HEIGHT); | 292 label.setHeight(CELL_HEIGHT); |
303 | 293 |
304 return label; | 294 return label; |
305 } | 295 } |
306 | |
307 | 296 |
308 /** Create Checkbox for column/value. */ | 297 /** Create Checkbox for column/value. */ |
309 protected Canvas createCheckBox(final String colName, final String value) { | 298 protected Canvas createCheckBox(final String colName, final String value) { |
310 CheckBox box = new CheckBox(); | 299 final CheckBox box = new CheckBox(); |
311 box.addClickHandler(new ClickHandler() { | 300 box.addClickHandler(new ClickHandler() { |
312 | 301 |
313 @Override | 302 @Override |
314 public void onClick(ClickEvent event) { | 303 public void onClick(final ClickEvent event) { |
315 Map<String, List<String>> selection = getSelection(); | 304 final Map<String, List<String>> selection = getSelection(); |
316 | 305 |
317 List<String> values = selection.get(colName); | 306 final List<String> values = selection.get(colName); |
318 if (values.indexOf(value) >= 0) { | 307 if (values.indexOf(value) >= 0) { |
319 values.remove(value); | 308 values.remove(value); |
320 } | 309 } else { |
321 else { | |
322 values.add(value); | 310 values.add(value); |
323 } | 311 } |
324 } | 312 } |
325 }); | 313 }); |
326 | 314 |
327 Canvas c = new Canvas(); | 315 final Canvas c = new Canvas(); |
328 c.addChild(box); | 316 c.addChild(box); |
329 return c; | 317 return c; |
330 } | 318 } |
331 | 319 |
332 | |
333 public Map<String, List<String>> getSelection() { | 320 public Map<String, List<String>> getSelection() { |
334 if (listGrid == null) { | 321 if (this.listGrid == null) { |
335 return selected; | 322 return this.selected; |
336 } | 323 } |
337 | 324 |
338 ListGridRecord[] records = listGrid.getRecords(); | 325 final ListGridRecord[] records = this.listGrid.getRecords(); |
339 Map<String, List<String>> result = new HashMap<String, List<String>>(); | 326 final Map<String, List<String>> result = new HashMap<String, List<String>>(); |
340 for (ListGridRecord record : records) { | 327 for (final ListGridRecord record : records) { |
341 for (int i = 0, n = columnNames.size(); i < n; i++) { | 328 for (int i = 0, n = this.columnNames.size(); i < n; i++) { |
342 String columnName = columnNames.get(i); | 329 final String columnName = this.columnNames.get(i); |
343 if (Boolean.valueOf(record.getAttribute(columnName)) == true) { | 330 if (Boolean.valueOf(record.getAttribute(columnName)) == true) { |
344 if (result.containsKey(columnName)) { | 331 if (result.containsKey(columnName)) { |
345 result.get(columnName).add( | 332 result.get(columnName).add(record.getAttribute(columnName + "-value")); |
346 record.getAttribute(columnName + "-value")); | 333 } else { |
347 } | 334 final List<String> items = new ArrayList<String>(); |
348 else { | |
349 List<String> items = new ArrayList<String>(); | |
350 items.add(record.getAttribute(columnName + "-value")); | 335 items.add(record.getAttribute(columnName + "-value")); |
351 result.put(columnName, items); | 336 result.put(columnName, items); |
352 } | 337 } |
353 } | 338 } |
354 } | 339 } |