Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Represent table relationships
5 : * Author: Nyall Dawson, <nyall dot dawson at gmail dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2022, Nyall Dawson <nyall dot dawson at gmail dot comg>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_port.h"
30 : #include "gdal.h"
31 : #include "gdal_priv.h"
32 :
33 : /**
34 : * \class GDALRelationship
35 : *
36 : * Definition of a table relationship.
37 : *
38 : * GDALRelationship describes the relationship between two tables, including
39 : * properties such as the cardinality of the relationship and the participating
40 : * tables.
41 : *
42 : * Not all relationship properties are supported by all data formats.
43 : *
44 : * @since GDAL 3.6
45 : */
46 :
47 : /************************************************************************/
48 : /* GDALRelationshipCreate() */
49 : /************************************************************************/
50 :
51 : /**
52 : * \brief Creates a new relationship.
53 : *
54 : * This function is the same as the C++ method
55 : * GDALRelationship::GDALRelationship()
56 : *
57 : * @param pszName relationship name
58 : * @param pszLeftTableName left table name
59 : * @param pszRightTableName right table name
60 : * @param eCardinality cardinality of relationship
61 : *
62 : * @return a new handle that should be freed with GDALDestroyRelationship(),
63 : * or NULL in case of error.
64 : */
65 : GDALRelationshipH
66 29 : GDALRelationshipCreate(const char *pszName, const char *pszLeftTableName,
67 : const char *pszRightTableName,
68 : GDALRelationshipCardinality eCardinality)
69 : {
70 29 : VALIDATE_POINTER1(pszName, __func__, nullptr);
71 29 : VALIDATE_POINTER1(pszLeftTableName, __func__, nullptr);
72 29 : VALIDATE_POINTER1(pszRightTableName, __func__, nullptr);
73 :
74 87 : return GDALRelationship::ToHandle(new GDALRelationship(
75 58 : pszName, pszLeftTableName, pszRightTableName, eCardinality));
76 : }
77 :
78 : /************************************************************************/
79 : /* GDALDestroyRelationship() */
80 : /************************************************************************/
81 :
82 : /**
83 : * \brief Destroys a relationship.
84 : *
85 : * This function is the same as the C++ method
86 : * GDALRelationship::~GDALRelationship()
87 : */
88 29 : void CPL_STDCALL GDALDestroyRelationship(GDALRelationshipH hRelationship)
89 : {
90 29 : if (hRelationship != nullptr)
91 29 : delete GDALRelationship::FromHandle(hRelationship);
92 29 : }
93 :
94 : /************************************************************************/
95 : /* GDALRelationshipGetName() */
96 : /************************************************************************/
97 :
98 : /**
99 : * \brief Get the name of the relationship.
100 : *
101 : * This function is the same as the C++ method
102 : * GDALRelationship::GetName().
103 : *
104 : * @return name.
105 : */
106 31 : const char *GDALRelationshipGetName(GDALRelationshipH hRelationship)
107 : {
108 31 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetName", nullptr);
109 :
110 31 : return GDALRelationship::FromHandle(hRelationship)->GetName().c_str();
111 : }
112 :
113 : /************************************************************************/
114 : /* GDALRelationshipGetCardinality() */
115 : /************************************************************************/
116 :
117 : /**
118 : * \brief Get the cardinality of the relationship.
119 : *
120 : * This function is the same as the C++ method
121 : * GDALRelationship::GetCardinality().
122 : *
123 : * @return cardinality.
124 : */
125 : GDALRelationshipCardinality
126 47 : GDALRelationshipGetCardinality(GDALRelationshipH hRelationship)
127 : {
128 47 : return GDALRelationship::FromHandle(hRelationship)->GetCardinality();
129 : }
130 :
131 : /************************************************************************/
132 : /* GDALRelationshipGetLeftTableName() */
133 : /************************************************************************/
134 :
135 : /**
136 : * \brief Get the name of the left (or base/origin) table in the relationship.
137 : *
138 : * This function is the same as the C++ method
139 : * GDALRelationship::GetLeftTableName().
140 : *
141 : * @return left table name.
142 : */
143 47 : const char *GDALRelationshipGetLeftTableName(GDALRelationshipH hRelationship)
144 : {
145 47 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetLeftTableName",
146 : nullptr);
147 :
148 : return GDALRelationship::FromHandle(hRelationship)
149 47 : ->GetLeftTableName()
150 47 : .c_str();
151 : }
152 :
153 : /************************************************************************/
154 : /* GDALRelationshipGetRightTableName() */
155 : /************************************************************************/
156 :
157 : /**
158 : * \brief Get the name of the right (or related/destination) table in the
159 : * relationship.
160 : *
161 : * This function is the same as the C++ method
162 : * GDALRelationship::GetRightTableName().
163 : *
164 : * @return right table name.
165 : */
166 47 : const char *GDALRelationshipGetRightTableName(GDALRelationshipH hRelationship)
167 : {
168 47 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetRightTableName",
169 : nullptr);
170 :
171 : return GDALRelationship::FromHandle(hRelationship)
172 47 : ->GetRightTableName()
173 47 : .c_str();
174 : }
175 :
176 : /************************************************************************/
177 : /* GDALRelationshipGetMappingTableName() */
178 : /************************************************************************/
179 :
180 : /**
181 : * \brief Get the name of the mapping table for many-to-many relationships.
182 : *
183 : * This function is the same as the C++ method
184 : * GDALRelationship::GetMappingTableName().
185 : *
186 : * @return mapping table name.
187 : *
188 : * @see GDALRelationshipSetMappingTableName
189 : */
190 32 : const char *GDALRelationshipGetMappingTableName(GDALRelationshipH hRelationship)
191 : {
192 32 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetMappingTableName",
193 : nullptr);
194 :
195 : return GDALRelationship::FromHandle(hRelationship)
196 32 : ->GetMappingTableName()
197 32 : .c_str();
198 : }
199 :
200 : /************************************************************************/
201 : /* GDALRelationshipSetMappingTableName() */
202 : /************************************************************************/
203 : /**
204 : * \brief Sets the name of the mapping table for many-to-many relationships.
205 : *
206 : * This function is the same as the CPP method
207 : * GDALRelationship::SetMappingTableName().
208 : *
209 : * @param hRelationship handle to the relationship to apply the new mapping name
210 : * to.
211 : * @param pszName the mapping table name to set.
212 : *
213 : * @see GDALRelationshipGetMappingTableName
214 : */
215 14 : void GDALRelationshipSetMappingTableName(GDALRelationshipH hRelationship,
216 : const char *pszName)
217 :
218 : {
219 14 : GDALRelationship::FromHandle(hRelationship)->SetMappingTableName(pszName);
220 14 : }
221 :
222 : /************************************************************************/
223 : /* GDALRelationshipGetLeftTableFields() */
224 : /************************************************************************/
225 :
226 : /**
227 : * \brief Get the names of the participating fields from the left table in the
228 : * relationship.
229 : *
230 : * This function is the same as the C++ method
231 : * GDALRelationship::GetLeftTableFields().
232 : *
233 : * @return the field names, to be freed with CSLDestroy()
234 : *
235 : * @see GDALRelationshipGetRightTableFields
236 : * @see GDALRelationshipSetLeftTableFields
237 : */
238 48 : char **GDALRelationshipGetLeftTableFields(GDALRelationshipH hRelationship)
239 : {
240 48 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetLeftTableFields",
241 : nullptr);
242 :
243 : const auto &fields =
244 48 : GDALRelationship::FromHandle(hRelationship)->GetLeftTableFields();
245 48 : return CPLStringList(fields).StealList();
246 : }
247 :
248 : /************************************************************************/
249 : /* GDALRelationshipGetRightTableFields() */
250 : /************************************************************************/
251 :
252 : /**
253 : * \brief Get the names of the participating fields from the right table in the
254 : * relationship.
255 : *
256 : * This function is the same as the C++ method
257 : * GDALRelationship::GetRightTableFields().
258 : *
259 : * @return the field names, to be freed with CSLDestroy()
260 : *
261 : * @see GDALRelationshipGetLeftTableFields
262 : * @see GDALRelationshipSetRightTableFields
263 : */
264 48 : char **GDALRelationshipGetRightTableFields(GDALRelationshipH hRelationship)
265 : {
266 48 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetRightTableFields",
267 : nullptr);
268 :
269 : const auto &fields =
270 48 : GDALRelationship::FromHandle(hRelationship)->GetRightTableFields();
271 48 : return CPLStringList(fields).StealList();
272 : }
273 :
274 : /************************************************************************/
275 : /* GDALRelationshipSetLeftTableFields() */
276 : /************************************************************************/
277 :
278 : /**
279 : * \brief Sets the names of the participating fields from the left table in the
280 : * relationship.
281 : *
282 : * This function is the same as the C++ method
283 : * GDALRelationship::GetLeftTableFields().
284 : *
285 : * @param hRelationship handle to the relationship to apply the left table
286 : * fields to.
287 : * @param papszFields the names of the fields.
288 : *
289 : * @see GDALRelationshipGetLeftTableFields
290 : * @see GDALRelationshipSetRightTableFields
291 : */
292 37 : void GDALRelationshipSetLeftTableFields(GDALRelationshipH hRelationship,
293 : CSLConstList papszFields)
294 : {
295 : GDALRelationship::FromHandle(hRelationship)
296 37 : ->SetLeftTableFields(cpl::ToVector(papszFields));
297 37 : }
298 :
299 : /************************************************************************/
300 : /* GDALRelationshipSetRightTableFields() */
301 : /************************************************************************/
302 :
303 : /**
304 : * \brief Sets the names of the participating fields from the right table in the
305 : * relationship.
306 : *
307 : * This function is the same as the C++ method
308 : * GDALRelationship::SetRightTableFields().
309 : *
310 : * @param hRelationship handle to the relationship to apply the right table
311 : * fields to.
312 : * @param papszFields the names of the fields.
313 : *
314 : * @see GDALRelationshipGetRightTableFields
315 : * @see GDALRelationshipSetLeftTableFields
316 : */
317 38 : void GDALRelationshipSetRightTableFields(GDALRelationshipH hRelationship,
318 : CSLConstList papszFields)
319 : {
320 : GDALRelationship::FromHandle(hRelationship)
321 38 : ->SetRightTableFields(cpl::ToVector(papszFields));
322 38 : }
323 :
324 : /************************************************************************/
325 : /* GDALRelationshipGetLeftMappingTableFields() */
326 : /************************************************************************/
327 :
328 : /**
329 : * \brief Get the names of the mapping table fields which correspond to the
330 : * participating fields from the left table in the relationship.
331 : *
332 : * This function is the same as the C++ method
333 : * GDALRelationship::GetLeftMappingTableFields().
334 : *
335 : * @return the field names, to be freed with CSLDestroy()
336 : *
337 : * @see GDALRelationshipGetRightMappingTableFields
338 : * @see GDALRelationshipSetLeftMappingTableFields
339 : */
340 : char **
341 23 : GDALRelationshipGetLeftMappingTableFields(GDALRelationshipH hRelationship)
342 : {
343 23 : VALIDATE_POINTER1(hRelationship,
344 : "GDALRelationshipGetLeftMappingTableFields", nullptr);
345 :
346 : const auto &fields = GDALRelationship::FromHandle(hRelationship)
347 23 : ->GetLeftMappingTableFields();
348 23 : return CPLStringList(fields).StealList();
349 : }
350 :
351 : /************************************************************************/
352 : /* GDALRelationshipGetRightMappingTableFields() */
353 : /************************************************************************/
354 :
355 : /**
356 : * \brief Get the names of the mapping table fields which correspond to the
357 : * participating fields from the right table in the relationship.
358 : *
359 : * This function is the same as the C++ method
360 : * GDALRelationship::GetRightMappingTableFields().
361 : *
362 : * @return the field names, to be freed with CSLDestroy()
363 : *
364 : * @see GDALRelationshipGetLeftMappingTableFields
365 : * @see GDALRelationshipSetRightMappingTableFields
366 : */
367 : char **
368 23 : GDALRelationshipGetRightMappingTableFields(GDALRelationshipH hRelationship)
369 : {
370 23 : VALIDATE_POINTER1(hRelationship,
371 : "GDALRelationshipGetRightMappingTableFields", nullptr);
372 :
373 : const auto &fields = GDALRelationship::FromHandle(hRelationship)
374 23 : ->GetRightMappingTableFields();
375 23 : return CPLStringList(fields).StealList();
376 : }
377 :
378 : /************************************************************************/
379 : /* GDALRelationshipSetLeftMappingTableFields() */
380 : /************************************************************************/
381 :
382 : /**
383 : * \brief Sets the names of the mapping table fields which correspond to the
384 : * participating fields from the left table in the relationship.
385 : *
386 : * This function is the same as the C++ method
387 : * GDALRelationship::SetLeftMappingTableFields().
388 : *
389 : * @param hRelationship handle to the relationship to apply the left table
390 : * fields to.
391 : * @param papszFields the names of the fields.
392 : *
393 : * @see GDALRelationshipGetLeftMappingTableFields
394 : * @see GDALRelationshipSetRightMappingTableFields
395 : */
396 9 : void GDALRelationshipSetLeftMappingTableFields(GDALRelationshipH hRelationship,
397 : CSLConstList papszFields)
398 : {
399 : GDALRelationship::FromHandle(hRelationship)
400 9 : ->SetLeftMappingTableFields(cpl::ToVector(papszFields));
401 9 : }
402 :
403 : /************************************************************************/
404 : /* GDALRelationshipSetRightMappingTableFields() */
405 : /************************************************************************/
406 :
407 : /**
408 : * \brief Sets the names of the mapping table fields which correspond to the
409 : * participating fields from the right table in the relationship.
410 : *
411 : * This function is the same as the C++ method
412 : * GDALRelationship::SetRightMappingTableFields().
413 : *
414 : * @param hRelationship handle to the relationship to apply the right table
415 : * fields to.
416 : * @param papszFields the names of the fields.
417 : *
418 : * @see GDALRelationshipGetRightMappingTableFields
419 : * @see GDALRelationshipSetLeftMappingTableFields
420 : */
421 9 : void GDALRelationshipSetRightMappingTableFields(GDALRelationshipH hRelationship,
422 : CSLConstList papszFields)
423 : {
424 : GDALRelationship::FromHandle(hRelationship)
425 9 : ->SetRightMappingTableFields(cpl::ToVector(papszFields));
426 9 : }
427 :
428 : /************************************************************************/
429 : /* GDALRelationshipGetType() */
430 : /************************************************************************/
431 :
432 : /**
433 : * \brief Get the type of the relationship.
434 : *
435 : * This function is the same as the C++ method
436 : * GDALRelationship::GetType().
437 : *
438 : * @return relationship type.
439 : *
440 : * @see GDALRelationshipSetType
441 : */
442 47 : GDALRelationshipType GDALRelationshipGetType(GDALRelationshipH hRelationship)
443 : {
444 47 : return GDALRelationship::FromHandle(hRelationship)->GetType();
445 : }
446 :
447 : /************************************************************************/
448 : /* GDALRelationshipSetType() */
449 : /************************************************************************/
450 :
451 : /**
452 : * \brief Sets the type of the relationship.
453 : *
454 : * This function is the same as the C++ method
455 : * GDALRelationship::SetType().
456 : *
457 : * @see GDALRelationshipGetType
458 : */
459 10 : void GDALRelationshipSetType(GDALRelationshipH hRelationship,
460 : GDALRelationshipType eType)
461 : {
462 10 : return GDALRelationship::FromHandle(hRelationship)->SetType(eType);
463 : }
464 :
465 : /************************************************************************/
466 : /* GDALRelationshipGetForwardPathLabel() */
467 : /************************************************************************/
468 :
469 : /**
470 : * \brief Get the label of the forward path for the relationship.
471 : *
472 : * This function is the same as the C++ method
473 : * GDALRelationship::GetForwardPathLabel().
474 : *
475 : * The forward and backward path labels are free-form, user-friendly strings
476 : * which can be used to generate descriptions of the relationship between
477 : * features from the right and left tables.
478 : *
479 : * E.g. when the left table contains buildings and the right table contains
480 : * furniture, the forward path label could be "contains" and the backward path
481 : * label could be "is located within". A client could then generate a
482 : * user friendly description string such as "fire hose 1234 is located within
483 : * building 15a".
484 : *
485 : * @return forward path label
486 : *
487 : * @see GDALRelationshipSetForwardPathLabel()
488 : * @see GDALRelationshipGetBackwardPathLabel()
489 : */
490 14 : const char *GDALRelationshipGetForwardPathLabel(GDALRelationshipH hRelationship)
491 : {
492 14 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetForwardPathLabel",
493 : nullptr);
494 :
495 : return GDALRelationship::FromHandle(hRelationship)
496 14 : ->GetForwardPathLabel()
497 14 : .c_str();
498 : }
499 :
500 : /************************************************************************/
501 : /* GDALRelationshipSetForwardPathLabel() */
502 : /************************************************************************/
503 : /**
504 : * \brief Sets the label of the forward path for the relationship.
505 : *
506 : * This function is the same as the CPP method
507 : * GDALRelationship::SetForwardPathLabel().
508 : *
509 : * The forward and backward path labels are free-form, user-friendly strings
510 : * which can be used to generate descriptions of the relationship between
511 : * features from the right and left tables.
512 : *
513 : * E.g. when the left table contains buildings and the right table contains
514 : * furniture, the forward path label could be "contains" and the backward path
515 : * label could be "is located within". A client could then generate a
516 : * user friendly description string such as "fire hose 1234 is located within
517 : * building 15a".
518 : *
519 : * @param hRelationship handle to the relationship to apply the new label to.
520 : * @param pszLabel the label to set.
521 : *
522 : * @see GDALRelationshipGetForwardPathLabel
523 : * @see GDALRelationshipSetBackwardPathLabel
524 : */
525 9 : void GDALRelationshipSetForwardPathLabel(GDALRelationshipH hRelationship,
526 : const char *pszLabel)
527 :
528 : {
529 9 : GDALRelationship::FromHandle(hRelationship)->SetForwardPathLabel(pszLabel);
530 9 : }
531 :
532 : /************************************************************************/
533 : /* GDALRelationshipGetForwardPathLabel() */
534 : /************************************************************************/
535 :
536 : /**
537 : * \brief Get the label of the backward path for the relationship.
538 : *
539 : * This function is the same as the C++ method
540 : * GDALRelationship::GetBackwardPathLabel().
541 : *
542 : * The forward and backward path labels are free-form, user-friendly strings
543 : * which can be used to generate descriptions of the relationship between
544 : * features from the right and left tables.
545 : *
546 : * E.g. when the left table contains buildings and the right table contains
547 : * furniture, the forward path label could be "contains" and the backward path
548 : * label could be "is located within". A client could then generate a
549 : * user friendly description string such as "fire hose 1234 is located within
550 : * building 15a".
551 : *
552 : * @return backward path label
553 : *
554 : * @see GDALRelationshipSetBackwardPathLabel()
555 : * @see GDALRelationshipGetForwardPathLabel()
556 : */
557 : const char *
558 14 : GDALRelationshipGetBackwardPathLabel(GDALRelationshipH hRelationship)
559 : {
560 14 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetBackwardPathLabel",
561 : nullptr);
562 :
563 : return GDALRelationship::FromHandle(hRelationship)
564 14 : ->GetBackwardPathLabel()
565 14 : .c_str();
566 : }
567 :
568 : /************************************************************************/
569 : /* GDALRelationshipSetBackwardPathLabel() */
570 : /************************************************************************/
571 : /**
572 : * \brief Sets the label of the backward path for the relationship.
573 : *
574 : * This function is the same as the CPP method
575 : * GDALRelationship::SetBackwardPathLabel().
576 : *
577 : * The forward and backward path labels are free-form, user-friendly strings
578 : * which can be used to generate descriptions of the relationship between
579 : * features from the right and left tables.
580 : *
581 : * E.g. when the left table contains buildings and the right table contains
582 : * furniture, the forward path label could be "contains" and the backward path
583 : * label could be "is located within". A client could then generate a
584 : * user friendly description string such as "fire hose 1234 is located within
585 : * building 15a".
586 : *
587 : * @param hRelationship handle to the relationship to apply the new label to.
588 : * @param pszLabel the label to set.
589 : *
590 : * @see GDALRelationshipGetBackwardPathLabel
591 : * @see GDALRelationshipSetForwardPathLabel
592 : */
593 9 : void GDALRelationshipSetBackwardPathLabel(GDALRelationshipH hRelationship,
594 : const char *pszLabel)
595 : {
596 9 : GDALRelationship::FromHandle(hRelationship)->SetBackwardPathLabel(pszLabel);
597 9 : }
598 :
599 : /************************************************************************/
600 : /* GDALRelationshipGetRelatedTableType() */
601 : /************************************************************************/
602 :
603 : /**
604 : * \brief Get the type string of the related table.
605 : *
606 : * This function is the same as the C++ method
607 : * GDALRelationship::GetRelatedTableType().
608 : *
609 : * This a free-form string representing the type of related features, where the
610 : * exact interpretation is format dependent. For instance, table types from
611 : * GeoPackage relationships will directly reflect the categories from the
612 : * GeoPackage related tables extension (i.e. "media", "simple attributes",
613 : * "features", "attributes" and "tiles").
614 : *
615 : * @return related table type
616 : *
617 : * @see GDALRelationshipSetRelatedTableType
618 : */
619 44 : const char *GDALRelationshipGetRelatedTableType(GDALRelationshipH hRelationship)
620 : {
621 44 : VALIDATE_POINTER1(hRelationship, "GDALRelationshipGetRelatedTableType",
622 : nullptr);
623 :
624 : return GDALRelationship::FromHandle(hRelationship)
625 44 : ->GetRelatedTableType()
626 44 : .c_str();
627 : }
628 :
629 : /************************************************************************/
630 : /* GDALRelationshipSetRelatedTableType() */
631 : /************************************************************************/
632 : /**
633 : * \brief Sets the type string of the related table.
634 : *
635 : * This function is the same as the CPP method
636 : * GDALRelationship::SetRelatedTableType().
637 : *
638 : * This a free-form string representing the type of related features, where the
639 : * exact interpretation is format dependent. For instance, table types from
640 : * GeoPackage relationships will directly reflect the categories from the
641 : * GeoPackage related tables extension (i.e. "media", "simple attributes",
642 : * "features", "attributes" and "tiles").
643 : *
644 : * @param hRelationship handle to the relationship to apply the new type to.
645 : * @param pszType the type to set.
646 : *
647 : * @see GDALRelationshipGetRelatedTableType
648 : */
649 20 : void GDALRelationshipSetRelatedTableType(GDALRelationshipH hRelationship,
650 : const char *pszType)
651 : {
652 20 : GDALRelationship::FromHandle(hRelationship)->SetRelatedTableType(pszType);
653 20 : }
|