333 lines
18 KiB
PHP
333 lines
18 KiB
PHP
|
<?PHP
|
||
|
/**
|
||
|
* Parser for JSON generated from XML generated by the export function of Faust.
|
||
|
* Tried and tested for exports for the Stiftung Haendelhaus Halle.
|
||
|
*
|
||
|
* @author Stefan Rohde-Enslin <s.rohde-enslin@museum-digital.de>
|
||
|
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||
|
*/
|
||
|
declare(strict_types = 1);
|
||
|
|
||
|
/**
|
||
|
* Parse function.
|
||
|
*
|
||
|
* @param array<mixed> $version Instance to import into.
|
||
|
* @param integer $institution_id Institution to import to.
|
||
|
* @param non-empty-string $XMLFolder Folder of the XML files to import.
|
||
|
* @param string $dataFolder Data folder.
|
||
|
* @param integer $sammlung_id Collection ID. Optional.
|
||
|
* @param boolean $visibility Import objects to be directly visible?.
|
||
|
* @param boolean $insertOnly If set to true, only new objects are added,
|
||
|
* old are not updated.
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
function parseImportXML(array $version, int $institution_id, string $XMLFolder, string $dataFolder = "", int $sammlung_id = 0, bool $visibility = false, bool $insertOnly = false) {
|
||
|
|
||
|
if (!is_dir(MD_IMPORTER_CONF::$import_dir_xml . "{$XMLFolder}")) throw new MDFileDoesNotExist("The folder to import from ($XMLFolder) does not exist.");
|
||
|
|
||
|
if (empty($dataFolder)) {
|
||
|
$importImages = false;
|
||
|
}
|
||
|
else $importImages = true;
|
||
|
|
||
|
// Set up writers
|
||
|
|
||
|
$collectionWriter = new MDCollectionWriter($version['mainDB']);
|
||
|
$literatureWriter = new MDLiteratureWriter($version['mainDB']);
|
||
|
$linkWriter = new MDLinkWriter($version['mainDB']);
|
||
|
$seriesWriter = new MDSeriesWriter($version['mainDB']);
|
||
|
$exhibitionWriter = new MDExhibitionWriter($version['mainDB']);
|
||
|
$objectRecordWriter = new MDObjectRecordWriter($version['mainDB']);
|
||
|
$tagWriter = new MDTagWriter($version['nodaDB']);
|
||
|
$resourceWriter = new MDResourceWriter($version['mainDB']);
|
||
|
|
||
|
$outputHandler = new MDOutputHandler;
|
||
|
$outputHandler->setVerbosity(2);
|
||
|
|
||
|
$objectWriter = new MDObjectWriter($version['mainDB'], $version['nodaDB'], $version['link'], $version['filepath'], $version['dataFolderLink']);
|
||
|
|
||
|
$startCounter = 0;
|
||
|
$iCounter = 0;
|
||
|
|
||
|
foreach (MD_STD::scandir(MD_IMPORTER_CONF::$import_dir_xml . "{$XMLFolder}") as $xmlFile) {
|
||
|
|
||
|
if ($iCounter < $startCounter) {
|
||
|
++$iCounter;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (pathinfo($xmlFile, PATHINFO_EXTENSION) !== "json") continue;
|
||
|
|
||
|
$outputHandler->toLog("Attempting to load JSON file {$xmlFile}", 2);
|
||
|
|
||
|
$rawData = MD_STD::file_get_contents(MD_IMPORTER_CONF::$import_dir_xml . "{$XMLFolder}/{$xmlFile}");
|
||
|
$rawData = str_replace('\u0096', '-', $rawData);
|
||
|
$rawData = str_replace('\u0092', "'", $rawData);
|
||
|
$rawData = str_replace('\u0091', "'", $rawData);
|
||
|
$rawData = str_replace('\u0094', '"', $rawData);
|
||
|
$rawData = str_replace('\u0093', '"', $rawData);
|
||
|
$rawData = str_replace('\u0084', '"', $rawData);
|
||
|
$objectData = json_decode($rawData, true);
|
||
|
//print_r($rawData);
|
||
|
//print_r($objectData);
|
||
|
|
||
|
if (empty($objectData['Signatur'])) $objectData['Signatur'] = '[' . $objectData["IMDAS_ID"] . ']';
|
||
|
|
||
|
$outputHandler->toLog("Successfully loaded XML file {$xmlFile} (Object: {$objectData['Signatur']})", 2);
|
||
|
|
||
|
// Handle contents
|
||
|
|
||
|
// Object base data
|
||
|
|
||
|
$objektart = "";
|
||
|
if (isset($objectData['Objektart']) and $objectData['Objektart'] != 'ERSATZ') $objektart = trim(MD_STD::preg_replace_str('/<[^>]*>/i', '', $objectData['Objektart']));
|
||
|
else $objektart = 'KEINE ANGABE IM IMPORT';
|
||
|
unset($objectData['Objektart']);
|
||
|
|
||
|
$obj_nam = $objectData['Objekttitel'];
|
||
|
|
||
|
if (empty($obj_nam)) $obj_nam = $objektart;
|
||
|
|
||
|
$objektbeschreibung = $objectData['Beschreibung'];
|
||
|
if (!empty($objectData['K_x129x_nstlersignatur_x032x__x040x_nach_x032x_Vorlage_x041x_'])) $objektbeschreibung = $objektbeschreibung . "\n\nSignatur: " . $objectData['K_x129x_nstlersignatur_x032x__x040x_nach_x032x_Vorlage_x041x_'];
|
||
|
if (!empty($objectData['Aufschrift_x032x__x040x_nach_x032x_Vorlage_x041x_'])) $objektbeschreibung = $objektbeschreibung . "\n\nBeschriftung: " . $objectData['Aufschrift_x032x__x040x_nach_x032x_Vorlage_x041x_'];
|
||
|
if (!empty($objectData['Wasserzeichen'])) $objektbeschreibung = $objektbeschreibung . "\n\nWasserzeichen: " . $objectData['Wasserzeichen'];
|
||
|
if (!empty($objectData['Quelle_x032x__x040x_Graphik_x032x_entnommen_x032x_aus_x041x_'])) $objektbeschreibung = $objektbeschreibung . "\n\nQuelle: " . $objectData['Quelle_x032x__x040x_Graphik_x032x_entnommen_x032x_aus_x041x_'];
|
||
|
|
||
|
$objektbeschreibung = str_replace("\[W9]\\", "\n", (string)$objektbeschreibung);
|
||
|
if (!$objektbeschreibung) $objektbeschreibung = 'Ein beschreibender Text war im Import nicht enthalten';
|
||
|
|
||
|
//echo PHP_EOL;print_r($objectData['Signatur']);echo PHP_EOL;
|
||
|
//echo PHP_EOL;print_r($objektart);echo PHP_EOL;
|
||
|
//echo PHP_EOL;print_r($obj_nam);echo PHP_EOL;
|
||
|
|
||
|
unset($objectData['Beschreibung'], $objectData['K_x129x_nstlersignatur_x032x__x040x_nach_x032x_Vorlage_x041x_'], $objectData['Aufschrift_x032x__x040x_nach_x032x_Vorlage_x041x_'], $objectData['Provenienz_x047x_Herkunft'], $objectData['Wasserzeichen'], $objectData['Quelle_x032x__x040x_Graphik_x032x_entnommen_x032x_aus_x041x_']);
|
||
|
|
||
|
$object = new MDObject($version['mainDB'], $version['nodaDB'], $version['language'], $institution_id, $objectData['Signatur'], $objektart, $obj_nam, $objektbeschreibung, $outputHandler);
|
||
|
unset($objectData['Signatur']);
|
||
|
|
||
|
if (!empty($objectData['Zustandsbeschreibung']) and $objectData['Zustandsbeschreibung'] != "ERSATZ") {
|
||
|
if (mb_strlen($objectData['Zustandsbeschreibung']) < 200) $object->set_string("zustand", $objectData['Zustandsbeschreibung']);
|
||
|
else $object->set_string("restaurierung", $objectData['Zustandsbeschreibung']);
|
||
|
}
|
||
|
if (!empty($objectData['Provenienz_x047x_Herkunft']) and $objectData['Provenienz_x047x_Herkunft'] != "ERSATZ") $object->set_string("objektgeschichte", $objectData['Provenienz_x047x_Herkunft']);
|
||
|
if (!empty($objectData['Literatur_x032x__x040x_Freitext_x041x_']) and $objectData['Literatur_x032x__x040x_Freitext_x041x_'] != "ERSATZ") {
|
||
|
if (is_array($objectData['Literatur_x032x__x040x_Freitext_x041x_'])) $object->set_string("notizen_text1", implode('PHP_EOL', $objectData['Literatur_x032x__x040x_Freitext_x041x_']));
|
||
|
else $object->set_string("notizen_text1", $objectData['Literatur_x032x__x040x_Freitext_x041x_']);
|
||
|
}
|
||
|
|
||
|
if (!empty($objectData['Literatur_x032x__x040x_Freitext_x041x_'])) {
|
||
|
if (is_array($objectData['Literatur_x032x__x040x_Freitext_x041x_'])) {
|
||
|
foreach ($objectData['Literatur_x032x__x040x_Freitext_x041x_'] as $litEntryName) {
|
||
|
if (substr($litEntryName, 0, 10) === 'Sasse 1962') $object->appendLiteratureByID(273);
|
||
|
else if (substr($litEntryName, 0, 10) === 'Sasse 1964') $object->appendLiteratureByID(436);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (substr($objectData['Literatur_x032x__x040x_Freitext_x041x_'], 0, 10) === 'Sasse 1962') $object->appendLiteratureByID(273);
|
||
|
else if (substr($objectData['Literatur_x032x__x040x_Freitext_x041x_'], 0, 10) === 'Sasse 1964') $object->appendLiteratureByID(436);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
unset($objectData['Zustandsbeschreibung'], $objectData['Provenienz_x047x_Herkunft'], $objectData['Literatur_x032x__x040x_Freitext_x041x_']);
|
||
|
|
||
|
/*
|
||
|
* Logic: Get collection name from either COLL_OBJ -> Bereich or COLL_OBJ -> Sammlung
|
||
|
* Attention: COLL_OBJ -> Sammlung might be an array
|
||
|
*/
|
||
|
if ($sammlung_id !== 0) {
|
||
|
$object->appendCollectionByID($sammlung_id);
|
||
|
}
|
||
|
else {
|
||
|
if (!empty($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_']) and !is_array($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_']) and $objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_'] != 'ERSATZ') {
|
||
|
$object->appendCollectionByName($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_'], "", $collectionWriter);
|
||
|
}
|
||
|
else if (!empty($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_']) and is_array($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_'])) {
|
||
|
foreach ($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_'] as $value) {
|
||
|
$object->appendCollectionByName($value, "", $collectionWriter);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
unset($objectData['Sammlung_x032x__x040x_geh_x148x_rt_x032x_zu_x041x_']);
|
||
|
|
||
|
/**/
|
||
|
if (!empty($objectData["Material_x047x_Technik"]) and $objectData["Material_x047x_Technik"] != "ERSATZ") $object->set_objekt_material_technik($objectData["Material_x047x_Technik"]);
|
||
|
if (!empty($objectData["Umfang_x047x_Format"]) and $objectData["Umfang_x047x_Format"] != "ERSATZ") $object->set_objekt_masse($objectData["Umfang_x047x_Format"]);
|
||
|
if (!empty($objectData['aktueller_x032x_Standort']) and $objectData['aktueller_x032x_Standort'] != "ERSATZ") {
|
||
|
if (is_array($objectData['aktueller_x032x_Standort'])) {
|
||
|
$object->set_string("standort_aktuell", implode("; ", $objectData['aktueller_x032x_Standort']));
|
||
|
}
|
||
|
else $object->set_string("standort_aktuell", $objectData['aktueller_x032x_Standort']);
|
||
|
}
|
||
|
unset($objectData['aktueller_x032x_Standort']);
|
||
|
|
||
|
/*
|
||
|
* Events
|
||
|
*/
|
||
|
|
||
|
$eventsConcordance = [
|
||
|
'verlegt' => 3,
|
||
|
'Vorlage erstellt' => 4,
|
||
|
'wurde abgebildet' => 5,
|
||
|
'gemalt' => 9,
|
||
|
'Druckplatte hergestellt' => 12,
|
||
|
'gezeichnet' => 19,
|
||
|
'gedruckt' => 26,
|
||
|
'modelliert' => 31,
|
||
|
];
|
||
|
|
||
|
if (!empty($objectData['Ereignis-Block']) and empty($objectData['Ereignis-Block'][0])) $objectData['Ereignis-Block'] = [$objectData['Ereignis-Block']];
|
||
|
|
||
|
/*
|
||
|
* Duplicate events in case of multiple actors or places
|
||
|
*/
|
||
|
|
||
|
if (!isset($objectData['Ereignis-Block'])) $objectData['Ereignis-Block'] = [];
|
||
|
|
||
|
// Duplicate event in case of multiple actors
|
||
|
foreach ($objectData['Ereignis-Block'] as $ix => $tEvent) {
|
||
|
|
||
|
if (empty($tEvent['Ereignis-Typ'])) {
|
||
|
unset($objectData['Ereignis-Block'][$ix]);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!empty($tEvent['wer_x063x__x032x__x040x_Ereignis_x041x_'])
|
||
|
and is_array($tEvent['wer_x063x__x032x__x040x_Ereignis_x041x_'])
|
||
|
) {
|
||
|
$copyEvent = $tEvent;
|
||
|
$copyEvent['wer_x063x__x032x__x040x_Ereignis_x041x_'] = $copyEvent['wer_x063x__x032x__x040x_Ereignis_x041x_'][1];
|
||
|
$objectData['Ereignis-Block'][$ix]['wer_x063x__x032x__x040x_Ereignis_x041x_'] = $objectData['Ereignis-Block'][$ix]['wer_x063x__x032x__x040x_Ereignis_x041x_'][0];
|
||
|
$copyEvent['GND_x032x_Person_x032x__x040x_Ereignis_x041x_'] = $copyEvent['GND_x032x_Person_x032x__x040x_Ereignis_x041x_'][1];
|
||
|
$objectData['Ereignis-Block'][$ix]['GND_x032x_Person_x032x__x040x_Ereignis_x041x_'] = $objectData['Ereignis-Block'][$ix]['GND_x032x_Person_x032x__x040x_Ereignis_x041x_'][0];
|
||
|
$objectData['Ereignis-Block'][] = $copyEvent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Duplicate event in case of multiple places
|
||
|
foreach ($objectData['Ereignis-Block'] as $ix => $tEvent) {
|
||
|
if (!empty($tEvent['wo_x063x__x032x__x040x_Ereignis_x041x_'])
|
||
|
and is_array($tEvent['wo_x063x__x032x__x040x_Ereignis_x041x_'])
|
||
|
) {
|
||
|
$copyEvent = $tEvent;
|
||
|
$copyEvent['wo_x063x__x032x__x040x_Ereignis_x041x_'] = $copyEvent['wo_x063x__x032x__x040x_Ereignis_x041x_'][1];
|
||
|
$objectData['Ereignis-Block'][$ix]['wo_x063x__x032x__x040x_Ereignis_x041x_'] = $objectData['Ereignis-Block'][$ix]['wo_x063x__x032x__x040x_Ereignis_x041x_'][0];
|
||
|
$objectData['Ereignis-Block'][] = $copyEvent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach ($objectData['Ereignis-Block'] as $ix => $tEvent) {
|
||
|
|
||
|
if (!isset($eventsConcordance[$tEvent['Ereignis-Typ']])) {
|
||
|
throw new Exception("Unknown event type: '{$tEvent['Ereignis-Typ']}'");
|
||
|
}
|
||
|
|
||
|
$event = new MDEvent($version['mainDB'], $version['nodaDB'], $version['language'], $eventsConcordance[$tEvent['Ereignis-Typ']], $outputHandler);
|
||
|
|
||
|
if (!empty($objectData['Ereignis-Block'][$ix]['GND_x032x_Person_x032x__x040x_Ereignis_x041x_'])) {
|
||
|
$event->set_persinst_id($objectData['Ereignis-Block'][$ix]['wer_x063x__x032x__x040x_Ereignis_x041x_'], "", "", $objectData['Ereignis-Block'][$ix]['GND_x032x_Person_x032x__x040x_Ereignis_x041x_']);
|
||
|
}
|
||
|
else if (!empty($objectData['Ereignis-Block'][$ix]['wer_x063x__x032x__x040x_Ereignis_x041x_'])) $event->set_persinst_id($objectData['Ereignis-Block'][$ix]['wer_x063x__x032x__x040x_Ereignis_x041x_']);
|
||
|
if (!empty($objectData['Ereignis-Block'][$ix]['wann_x063x__x032x__x040x_Ereignis_x041x_'])) $event->set_zeiten_id($objectData['Ereignis-Block'][$ix]['wann_x063x__x032x__x040x_Ereignis_x041x_']);
|
||
|
|
||
|
if (!empty($objectData['Ereignis-Block'][$ix]['wo_x063x__x032x__x040x_Ereignis_x041x_'])) $event->set_orte_id($objectData['Ereignis-Block'][$ix]['wo_x063x__x032x__x040x_Ereignis_x041x_']);
|
||
|
$object->appendEvent($event);
|
||
|
|
||
|
unset($objectData['Ereignis-Block'][$ix]['Ereignis-Typ'], $objectData['Ereignis-Block'][$ix]['wer_x063x__x032x__x040x_Ereignis_x041x_'], $objectData['Ereignis-Block'][$ix]['GND_x032x_Person_x032x__x040x_Ereignis_x041x_'], $objectData['Ereignis-Block'][$ix]['wann_x063x__x032x__x040x_Ereignis_x041x_'], $objectData['Ereignis-Block'][$ix]['wo_x063x__x032x__x040x_Ereignis_x041x_']);
|
||
|
if (empty($objectData['Ereignis-Block'][$ix])) unset ($objectData['Ereignis-Block'][$ix]);
|
||
|
|
||
|
}
|
||
|
if (empty($objectData['Ereignis-Block'])) unset ($objectData['Ereignis-Block']);
|
||
|
|
||
|
/*
|
||
|
* Tags
|
||
|
*/
|
||
|
if (!empty($objectData['Sachschlagwort'])) {
|
||
|
foreach ($objectData['Sachschlagwort'] as $tTag) {
|
||
|
$object->appendTagByName($tTag, "", $tagWriter);
|
||
|
}
|
||
|
unset($objectData['Sachschlagwort']);
|
||
|
}
|
||
|
|
||
|
if ($importImages === true) {
|
||
|
|
||
|
// Images, Vorderseite
|
||
|
$objectData["Dateiname_x032x_Vorderseite"] = str_replace("/", "-", $objectData["Dateiname_x032x_Vorderseite"]) . ".jpg";
|
||
|
if (!file_exists(MD_IMPORTER_CONF::$import_dir_files . $dataFolder . "/" . $objectData["Dateiname_x032x_Vorderseite"])) {
|
||
|
|
||
|
/*
|
||
|
$imageNameFound = false;
|
||
|
if ($imageNameFound === false) {
|
||
|
}
|
||
|
*/
|
||
|
unset($objectData["Dateiname_x032x_Vorderseite"]);
|
||
|
//continue;
|
||
|
}
|
||
|
else {
|
||
|
$image = new MDImage($version['mainDB'], (string)$object->get_string("objekt_name"), MD_IMPORTER_CONF::$import_dir_files . $dataFolder . "/" . $objectData["Dateiname_x032x_Vorderseite"]);
|
||
|
$image->set_image_owner("Stiftung Händelhaus, Halle");
|
||
|
$image->set_visible(true);
|
||
|
$image->set_main_image(true);
|
||
|
$image->set_image_rights("CC BY-NC-SA");
|
||
|
$object->appendImage($image);
|
||
|
}
|
||
|
|
||
|
unset($objectData["Dateiname_x032x_Vorderseite"], $image);
|
||
|
|
||
|
// Images, Rückseite
|
||
|
$objectData["Dateiname_x032x_R_x129x_ckseite"] = str_replace("/", "-", $objectData["Dateiname_x032x_R_x129x_ckseite"]) . ".jpg";
|
||
|
if (!file_exists(MD_IMPORTER_CONF::$import_dir_files . $dataFolder . "/" . $objectData["Dateiname_x032x_R_x129x_ckseite"])) {
|
||
|
/*
|
||
|
$imageNameFound = false;
|
||
|
|
||
|
if ($imageNameFound === false) {
|
||
|
unset($objectData["Dateiname_x032x_R_x129x_ckseite"]);
|
||
|
//continue;
|
||
|
}
|
||
|
*/
|
||
|
} else {
|
||
|
$image = new MDImage($version['mainDB'], (string)$object->get_string("objekt_name"), MD_IMPORTER_CONF::$import_dir_files . $dataFolder . "/" . $objectData["Dateiname_x032x_R_x129x_ckseite"]);
|
||
|
$image->set_image_owner("Stiftung Händelhaus, Halle");
|
||
|
$image->set_visible(true);
|
||
|
$image->set_main_image(false);
|
||
|
$image->set_image_rights("CC BY-NC-SA");
|
||
|
$object->appendImage($image);
|
||
|
}
|
||
|
unset($objectData["Dateiname_x032x_R_x129x_ckseite"], $image);
|
||
|
|
||
|
}
|
||
|
|
||
|
unset($objectData["Inventar-Nummer"], $objectData["Objekttitel"],
|
||
|
$objectData['Maler_x047x_Zeichner'],
|
||
|
$objectData['GND_x032x_Maler_x047x_Zeichner'],
|
||
|
$objectData["Ersteller_x032x_der_x032x_Druckplatte"],
|
||
|
$objectData["GND_x032x_Ersteller_x032x_der_x032x_Druckplatte"],
|
||
|
$objectData["Bildhauer_x047x_Graveur"],
|
||
|
$objectData["GND_x032x_Bildhauer_x047x_Graveur"],
|
||
|
$objectData["Ersteller_x032x_der_x032x_Vorlage"],
|
||
|
$objectData["GND_x032x_Ersteller_x032x_der_x032x_Vorlage"], $objectData["Dargestellte_x032x_Person"], $objectData["GND_x032x_dargestellte_x032x_Person"], $objectData["Datierung"], $objectData["Datierung_x032x_textuell"], $objectData["Material_x047x_Technik"], $objectData["Umfang_x047x_Format"], $objectData["Fotos"], $objectData["Fotosammlung_x032x_Positiv"], $objectData["Fotosammlung_x032x_Negativ"], $objectData["Erfassung"], $objectData["Korrektur"], $objectData["Verleger"], $objectData["GND_x032x_Verleger"], $objectData["Ort"], $objectData["Bemerkungen"], $objectData["Restaurierung"], $objectData["Objektsch_x132x_tzung"], $objectData["Fotosammlung_x032x_Dia"]);
|
||
|
|
||
|
foreach ($objectData as $key => $value) {
|
||
|
if ($value === "ERSATZ") unset($objectData[$key]);
|
||
|
}
|
||
|
/*
|
||
|
* Write it!
|
||
|
*/
|
||
|
|
||
|
$object->set_objekt_publik($visibility);
|
||
|
$newObjectID = $objectWriter->writeObject($object, true, $insertOnly, $outputHandler);
|
||
|
|
||
|
if (!empty($objectData)) {
|
||
|
throw new MDParserIncomplete(var_export($objectData, true));
|
||
|
}
|
||
|
|
||
|
$outputHandler->toLog("Done with object $iCounter", 2);
|
||
|
++$iCounter;
|
||
|
|
||
|
// Sleep for a millisecond
|
||
|
usleep(IMPORTER_DELAY_PER_OBJECT);
|
||
|
}
|
||
|
|
||
|
}
|