Index: trunk/extensions/Wikidata/OmegaWiki/WikiDataGlobals.php |
— | — | @@ -92,13 +92,13 @@ |
93 | 93 | $wgSourceIdentifierAttributeName = "Source identifier"; |
94 | 94 | $wgTextAttributeAttributeName = "Property"; |
95 | 95 | $wgTextAttributeName = "Text"; |
96 | | -$wgTextAttributeValuesAttributeName = "Plain text properties"; |
| 96 | +$wgTextAttributeValuesAttributeName = "Plain texts"; |
97 | 97 | $wgTranslatedTextAttributeAttributeName = "Property"; |
98 | 98 | $wgTranslatedTextAttributeName = "Translated text"; |
99 | 99 | $wgTranslatedTextAttributeValueAttributeName = "Text"; |
100 | | -$wgTranslatedTextAttributeValuesAttributeName = "Translatable text properties"; |
| 100 | +$wgTranslatedTextAttributeValuesAttributeName = "Translatable texts"; |
101 | 101 | $wgUrlAttributeAttributeName = "Property"; |
102 | | -$wgUrlAttributeValuesAttributeName = "URL properties"; |
| 102 | +$wgUrlAttributeValuesAttributeName = "URLs"; |
103 | 103 | |
104 | 104 | // Go to source templates |
105 | 105 | |
Index: trunk/extensions/Wikidata/OmegaWiki/PropertyToColumnFilter.php |
— | — | @@ -1,14 +1,18 @@ |
2 | 2 | <?php |
3 | 3 | |
| 4 | +require_once('Attribute.php'); |
| 5 | + |
4 | 6 | class PropertyToColumnFilter { |
5 | | - public $identifier; // The identifier of the attribute that will be created |
6 | | - public $caption; // The caption of the attribute that will be created |
7 | 7 | public $attributeIDs; // Array containing the defined meaning ids of the attributes that should be filtered |
| 8 | + protected $attribute; // Attribute |
8 | 9 | |
9 | 10 | public function __construct($identifier, $caption, array $attributeIDs) { |
10 | | - $this->identifier = $identifier; |
11 | | - $this->caption = $caption; |
12 | 11 | $this->attributeIDs = $attributeIDs; |
| 12 | + $this->attribute = new Attribute($identifier, $caption, "will-be-specified-later"); |
| 13 | + } |
| 14 | + |
| 15 | + public function getAttribute() { |
| 16 | + return $this->attribute; |
13 | 17 | } |
14 | 18 | } |
15 | 19 | |
Index: trunk/extensions/Wikidata/OmegaWiki/SpecialSuggest.php |
— | — | @@ -72,7 +72,7 @@ |
73 | 73 | $sql = getSQLToSelectPossibleAttributes($objectId, $attributesLevel, 'TEXT'); |
74 | 74 | break; |
75 | 75 | case 'url-attribute': |
76 | | - $sql = getSQLToSelectPossibleAttributes($objectId, $attributesLevel, 'URL'); |
| 76 | + $sql = getSQLToSelectPossibleAttributes($objectId, $attributesLevel, 'TEXT'); |
77 | 77 | break; |
78 | 78 | case 'language': |
79 | 79 | require_once('languages.php'); |
— | — | @@ -118,6 +118,7 @@ |
119 | 119 | $query == 'option-attribute' or |
120 | 120 | $query == 'translated-text-attribute' or |
121 | 121 | $query == 'text-attribute' or |
| 122 | + $query == 'url-attribute' or |
122 | 123 | $query == 'collection') |
123 | 124 | $searchCondition = " WHERE $rowText LIKE " . $dbr->addQuotes("$search%"); |
124 | 125 | else |
— | — | @@ -231,7 +232,7 @@ |
232 | 233 | $sqlActual = getSQLToSelectPossibleAttributesForLanguage($objectId, $attributesLevel, $attributesType, $wgUser->getOption('language')); |
233 | 234 | $sqlFallback = getSQLToSelectPossibleAttributesForLanguage($objectId, $attributesLevel, $attributesType, 'en'); |
234 | 235 | |
235 | | - return constructSQLWithFallback($sqlActual, $sqlFallback, array("attribute_mid", "spelling")); |
| 236 | + return constructSQLWithFallback($sqlActual, $sqlFallback, array("attribute_mid", "spelling")); |
236 | 237 | } |
237 | 238 | |
238 | 239 | # language is the 2 letter wikimedia code. use "<ANY>" if you don't want language filtering |
Index: trunk/extensions/Wikidata/OmegaWiki/OmegaWikiAttributes.php |
— | — | @@ -311,6 +311,21 @@ |
312 | 312 | $objectAttributesStructure = new Structure("object-attributes", $objectIdAttribute, $textAttributeValuesAttribute, $translatedTextAttributeValuesAttribute, $optionAttributeValuesAttribute); |
313 | 313 | $objectAttributesAttribute->setAttributeType($objectAttributesStructure); |
314 | 314 | $definedMeaningAttributesAttribute->setAttributeType($objectAttributesStructure); |
| 315 | + |
| 316 | + $annotatedAttributes = array( |
| 317 | + $definitionAttribute, |
| 318 | + $synonymsAndTranslationsAttribute, |
| 319 | + $relationsAttribute, |
| 320 | + $reciprocalRelationsAttribute |
| 321 | + ); |
| 322 | + |
| 323 | + foreach ($viewInformation->getPropertyToColumnFilters() as $propertyToColumnFilter) { |
| 324 | + $attribute = $propertyToColumnFilter->getAttribute(); |
| 325 | + $attribute->setAttributeType($objectAttributesStructure); |
| 326 | + |
| 327 | + foreach ($annotatedAttributes as $annotatedAttribute) |
| 328 | + $annotatedAttribute->type->addAttribute($attribute); |
| 329 | + } |
315 | 330 | |
316 | 331 | global $wdDefinedMeaningAttributesOrder; |
317 | 332 | |
Index: trunk/extensions/Wikidata/OmegaWiki/RecordSet.php |
— | — | @@ -58,6 +58,10 @@ |
59 | 59 | public function add($record) { |
60 | 60 | $this->records[] = $record; |
61 | 61 | } |
| 62 | + |
| 63 | + public function remove($index) { |
| 64 | + array_splice($this->records, $index, 1); |
| 65 | + } |
62 | 66 | |
63 | 67 | public function addRecord($values) { |
64 | 68 | $record = new ArrayRecord($this->structure); |
Index: trunk/extensions/Wikidata/OmegaWiki/OmegaWikiEditors.php |
— | — | @@ -16,7 +16,6 @@ |
17 | 17 | $translatedTextValueObjectAttributesEditor, $translatedTextAttributeIdAttribute, |
18 | 18 | $optionValueObjectAttributesEditor, $optionAttributeIdAttribute, $annotationMeaningName; |
19 | 19 | |
20 | | - |
21 | 20 | $textValueObjectAttributesEditor = new RecordUnorderedListEditor($objectAttributesAttribute, 5); |
22 | 21 | $urlValueObjectAttributesEditor = new RecordUnorderedListEditor($objectAttributesAttribute, 5); |
23 | 22 | $translatedTextValueObjectAttributesEditor = new RecordUnorderedListEditor($objectAttributesAttribute, 5); |
— | — | @@ -74,8 +73,17 @@ |
75 | 74 | new DefinedMeaningFilteredDefinitionController($viewInformation->filterLanguageId), |
76 | 75 | $viewInformation |
77 | 76 | )); |
| 77 | + |
| 78 | + foreach ($viewInformation->getPropertyToColumnFilters() as $propertyToColumnFilter) { |
| 79 | + $attribute = $propertyToColumnFilter->getAttribute(); |
| 80 | + $editor->addEditor(new PopUpEditor( |
| 81 | + createDefinitionObjectAttributesEditor($viewInformation, $attribute, $definedMeaningIdAttribute, 0, $definitionMeaningName), |
| 82 | + $attribute->name |
| 83 | + )); |
| 84 | + } |
| 85 | + |
78 | 86 | $editor->addEditor(new PopUpEditor( |
79 | | - createObjectAttributesEditor($viewInformation, $objectAttributesAttribute, $definedMeaningIdAttribute, 0, $definitionMeaningName), |
| 87 | + createDefinitionObjectAttributesEditor($viewInformation, $objectAttributesAttribute, $definedMeaningIdAttribute, 0, $definitionMeaningName), |
80 | 88 | $wgPopupAnnotationName |
81 | 89 | )); |
82 | 90 | |
— | — | @@ -125,6 +133,23 @@ |
126 | 134 | return $result; |
127 | 135 | } |
128 | 136 | |
| 137 | +function createDefinitionObjectAttributesEditor(ViewInformation $viewInformation, Attribute $attribute, Attribute $idAttribute, $levelsFromDefinedMeaning, $levelName) { |
| 138 | + global |
| 139 | + $objectAttributesAttribute, $definedMeaningIdAttribute; |
| 140 | + |
| 141 | + $result = new RecordUnorderedListEditor($attribute, 5); |
| 142 | + |
| 143 | + setObjectAttributesEditor( |
| 144 | + $result, |
| 145 | + $viewInformation, |
| 146 | + new DefinitionObjectIdFetcher(0, $idAttribute), |
| 147 | + $levelName, |
| 148 | + new ObjectIdFetcher($levelsFromDefinedMeaning, $definedMeaningIdAttribute) |
| 149 | + ); |
| 150 | + |
| 151 | + return $result; |
| 152 | +} |
| 153 | + |
129 | 154 | function getAlternativeDefinitionsEditor(ViewInformation $viewInformation) { |
130 | 155 | global |
131 | 156 | $alternativeDefinitionsAttribute, $alternativeDefinitionAttribute, $sourceAttribute; |
Index: trunk/extensions/Wikidata/OmegaWiki/OmegaWikiRecordSets.php |
— | — | @@ -522,20 +522,29 @@ |
523 | 523 | $definitionId = getDefinedMeaningDefinitionId($definedMeaningId); |
524 | 524 | $record = new ArrayRecord(new Structure($definitionAttribute)); |
525 | 525 | $record->setAttributeValue($translatedTextAttribute, getTranslatedContentValue($definitionId, $viewInformation)); |
526 | | - $record->setAttributeValue($objectAttributesAttribute, getObjectAttributesRecord($definitionId, $viewInformation, $objectAttributesAttribute->id)); |
| 526 | + |
| 527 | + $objectAttributesRecord = getObjectAttributesRecord($definitionId, $viewInformation, $objectAttributesAttribute->id); |
| 528 | + $record->setAttributeValue($objectAttributesAttribute, $objectAttributesRecord); |
| 529 | + |
| 530 | + foreach ($viewInformation->getPropertyToColumnFilters() as $propertyToColumnFilter) { |
| 531 | + $record->setAttributeValue( |
| 532 | + $propertyToColumnFilter->getAttribute(), |
| 533 | + filterObjectAttributesRecord($objectAttributesRecord, $propertyToColumnFilter->attributeIDs) |
| 534 | + ); |
| 535 | + } |
527 | 536 | |
528 | 537 | return $record; |
529 | 538 | } |
530 | 539 | |
531 | 540 | function getObjectAttributesRecord($objectId, ViewInformation $viewInformation, $structuralOverride = null) { |
532 | 541 | global |
533 | | - $objectAttributesAttribute, $objectIdAttribute, |
| 542 | + $objectIdAttribute, |
534 | 543 | $urlAttributeValuesAttribute, $textAttributeValuesAttribute, |
535 | 544 | $translatedTextAttributeValuesAttribute, $optionAttributeValuesAttribute, |
536 | 545 | $definedMeaningAttributesAttribute; |
537 | 546 | |
538 | 547 | if ($structuralOverride) |
539 | | - $record = new ArrayRecord(new Structure($structuralOverride,$definedMeaningAttributesAttribute)); |
| 548 | + $record = new ArrayRecord(new Structure($structuralOverride, $definedMeaningAttributesAttribute)); |
540 | 549 | else |
541 | 550 | $record = new ArrayRecord(new Structure($definedMeaningAttributesAttribute)); |
542 | 551 | |
— | — | @@ -548,6 +557,65 @@ |
549 | 558 | return $record; |
550 | 559 | } |
551 | 560 | |
| 561 | +function filterAttributeValues(RecordSet $sourceRecordSet, Attribute $attributeAttribute, array &$attributeIds) { |
| 562 | + global |
| 563 | + $definedMeaningIdAttribute; |
| 564 | + |
| 565 | + $result = new ArrayRecordSet($sourceRecordSet->getStructure(), $sourceRecordSet->getKey()); |
| 566 | + $i = 0; |
| 567 | + |
| 568 | + while ($i < $sourceRecordSet->getRecordCount()) { |
| 569 | + $record = $sourceRecordSet->getRecord($i); |
| 570 | + |
| 571 | + if (in_array($record->getAttributeValue($attributeAttribute)->getAttributeValue($definedMeaningIdAttribute), $attributeIds)) { |
| 572 | + $result->add($record); |
| 573 | + $sourceRecordSet->remove($i); |
| 574 | + } |
| 575 | + else |
| 576 | + $i++; |
| 577 | + } |
| 578 | + |
| 579 | + return $result; |
| 580 | +} |
| 581 | + |
| 582 | +function filterObjectAttributesRecord(Record $sourceRecord, array &$attributeIds) { |
| 583 | + global |
| 584 | + $definedMeaningAttributesAttribute, $objectIdAttribute, |
| 585 | + $textAttributeValuesAttribute, $textAttributeAttribute, |
| 586 | + $translatedTextAttributeAttribute, $translatedTextAttributeValuesAttribute, |
| 587 | + $urlAttributeAttribute, $urlAttributeValuesAttribute, |
| 588 | + $optionAttributeAttribute, $optionAttributeValuesAttribute; |
| 589 | + |
| 590 | + $result = new ArrayRecord(new Structure($definedMeaningAttributesAttribute)); |
| 591 | + $result->setAttributeValue($objectIdAttribute, $sourceRecord->getAttributeValue($objectIdAttribute)); |
| 592 | + |
| 593 | + $result->setAttributeValue($textAttributeValuesAttribute, filterAttributeValues( |
| 594 | + $sourceRecord->getAttributeValue($textAttributeValuesAttribute), |
| 595 | + $textAttributeAttribute, |
| 596 | + $attributeIds |
| 597 | + )); |
| 598 | + |
| 599 | + $result->setAttributeValue($translatedTextAttributeValuesAttribute, filterAttributeValues( |
| 600 | + $sourceRecord->getAttributeValue($translatedTextAttributeValuesAttribute), |
| 601 | + $translatedTextAttributeAttribute, |
| 602 | + $attributeIds |
| 603 | + )); |
| 604 | + |
| 605 | + $result->setAttributeValue($urlAttributeValuesAttribute, filterAttributeValues( |
| 606 | + $sourceRecord->getAttributeValue($urlAttributeValuesAttribute), |
| 607 | + $urlAttributeAttribute, |
| 608 | + $attributeIds |
| 609 | + )); |
| 610 | + |
| 611 | + $result->setAttributeValue($optionAttributeValuesAttribute, filterAttributeValues( |
| 612 | + $sourceRecord->getAttributeValue($optionAttributeValuesAttribute), |
| 613 | + $optionAttributeAttribute, |
| 614 | + $attributeIds |
| 615 | + )); |
| 616 | + |
| 617 | + return $result; |
| 618 | +} |
| 619 | + |
552 | 620 | function getTranslatedContentValue($translatedContentId, ViewInformation $viewInformation) { |
553 | 621 | global |
554 | 622 | $textAttribute; |
— | — | @@ -648,22 +716,22 @@ |
649 | 717 | expandExpressionReferencesInRecordSet($recordSet, array($expressionAttribute)); |
650 | 718 | else |
651 | 719 | expandExpressionSpellingsInRecordSet($recordSet, array($expressionAttribute)); |
652 | | - //add object attributes attribute to the generated structure |
653 | | - //and expand the records |
654 | | - $recordSet->getStructure()->addAttribute($objectAttributesAttribute); |
655 | | - expandObjectAttributesAttribute($recordSet, $syntransIdAttribute, $viewInformation); |
| 720 | + |
| 721 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $syntransIdAttribute, $viewInformation); |
656 | 722 | return $recordSet; |
657 | 723 | } |
658 | 724 | |
659 | | -function expandObjectAttributesAttribute(RecordSet $recordSet, Attribute $objectIdAttribute, ViewInformation $viewInformation) { |
| 725 | +function expandObjectAttributesAttribute(RecordSet $recordSet, Attribute $attributeToExpand, Attribute $objectIdAttribute, ViewInformation $viewInformation) { |
660 | 726 | global |
661 | | - $objectAttributesAttribute, |
662 | 727 | $textAttributeObjectAttribute, $textAttributeValuesAttribute, |
663 | 728 | $translatedTextAttributeObjectAttribute, $translatedTextAttributeValuesAttribute, |
664 | 729 | $urlAttributeObjectAttribute, $urlAttributeValuesAttribute, |
665 | 730 | $optionAttributeObjectAttribute, $optionAttributeValuesAttribute; |
666 | 731 | |
667 | | - $objectAttributesRecordStructure = $objectAttributesAttribute->type; |
| 732 | + $recordSetStructure = $recordSet->getStructure(); |
| 733 | + $recordSetStructure->addAttribute($attributeToExpand); |
| 734 | + |
| 735 | + $objectAttributesRecordStructure = $attributeToExpand->type; |
668 | 736 | $objectIds = getUniqueIdsInRecordSet($recordSet, array($objectIdAttribute)); |
669 | 737 | |
670 | 738 | if (count($objectIds) > 0) { |
— | — | @@ -750,7 +818,7 @@ |
751 | 819 | $objectAttributesRecord->setAttributeValue($urlAttributeValuesAttribute, $urlAttributeValuesRecordSet); |
752 | 820 | $objectAttributesRecord->setAttributeValue($optionAttributeValuesAttribute, $optionAttributeValuesRecordSet); |
753 | 821 | |
754 | | - $record->setAttributeValue($objectAttributesAttribute, $objectAttributesRecord); |
| 822 | + $record->setAttributeValue($attributeToExpand, $objectAttributesRecord); |
755 | 823 | } |
756 | 824 | } |
757 | 825 | } |
— | — | @@ -794,12 +862,7 @@ |
795 | 863 | ); |
796 | 864 | |
797 | 865 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($relationTypeAttribute, $otherDefinedMeaningAttribute)); |
798 | | - |
799 | | - //add object attributes attribute to the generated structure |
800 | | - //and expand the records |
801 | | - $struct=$recordSet->getStructure(); |
802 | | - $struct->addAttribute($objectAttributesAttribute); |
803 | | - expandObjectAttributesAttribute($recordSet, $relationIdAttribute, $viewInformation); |
| 866 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $relationIdAttribute, $viewInformation); |
804 | 867 | |
805 | 868 | return $recordSet; |
806 | 869 | } |
— | — | @@ -825,12 +888,7 @@ |
826 | 889 | ); |
827 | 890 | |
828 | 891 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($relationTypeAttribute, $otherDefinedMeaningAttribute)); |
829 | | - |
830 | | - //add object attributes attribute to the generated structure |
831 | | - //and expand the records |
832 | | - $struct=$recordSet->getStructure(); |
833 | | - $struct->addAttribute($objectAttributesAttribute); |
834 | | - expandObjectAttributesAttribute($recordSet, $relationIdAttribute, $viewInformation); |
| 892 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $relationIdAttribute, $viewInformation); |
835 | 893 | |
836 | 894 | return $recordSet; |
837 | 895 | } |
— | — | @@ -857,12 +915,7 @@ |
858 | 916 | ); |
859 | 917 | |
860 | 918 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($possibleSynonymAttribute)); |
861 | | - |
862 | | - //add object attributes attribute to the generated structure |
863 | | - //and expand the records |
864 | | - $struct=$recordSet->getStructure(); |
865 | | - $struct->addAttribute($objectAttributesAttribute); |
866 | | - expandObjectAttributesAttribute($recordSet, $possiblySynonymousIdAttribute, $viewInformation); |
| 919 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $possiblySynonymousIdAttribute, $viewInformation); |
867 | 920 | |
868 | 921 | return $recordSet; |
869 | 922 | } |
— | — | @@ -929,11 +982,7 @@ |
930 | 983 | ); |
931 | 984 | |
932 | 985 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($textAttributeAttribute)); |
933 | | - |
934 | | - //add object attributes attribute to the generated structure |
935 | | - //and expand the records |
936 | | - $recordSet->getStructure()->addAttribute($objectAttributesAttribute); |
937 | | - expandObjectAttributesAttribute($recordSet, $textAttributeIdAttribute, $viewInformation); |
| 986 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $textAttributeIdAttribute, $viewInformation); |
938 | 987 | |
939 | 988 | return $recordSet; |
940 | 989 | } |
— | — | @@ -959,11 +1008,7 @@ |
960 | 1009 | ); |
961 | 1010 | |
962 | 1011 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($urlAttributeAttribute)); |
963 | | - |
964 | | - //add object attributes attribute to the generated structure |
965 | | - //and expand the records |
966 | | - $recordSet->getStructure()->addAttribute($objectAttributesAttribute); |
967 | | - expandObjectAttributesAttribute($recordSet, $urlAttributeIdAttribute, $viewInformation); |
| 1012 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $urlAttributeIdAttribute, $viewInformation); |
968 | 1013 | |
969 | 1014 | return $recordSet; |
970 | 1015 | } |
— | — | @@ -992,11 +1037,7 @@ |
993 | 1038 | |
994 | 1039 | expandTranslatedContentsInRecordSet($recordSet, $translatedTextValueIdAttribute, $translatedTextValueAttribute, $viewInformation); |
995 | 1040 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($translatedTextAttributeAttribute)); |
996 | | - |
997 | | - //add object attributes attribute to the generated structure |
998 | | - //and expand the records |
999 | | - $recordSet->getStructure()->addAttribute($objectAttributesAttribute); |
1000 | | - expandObjectAttributesAttribute($recordSet, $translatedTextAttributeIdAttribute, $viewInformation); |
| 1041 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $translatedTextAttributeIdAttribute, $viewInformation); |
1001 | 1042 | return $recordSet; |
1002 | 1043 | } |
1003 | 1044 | |
— | — | @@ -1043,12 +1084,8 @@ |
1044 | 1085 | |
1045 | 1086 | expandOptionsInRecordSet($recordSet, $viewInformation); |
1046 | 1087 | expandDefinedMeaningReferencesInRecordSet($recordSet, array($optionAttributeAttribute, $optionAttributeOptionAttribute)); |
| 1088 | + expandObjectAttributesAttribute($recordSet, $objectAttributesAttribute, $optionAttributeIdAttribute, $viewInformation); |
1047 | 1089 | |
1048 | | - /* Add object attributes attribute to the generated structure |
1049 | | - and expand the records. */ |
1050 | | - $recordSet->getStructure()->addAttribute($objectAttributesAttribute); |
1051 | | - expandObjectAttributesAttribute($recordSet, $optionAttributeIdAttribute, $viewInformation); |
1052 | | - |
1053 | 1090 | return $recordSet; |
1054 | 1091 | } |
1055 | 1092 | |
Index: trunk/extensions/Wikidata/OmegaWiki/ViewInformation.php |
— | — | @@ -24,6 +24,7 @@ |
25 | 25 | $this->possiblySynonymousRelationTypeId = 0; |
26 | 26 | $this->queryTransactionInformation; |
27 | 27 | $this->showRecordLifeSpan = false; |
| 28 | + $this->propertyToColumnFilters = array(); |
28 | 29 | } |
29 | 30 | |
30 | 31 | public function hasMetaDataAttributes() { |
— | — | @@ -37,6 +38,10 @@ |
38 | 39 | public function setPropertyToColumnFilters(array $propertyToColumnFilters) { |
39 | 40 | $this->propertyToColumnFilters = $propertyToColumnFilters; |
40 | 41 | } |
| 42 | + |
| 43 | + public function getPropertyToColumnFilters() { |
| 44 | + return $this->propertyToColumnFilters; |
| 45 | + } |
41 | 46 | } |
42 | 47 | |
43 | 48 | ?> |