Fix sonar issue cli codegen
[policy/apex-pdp.git] / auth / cli-codegen / src / main / java / org / onap / policy / apex / auth / clicodegen / CodeGeneratorCliEditor.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.auth.clicodegen;
22
23 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.ALBUM_NAME;
24 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.ALBUM_VERSION;
25 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.CONTEXT_REFS;
26 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.CTX_REFS;
27 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.DECLARATION;
28 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.DEFAULT_TASK;
29 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.DEFAULT_TASK_VERSION;
30 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.DEFAULT_VALUE;
31 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.DEFINITIONS;
32 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.DESCRIPTION;
33 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.EVENT_NAME;
34 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.EVENT_VERSION;
35 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FIELDS;
36 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FIELD_NAME;
37 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FIELD_SCHEMA;
38 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FIELD_SCHEMA_VERSION;
39 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FINALIZER_LOGICS;
40 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FINALIZER_LOGIC_NAME;
41 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FIRST_STATE;
42 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.FLAVOUR;
43 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.INFIELDS;
44 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.LOGIC;
45 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.LOGIC_FLAVOUR;
46 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.NAME;
47 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.NAME_SPACE;
48 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.NEXT_STATE;
49 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.OPTIONAL;
50 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.OUTFIELDS;
51 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.OUTPUTS;
52 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.OUTPUT_NAME;
53 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.OUTPUT_TYPE;
54 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.PARAMS;
55 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.PAR_NAME;
56 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.POLICY_NAME;
57 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.SCHEMA;
58 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.SCHEMA_NAME;
59 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.SCHEMA_VERSION;
60 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.SCOPE;
61 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.SOURCE;
62 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.STATES;
63 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.STATE_NAME;
64 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TARGET;
65 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TASKS;
66 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TASK_LOCAL_NAME;
67 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TASK_NAME;
68 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TASK_VERSION;
69 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TEMPLATE;
70 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TRIGGER_NAME;
71 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TRIGGER_VERSION;
72 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.TS_LOGIC;
73 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.UUID;
74 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.VERSION;
75 import static org.onap.policy.apex.auth.clicodegen.CliEditorContants.WRITABLE;
76
77 import java.util.List;
78
79 import org.stringtemplate.v4.ST;
80 import org.stringtemplate.v4.STGroupFile;
81
82 /**
83  * Code generator generating expressions for the APEX CLI Editor.
84  *
85  * @author Sven van der Meer (sven.van.der.meer@ericsson.com)
86  */
87 public class CodeGeneratorCliEditor {
88
89     // CHECKSTYLE:OFF: ParameterNumber
90
91     /**
92      * The name of the STG file for the code generator.
93      */
94     public static final String STG_FILE = "org/onap/policy/apex/auth/clicodegen/cli-editor.stg";
95
96     /**
97      * The String Template Group, taken from the context.
98      */
99     private final STGroupFile stg;
100
101     /**
102      * The ST for the model, loaded from the STG.
103      */
104     private final ST model;
105
106     /**
107      * A default name space, set from specification.
108      */
109     private String defaultNamespace;
110
111     /**
112      * Creates a new code generator.
113      */
114     public CodeGeneratorCliEditor() {
115         stg = new STGroupFile(STG_FILE);
116         stg.registerRenderer(String.class, new CgStringRenderer(), true);
117         model = stg.getInstanceOf("policyModel");
118     }
119
120     /**
121      * Adds model parameters to the template.
122      *
123      * @param name the name of the mode, must not be blank
124      * @param version a version, can be null
125      * @param uuid a UUID, can be null
126      * @param description a description, must not be blank
127      */
128     public void addModelParams(final String name, final String version, final String uuid, final String description) {
129         if (name == null || name.isEmpty()) {
130             throw new IllegalArgumentException("model name should not be blank");
131         }
132         if (description == null || description.isEmpty()) {
133             throw new IllegalArgumentException("model description should not be blank");
134         }
135
136         model.add(NAME, name);
137         model.add(VERSION, version);
138         model.add(UUID, uuid);
139         model.add(DESCRIPTION, description);
140     }
141
142     /**
143      * Returns the model.
144      *
145      * @return the model
146      */
147     public ST getModel() {
148         return model;
149     }
150
151     /**
152      * Sets the default name space.
153      *
154      * @param nameSpace new name space, ignored if blank
155      */
156     public void setDefaultNamespace(final String nameSpace) {
157         if (nameSpace != null && !nameSpace.isEmpty()) {
158             defaultNamespace = nameSpace;
159         }
160     }
161
162     /**
163      * Adds a new schema declaration to the model.
164      *
165      * @param name the name of the schema
166      * @param version the version of the declaration
167      * @param uuid the UUID for the declaration
168      * @param description a description of the schema
169      * @param flavour the flavour of the schema declaration, e.g. Java or Avro
170      * @param schema the actual schema declaration, either a string or as <code>LS schema LE</code>
171      */
172     public void addSchemaDeclaration(final String name, final String version, final String uuid,
173             final String description, final String flavour, final String schema) {
174         final ST st = stg.getInstanceOf("schemaDecl");
175         st.add(NAME, name);
176         st.add(VERSION, version);
177         st.add(UUID, uuid);
178         st.add(DESCRIPTION, description);
179         st.add(FLAVOUR, flavour);
180         st.add(SCHEMA, schema);
181         model.add(DECLARATION, st);
182     }
183
184     /**
185      * Adds a new context album declaration to the model.
186      *
187      * @param codeGenCliEditorBuilder The parameters for the context album
188      */
189     public void addContextAlbumDeclaration(CodeGenCliEditorBuilder codeGenCliEditorBuilder) {
190         final ST st = stg.getInstanceOf("ctxAlbumDecl");
191         st.add(NAME, codeGenCliEditorBuilder.getName());
192         st.add(VERSION, codeGenCliEditorBuilder.getVersion());
193         st.add(UUID, codeGenCliEditorBuilder.getUuid());
194         st.add(DESCRIPTION, codeGenCliEditorBuilder.getDescription());
195         st.add(SCOPE, codeGenCliEditorBuilder.getScope());
196         st.add(WRITABLE, codeGenCliEditorBuilder.isWritable());
197         st.add(SCHEMA_NAME, codeGenCliEditorBuilder.getSchemaName());
198         st.add(SCHEMA_VERSION, codeGenCliEditorBuilder.getSchemaVersion());
199         model.add(DECLARATION, st);
200     }
201
202     /**
203      * Creates a new event field definition which belongs to an event.
204      *
205      * @param eventName the event name
206      * @param version the event version
207      * @param fieldName the name for the field in the event
208      * @param fieldSchema the schema of the field
209      * @param fieldSchemaVersion the version of the schema
210      * @param optional a flag for optional fields
211      * @return a CLI command for event field definition
212      */
213     public ST createEventFieldDefinition(final String eventName, final String version, final String fieldName,
214             final String fieldSchema, final String fieldSchemaVersion, final boolean optional) {
215         final ST st = stg.getInstanceOf("eventDefField");
216         st.add(EVENT_NAME, eventName);
217         st.add(VERSION, version);
218         st.add(FIELD_NAME, fieldName);
219         st.add(FIELD_SCHEMA, fieldSchema);
220         st.add(FIELD_SCHEMA_VERSION, fieldSchemaVersion);
221         st.add(OPTIONAL, optional);
222         return st;
223     }
224
225     /**
226      * Creates a new task logic definition which belongs to a task.
227      *
228      * @param taskName the name of the task
229      * @param version the task version
230      * @param flavour the flavour, e.g. JAVA or JAVASCRIPT
231      * @param logic the actual logic (use either a string or a multi-line with <code>LS some code LE</code>
232      * @return a CLI command for task definition, logic
233      */
234     public ST createTaskDefLogic(final String taskName, final String version, final String flavour,
235             final String logic) {
236         final ST st = stg.getInstanceOf("taskDefLogic");
237         st.add(TASK_NAME, taskName);
238         st.add(VERSION, version);
239         st.add(FLAVOUR, flavour);
240         st.add(LOGIC, logic);
241         return st;
242     }
243
244     /**
245      * Adds a new event declaration to the model.
246      *
247      * @param eventDeclarationBuilder param object for event declaration
248      */
249     public void addEventDeclaration(EventDeclarationBuilder eventDeclarationBuilder) {
250         final ST st = stg.getInstanceOf("eventDecl");
251         st.add(NAME, eventDeclarationBuilder.getName());
252         st.add(VERSION, eventDeclarationBuilder.getVersion());
253         st.add(UUID, eventDeclarationBuilder.getUuid());
254         st.add(DESCRIPTION, eventDeclarationBuilder.getDescription());
255         st.add(SOURCE, eventDeclarationBuilder.getSource());
256         st.add(TARGET, eventDeclarationBuilder.getTarget());
257         st.add(FIELDS, eventDeclarationBuilder.getFields());
258
259         if (eventDeclarationBuilder.getNameSpace() != null) {
260             st.add(NAME_SPACE, eventDeclarationBuilder.getNameSpace());
261         } else if (defaultNamespace != null) {
262             st.add(NAME_SPACE, defaultNamespace);
263         }
264
265         model.add(DECLARATION, st);
266     }
267
268     /**
269      * Adds a new task declaration to the model.
270      *
271      * @param name the name of the task
272      * @param version the version of the task
273      * @param uuid a UUID for the definition
274      * @param description a description of the task
275      * @param infields all infields for the task
276      * @param outfields all outfields for the task
277      * @param logic the logic for the task
278      * @param parameters any task parameter
279      * @param contextRefs any context reference
280      */
281     public void addTaskDeclaration(final String name, final String version, final String uuid, final String description,
282             final List<ST> infields, final List<ST> outfields, final ST logic, final List<ST> parameters,
283             final List<ST> contextRefs) {
284         final ST st = stg.getInstanceOf("taskDecl");
285         st.add(NAME, name);
286         st.add(VERSION, version);
287         st.add(UUID, uuid);
288         st.add(DESCRIPTION, description);
289         st.add(INFIELDS, infields);
290         st.add(OUTFIELDS, outfields);
291         st.add(LOGIC, logic);
292         st.add(PARAMS, parameters);
293         st.add(CONTEXT_REFS, contextRefs);
294         model.add(DECLARATION, st);
295     }
296
297     /**
298      * Adds a new policy definition to the model.
299      *
300      * @param name the name of the policy
301      * @param version the version of the policy
302      * @param uuid a UUID for the definition
303      * @param description a description of the policy
304      * @param template the template type for this policy
305      * @param firstState the first state of the policy
306      * @param states all policy states
307      */
308     public void addPolicyDefinition(final String name, final String version, final String uuid,
309             final String description, final String template, final String firstState, final List<ST> states) {
310         final ST st = stg.getInstanceOf("policyDef");
311         st.add(NAME, name);
312         st.add(VERSION, version);
313         st.add(UUID, uuid);
314         st.add(DESCRIPTION, description);
315         st.add(TEMPLATE, template);
316         st.add(FIRST_STATE, firstState);
317         st.add(STATES, states);
318         model.add(DEFINITIONS, st);
319     }
320
321     /**
322      * Creates a new task infield definition.
323      *
324      * @param taskName the name of the task
325      * @param version the version of the task
326      * @param fieldName the name of the infield
327      * @param fieldSchema the schema for the infield
328      * @param fieldSchemaVersion the version of the schema
329      * @return a CLI command for task infield definition
330      */
331     public ST createTaskDefinitionInfields(final String taskName, final String version, final String fieldName,
332             final String fieldSchema, final String fieldSchemaVersion) {
333         final ST st = stg.getInstanceOf("taskDefInputFields");
334         st.add(TASK_NAME, taskName);
335         st.add(VERSION, version);
336         st.add(FIELD_NAME, fieldName);
337         st.add(FIELD_SCHEMA, fieldSchema);
338         st.add(FIELD_SCHEMA_VERSION, fieldSchemaVersion);
339         return st;
340     }
341
342     /**
343      * Creates a new task outfield definition.
344      *
345      * @param taskName the name of the task
346      * @param version the version of the task
347      * @param fieldName the name of the outfield
348      * @param fieldSchema the schema for the outfield
349      * @param fieldSchemaVersion the version of the schema
350      * @return a CLI command for task outfield definition
351      */
352     public ST createTaskDefinitionOutfields(final String taskName, final String version, final String fieldName,
353             final String fieldSchema, final String fieldSchemaVersion) {
354         final ST st = stg.getInstanceOf("taskDefOutputFields");
355         st.add(TASK_NAME, taskName);
356         st.add(VERSION, version);
357         st.add(FIELD_NAME, fieldName);
358         st.add(FIELD_SCHEMA, fieldSchema);
359         st.add(FIELD_SCHEMA_VERSION, fieldSchemaVersion);
360         return st;
361     }
362
363     /**
364      * Creates a new task parameter definition belonging to a task.
365      *
366      * @param name the name of the task
367      * @param version the version of the task
368      * @param parName the parameter name
369      * @param defaultValue a default value for the parameter
370      * @return a CLI command for a task parameter definition
371      */
372     public ST createTaskDefinitionParameters(final String name, final String version, final String parName,
373             final String defaultValue) {
374         final ST st = stg.getInstanceOf("taskDefParameter");
375         st.add(NAME, name);
376         st.add(VERSION, version);
377         st.add(PAR_NAME, parName);
378         st.add(DEFAULT_VALUE, defaultValue);
379         return st;
380     }
381
382     /**
383      * Creates a new task definition context reference which belongs to a task.
384      *
385      * @param name the name of the task
386      * @param version the version of the task
387      * @param albumName the name of the context album
388      * @param albumVersion the version of the context album
389      * @return a CLI command for a task context reference definition
390      */
391     public ST createTaskDefinitionContextRef(final String name, final String version, final String albumName,
392             final String albumVersion) {
393         final ST st = stg.getInstanceOf("taskDefCtxRef");
394         st.add(NAME, name);
395         st.add(VERSION, version);
396         st.add(ALBUM_NAME, albumName);
397         st.add(ALBUM_VERSION, albumVersion);
398         return st;
399     }
400
401     /**
402      * Creates a new policy state task definition for a task which belongs to a state which belongs to a policy.
403      *
404      * @param policyName the name of the policy
405      * @param version the version of the policy
406      * @param stateName the name of the new state
407      * @param taskLocalName the local (in policy and state) name of the task
408      * @param taskName the identifier of the task (previously defined as a task)
409      * @param taskVersion the version of the task definition
410      * @param outputType the output type
411      * @param outputName the output name
412      * @return a CLI command for a policy state task definition
413      */
414     public ST createPolicyStateTask(final String policyName, final String version, final String stateName,
415             final String taskLocalName, final String taskName, final String taskVersion,
416             final String outputType, final String outputName) {
417         final ST st = stg.getInstanceOf("policyStateTask");
418         st.add(POLICY_NAME, policyName);
419         st.add(VERSION, version);
420         st.add(STATE_NAME, stateName);
421         st.add(TASK_LOCAL_NAME, taskLocalName);
422         st.add(TASK_NAME, taskName);
423         st.add(TASK_VERSION, taskVersion);
424         st.add(OUTPUT_TYPE, outputType);
425         st.add(OUTPUT_NAME, outputName);
426         return st;
427     }
428
429     /**
430      * Creates a new policy state output definition for a state which belongs to a policy.
431      *
432      * @param policyName the name of the policy
433      * @param version the version of the policy
434      * @param stateName the name of the new state
435      * @param outputName the name of the new output
436      * @param eventName the event name for the output
437      * @param eventVersion the version of the event for the output
438      * @param nextState the next state if any
439      * @return a CLI command for a state output definition
440      */
441     public ST createPolicyStateOutput(final String policyName, final String version, final String stateName,
442             final String outputName, final String eventName, final String eventVersion,
443             final String nextState) {
444         final ST st = stg.getInstanceOf("policyStateOutput");
445         st.add(POLICY_NAME, policyName);
446         st.add(VERSION, version);
447         st.add(STATE_NAME, stateName);
448         st.add(OUTPUT_NAME, outputName);
449         st.add(EVENT_NAME, eventName);
450         st.add(EVENT_VERSION, eventVersion);
451         st.add(NEXT_STATE, nextState);
452         return st;
453     }
454
455     /**
456      * Creates a new policy state definition for a state which belongs to a policy.
457      *
458      * @param policyName the name of the policy
459      * @param version the version of the policy
460      * @param stateName the name of the new state
461      * @param triggerName the name of the trigger event
462      * @param triggerVersion the version of the trigger event
463      * @param defaultTask the identifier of the default task
464      * @param defaultTaskVersion the version of the default task
465      * @param outputs the output definitions of the state
466      * @param tasks the task definition of the state
467      * @param tsLogic the task selection logic of the state
468      * @param finalizerLogics the finalizer logics for the state
469      * @param ctxRefs any context reference for the state
470      * @return a CLI command for a policy state definition
471      */
472     public ST createPolicyStateDef(final String policyName, final String version, final String stateName,
473             final String triggerName, final String triggerVersion, final String defaultTask,
474             final String defaultTaskVersion, final List<ST> outputs, final List<ST> tasks,
475             final List<ST> tsLogic, final List<ST> finalizerLogics, final List<ST> ctxRefs) {
476         final ST st = stg.getInstanceOf("policyStateDef");
477         st.add(POLICY_NAME, policyName);
478         st.add(VERSION, version);
479         st.add(STATE_NAME, stateName);
480         st.add(TRIGGER_NAME, triggerName);
481         st.add(TRIGGER_VERSION, triggerVersion);
482         st.add(DEFAULT_TASK, defaultTask);
483         st.add(DEFAULT_TASK_VERSION, defaultTaskVersion);
484         st.add(OUTPUTS, outputs);
485         st.add(TASKS, tasks);
486         st.add(TS_LOGIC, tsLogic);
487         st.add(FINALIZER_LOGICS, finalizerLogics);
488         st.add(CTX_REFS, ctxRefs);
489         return st;
490     }
491
492     /**
493      * Creates a new task selection logic definition for a state which belongs to a policy.
494      *
495      * @param name the name of the policy
496      * @param version the version of the policy
497      * @param stateName the name of the state
498      * @param logicFlavour the flavour, e.g. JAVA or JAVASCRIPT
499      * @param logic the actual logic (use either a string or a multi-line with <code>LS some code LE</code>
500      * @return a CLI command for task selection logic definition
501      */
502     public ST createPolicyStateDefTaskSelLogic(final String name, final String version, final String stateName,
503             final String logicFlavour, final String logic) {
504         final ST st = stg.getInstanceOf("policyStateTaskSelectionLogic");
505         st.add(NAME, name);
506         st.add(VERSION, version);
507         st.add(STATE_NAME, stateName);
508         st.add(LOGIC_FLAVOUR, logicFlavour);
509         st.add(LOGIC, logic);
510         return st;
511     }
512
513     /**
514      * Creates a new state finalizer definition for a state which belongs to a policy.
515      *
516      * @param name the name of the policy
517      * @param version the version of the policy
518      * @param stateName the name of the state
519      * @param finalizerLogicName name of the finalizer logic
520      * @param logicFlavour the flavour, e.g. JAVA or JAVASCRIPT
521      * @param logic the actual logic (use either a string or a multi-line with <code>LS some code LE</code>
522      * @return a CLI command for finalizer definition
523      */
524     public ST createPolicyStateDefFinalizerLogic(final String name, final String version, final String stateName,
525             final String finalizerLogicName, final String logicFlavour, final String logic) {
526         final ST st = stg.getInstanceOf("policyStateFinalizerLogic");
527         st.add(NAME, name);
528         st.add(VERSION, version);
529         st.add(STATE_NAME, stateName);
530         st.add(FINALIZER_LOGIC_NAME, finalizerLogicName);
531         st.add(LOGIC_FLAVOUR, logicFlavour);
532         st.add(LOGIC, logic);
533         return st;
534     }
535
536     /**
537      * Creates a new policy state context reference for a state which belongs to a policy.
538      *
539      * @param name the name of the policy
540      * @param version the version of the policy
541      * @param stateName the name of the state
542      * @param albumName the name of the album
543      * @param albumVersion the version of the album
544      * @return a CLI command for state context reference
545      */
546     public ST createPolicyStateDefContextRef(final String name, final String version, final String stateName,
547             final String albumName, final String albumVersion) {
548         final ST st = stg.getInstanceOf("policyStateContextRef");
549         st.add(NAME, name);
550         st.add(VERSION, version);
551         st.add(STATE_NAME, stateName);
552         st.add(ALBUM_NAME, albumName);
553         st.add(ALBUM_VERSION, albumVersion);
554         return st;
555     }
556
557 }