• We are currently performing site maintenance, parts of civfanatics are currently offline, but will come back online in the coming days (this includes any time you see the message "account suspended"). For more updates please see here.

Quick Modding Questions Thread

I'm trying to get the plot feature but having trouble using the following.

local iUnitX, iUnitY = pUnit:GetX(), pUnit:GetY()
local pUnitPlot = Map.GetPlot(iUnitX, iUnitY)
local pUnitPlotTerrain = pUnitPlot:GetTerrainType()
local pUnitPlotFeature = pUnitPlot:GetFeatureType()
local fFeature = GameInfo.Features[pUnitPlotFeatureID].FeatureType

pUnitPlotFeature returns a numeric value but fFeature won't give the FeatureType. This method works fine for terrain types and I assumed it would work for features as well. any suggestions?
 
Code:
pUnitPlotFeature != pUnitPlotFeatureID
You are asking lua to find the row within table <Features> which corresponds to an ID number that is a nil value. This can never happen.
Code:
local pPlot = Map.GetPlot(iUnitX, iUnitY)
if (pPlot ~= nil) then
     local iFeatureType = pPlot:GetFeatureType()
     local sFeatureType = "NONE"
     if (iFeatureType ~= -1) then
          --the plot has a FeatureType registered within xml table <Features>
          sFeatureType = GameInfo.Features[iFeatureType].FeatureType
     end
     print("The unit's plot feature type is " .. sFeatureType)
else
     print("The Unit's XY location retrieved an invalid result for a plot object")
end
 
Hi, I am new to the forum and trying to make my first mod. I am currently unable to load the mod in game. I think one of the issues is linked to the database where I am unable to load my ModifierId in my Modifiers table. I have uploaded a zip file with the mod and the logs. Thank you.
 

Attachments

By looking at several mods I figured out, that in order to use an OwnerRequirementSetId (owner of the modifier what the modifier instance is attached to) I don't need to use LeaderTraits or CivilizationTraits ... So I switched from TraitModifiers to ImprovementModifiers as the final goal is to reduce (for the human player) food from mined plots (resourceless, strategic & luxury resources, but not bonus resources). So far:

Code:
INSERT INTO ImprovementModifiers (ImprovementType, ModifierId)
VALUES ("IMPROVEMENT_MINE", "MACERATE_MINE_JJ");

INSERT INTO Modifiers (ModifierId, ModifierType, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES ("MACERATE_MINE_JJ", "MODIFIER_SINGLE_PLOT_ADJUST_PLOT_YIELDS", "PLAYER_IS_HUMAN", "PLOT_HAS_REQUIREMENTS_JJ");

INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ("MACERATE_MINE_JJ", "Amount", -1),
       ("MACERATE_MINE_JJ", "YieldType", "YIELD_FOOD");


INSERT INTO RequirementSets (RequirementSetId, RequirementSetType)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "REQUIREMENTSET_TEST_ALL");

INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "RESOURCE_REQUIREMENT_JJ");


INSERT INTO Requirements (RequirementId, RequirementType)
VALUES ("RESOURCE_REQUIREMENT_JJ", "REQUIREMENT_PLOT_RESOURCE_TYPE_MATCHES");

INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("RESOURCE_REQUIREMENT_JJ", "ResourceType", SELECT ResourceType FROM Resource_ValidTerrains
                                                   WHERE TerrainType IN ("TERRAIN_GRASS", "TERRAIN_GRASS_HILLS", "TERRAIN_PLAINS",
                                                                         "TERRAIN_PLAINS_HILLS", "TERRAIN_TUNDRA", "TERRAIN_TUNDRA_HILLS")
                                                   AND ResourceType != "RESOURCE_COPPER");

But how can I integrate the resourceless mines into this? Would be ResourceType = "RESOURCE_NONE", but as I understand it, that is not part of the Resource_ValidTerrains table?!?

.
 
But how can I integrate the resourceless mines into this? Would be ResourceType = "RESOURCE_NONE", but as I understand it, that is not part of the Resource_ValidTerrains table?!?
You can set things up to remove 1 food from all mines, and then create a second modifier that gives +1 food to all mines on bonus resources.
 
  • Like
Reactions: cvb
Hi, I am new to the forum and trying to make my first mod. I am currently unable to load the mod in game. I think one of the issues is linked to the database where I am unable to load my ModifierId in my Modifiers table. I have uploaded a zip file with the mod and the logs. Thank you.
This isn't really a question appropriate for a Quick Questions / Answers thread, but
  1. You cannot create your own EffectType
    Code:
    INSERT INTO	Types
    		(Type,											Kind			)
    VALUES	('TRAIT_CIVILIZATION_CROSSROADS_OF_GLOABL_TRADE',			'KIND_TRAIT'	),
    		('MODIFIER_SG_SETTLER_DISABLED',			'KIND_MODIFIER'	),
    		('MODIFIER_SG_ADJUST_FOUND_CITY_ABILITY',			'KIND_MODIFIER'	),
    		('EFFECT_SG_ADJUST_FOUND_CITY_ABILITY',			'KIND_EFFECT'	);
    EffectTypes are all specifically coded at the game DLL software level and are not exposed to modding.
  2. Regardless of the previous, this is a syntax error:
    Code:
    INSERT INTO	GameEffectArguments
    		(Type,									Name,					Description,	ArgumentType, 	Required					)
    VALUES	('EFFECT_SG_ADJUST_FOUND_CITY_ABILITY',	'CanFoundCities',		'Prevents founding of cities by major civ',	boolean	, 0	);
    boolean in the quoted snippet will be interpreted as a column-name, not a value. Hence this error:
    Code:
    [3879517.263] [Gameplay] ERROR: no such column: Boolean
    The error takes out everything else farther-down in the Civilization_UA.sql file
  3. No mod should ever be writing to table GameEffectArguments
  4. Table DynamicModifiers is OK to use to create a new ModifierType if there is not one that serves one's needs, but all argument values given for columns CollectionType and EffectType must use collections or effect-types already provided by Firaxis since all of these are directly defined and coded within the game's inaccessible DLL code.
  5. You have a mis-spelled column-name here
    Code:
    INSERT INTO Districts	
    		(DistrictType,	Name,	PrereqTech,		PrereqCivic,	Coast, Description, Cost,	RequiresPlacement,	RequiresPopulation,		NoAdjacentCity,	CityCenter, Aqueduct,InternalOnly,ZOC,FreeEmbark,HitPoints,CaptureRemovesBuildings,CaptureRemovesCityDefenses,PlunderType,PlunderAmount,TradeEmbark,MilitaryDomain,CostProgressionModel,CostProgessionParam1,TraitType,Appeal,Housing,Entertainment,OnePerCity,AllowsHolyCity,Maintenance,AirSlots,CitizenSlots,TravelTime,CityStrengthModifier,AdjacentToLand,CanAttack,AdvisorType,CaptureRemovesDistrict,MaxPerPlayer)
    VALUES  ('DISTRICT_TKB_HDB_ESTATE', 'LOC_DISTRICT_TKB_HDB_ESTATE_NAME', NULL, 'CIVIC_URBANIZATION', 0, 'LOC_DISTRICT_TKB_HDB_ESTATE_DESCRIPTION', 27, 1, 0, 0, 0, 0,0,1,0,0,0,'PLUNDER_GOLD',50,0,'NO_DOMAIN','COST_PROGRESSION_GAME_PROGRESS',1000,'TRAIT_CIVILIZATION_TKB_HDB_ESTATE',0,10,3,0,0,0,0,NULL,-1,-2,0,0,'ADVISOR_GENERIC',0,-1.0);
    Which is being reported here
    Code:
    [3879517.264] [Gameplay] ERROR: table Districts has no column named CostProgessionParam1
    This is another fatal syntax error and causes the game to cease reading anything further within file Civilization_UI.sql
    • The correct spelling of the column is "CostProgressionParam1"
    • You are missing an 'r'
  6. This is a syntax error also since it terminates with a comma , instead of a semi-colon ;
    Code:
    INSERT INTO	CityNames
    		(CivilizationType,				LeaderType,				SortIndex,	CityName						)
    VALUES	('CIVILIZATION_TKB_SINGAPORE',	'LEADER_TKB_LKY',	-1,			'LOC_CITY_NAME_TKB_SINGAPORE_1'		),
    So you end up with a civilization that has no city-names assigned to it.
  7. Your Leader UA file has similar issues wrt attempting to create your own EffectType. And in table GameEffectArguments within this second file you have another fatal syntax error which causes the game to cease reading anything further from within the file
    Code:
    INSERT INTO	GameEffectArguments
    		(Type,									Name,					Description,	ArgumentType, 	Required					)
    VALUES	('EFFECT_SG_GOVERNOR_ADJUST_TRANSITION_STRENGTH',	'TransitionStrength',		'Modifies time taken for governor to establish in city', integer, 0	);
    Again integer is interpreted as a column-name rather than argument-data, and so this error ensues
    Code:
    [3879517.274] [Gameplay] ERROR: no such column: integer
    As in the previous example, this causes the game to cease reading anything further from within the file.
  8. Another comma where a semi-colon is required to terminate the code chunk
    Code:
    INSERT INTO NamedMountains
    		(NamedMountainType,			Name							)
    VALUES	('NAMED_MOUNTAIN_BUKIT_TIMAH',	'LOC_NAMED_MOUNTAIN_BUKIT_TIMAH'		),
    		('NAMED_MOUNTAIN_BUKIT_BATOK',	'LOC_NAMED_BUKIT_BATOK'		),
    		('NAMED_MOUNTAIN_MOUNT_FABER',	'LOC_NAMED_MOUNTAIN_MOUNT_FABER'		),
    		('NAMED_MOUNTAIN_TELOK_BLANGAH',	'LOC_NAMED_MOUNTAIN_TELOK_BLANGAH'	),
    		('NAMED_MOUNTAIN_BUKIT_GOMBAK',	'LOC_NAMED_MOUNTAIN_BUKIT_GOMBAK'	),
    		('NAMED_MOUNTAIN_KENT_RIDGE',	'LOC_NAMED_MOUNTAIN_KENT_RIDGE'	),
    		('NAMED_MOUNTAIN_BUKIT PANJANG',	'LOC_NAMED_MOUNTAIN_BUKIT PANJANG'	),
    This is also fatal to the remainder of the file.
  9. This error
    Code:
    [3879517.266] [Gameplay] ERROR: near ")": syntax error
    is caused by one line missing the comment codes at the front of the line
    Code:
    --		PrereqCivic
    		)
    --SELECT	'UNIT_TKB_SINGAPORE_UU',	-- UnitType
    But since everything in that file is being disabled by comment commands it really has no effect except to add another error message into database.log
 
You can set things up to remove 1 food from all mines, and then create a second modifier that gives +1 food to all mines on bonus resources.
Yes! Take away & give back partly, thank you for pointing out ... I blame the multitude of occurrences of the word Requirement - they make me somewhat dizzy. (Besides having virtual pictures of developers chained to their workstations in dark & damp cellars trying to send a help message to the world while implementing this code :D)
Code:
INSERT INTO ImprovementModifiers (ImprovementType, ModifierId)
VALUES ("IMPROVEMENT_MINE", "MACERATE_MINE_JJ"),
       ("IMPROVEMENT_MINE", "MACERATE_MINE_BONUS_JJ");
INSERT INTO Modifiers (ModifierId, ModifierType, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES ("MACERATE_MINE_JJ", "MODIFIER_SINGLE_PLOT_ADJUST_PLOT_YIELDS", "PLAYER_IS_HUMAN", "PLOT_HAS_REQUIREMENTS_JJ"),
       ("MACERATE_MINE_BONUS_JJ", "MODIFIER_SINGLE_PLOT_ADJUST_PLOT_YIELDS", "PLAYER_IS_HUMAN", "PLOT_HAS_REQUIREMENTS_BONUS_JJ");
INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ("MACERATE_MINE_JJ", "Amount", -1),
       ("MACERATE_MINE_JJ", "YieldType", "YIELD_FOOD"),
       ("MACERATE_MINE_BONUS_JJ", "Amount", 1),
       ("MACERATE_MINE_BONUS_JJ", "YieldType", "YIELD_FAITH");

INSERT INTO RequirementSets (RequirementSetId, RequirementSetType)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "REQUIREMENTSET_TEST_ALL"),
       ("PLOT_HAS_REQUIREMENTS_BONUS_JJ", "REQUIREMENTSET_TEST_ALL");
INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "TERRAIN_REQUIREMENT_JJ"),
       ("PLOT_HAS_REQUIREMENTS_BONUS_JJ", "RESOURCE_REQUIREMENT_JJ");

INSERT INTO Requirements (RequirementId, RequirementType)
VALUES ("TERRAIN_REQUIREMENT_JJ", "REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES"),
       ("RESOURCE_REQUIREMENT_JJ", "REQUIREMENT_PLOT_RESOURCE_TYPE_MATCHES");
INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("TERRAIN_REQUIREMENT_JJ",  "TerrainType",  SELECT TerrainType FROM Terrains
                                                   WHERE TerrainType IN ("TERRAIN_GRASS", "TERRAIN_GRASS_HILLS", "TERRAIN_PLAINS",
                                                                         "TERRAIN_PLAINS_HILLS", "TERRAIN_TUNDRA", "TERRAIN_TUNDRA_HILLS")   ),
       ("RESOURCE_REQUIREMENT_JJ", "ResourceType", SELECT ResourceType FROM Resource_ValidTerrains
                                                   WHERE TerrainType IN ("TERRAIN_GRASS", "TERRAIN_GRASS_HILLS", "TERRAIN_PLAINS",
                                                                         "TERRAIN_PLAINS_HILLS", "TERRAIN_TUNDRA", "TERRAIN_TUNDRA_HILLS")
                                                   AND ResourceType = "RESOURCE_COPPER"                                                      );
Does anybody spot errors still present?

The purpose of this mod is to deflate the efficient human snowballing a bit - you need more farms, what increases the time to reach "enough population to build and staff campuses and theater squares".


[Edit: change granted YieldType for BonusResources to YIELD_FAITH instead of YIELD_FOOD in order to give copper the chance not to be harvested immediately because of the food-reduced mine]
.
 
Last edited:
This isn't really a question appropriate for a Quick Questions / Answers thread, but...

Thank you so much for all the help. Sorry about not using the best thread. What is the best thread for longer mod problems?

Edit: I have followed through with the edits and everything works. Once again, thank you.
 
Last edited:
tkbean
For help on a new mod, you could create your thread so the discussion could go on without getting lost if needed.

cvb
Maybe you could create a resource tag with the mining bonus resources (only copper?) and add the requirement 'plot resource tag matches' with inverse=true'?
I'm sorry I'm really not familiar with sql so I can't give you an exemple but in xml it would like:
Code:
    <Tags>
        <Row Tag="CLASS_MACERATE_MINE_JJ" Vocabulary="RESOURCE_CLASS" />
    </Tags>
    <TypeTags>
        <Row Type="RESOURCE_COPPER" Tag="CLASS_MACERATE_MINE_JJ" />
    </TypeTags>
 
    <ImprovementModifiers>
        <Row Type="IMPROVEMENT_MINE" ModifierId="MACERATE_MINE_JJ" />
    </ImprovementModifiers>
    <Modifiers>
        <Row ModifierId="MACERATE_MINE_JJ" ModifierType="MODIFIER_SINGLE_PLOT_ADJUST_PLOT_YIELDS" OwnerRequirementSetId="PLAYER_IS_HUMAN" SubjectRequirementSetId="PLOT_HAS_REQUIREMENTS_JJ" />
    </Modifiers>
    <ModifierArguments>
        <Row ModifierId="MACERATE_MINE_JJ" Name="YieldType" Value="YIELD_FOOD" />
        <Row ModifierId="MACERATE_MINE_JJ" Name="Amount" Value="-1" />
    </ModifierArguments>

    <RequirementSets>
        <Row RequirementSetId="PLOT_HAS_REQUIREMENTS_JJ" RequirementSetType="REQUIREMENTSET_TEST_ALL" />
    </RequirementSets>
    <RequirementSetRequirements>
        <Row RequirementSetId="PLOT_HAS_REQUIREMENTS_JJ" RequirementId="RESOURCE_NOT_BONUS_JJ" />
    </RequirementSetRequirements>

    <Requirement>
        <Row RequirementId="RESOURCE_NOT_BONUS_JJ" RequirementType="REQUIREMENT_PLOT_RESOURCE_CLASS_TYPE_MATCHES" Inverse="true" />
    </Requirement>
    <RequirementArguments>
        <Row RequirementId="RESOURCE_NOT_BONUS_JJ" Name="ResourceClassType" Value="CLASS_MACERATE_MINE_JJ" />
    </RequirementArguments>
 
Thank you so much for all the help. Sorry about not using the best thread. What is the best thread for longer mod problems?

Edit: I have followed through with the edits and everything works. Once again, thank you.
As mentioned above you are usually better off starting a new thread in the "Help" forum when you have a mod that is simply not working. You get better visibility that way and your request for help is less likely to get buried in the clutter of a much larger thread. And the "Mod Doctor" is not always in the house, as it were, so you want better visibility because folks such as Laurana Kanan & etc are usually able to help you solve a problem when I am not currently making house-calls. :mischief:
 
And the "Mod Doctor" is not always in the house, as it were, so you want better visibility because folks such as Laurana Kanan & etc are usually able to help you solve a problem when I am not currently making house-calls. :mischief:
Unfortunately, I've been having to visit "Real Doctors" more the last month or so, which has limited the time I've spent on the forums.
 
Maybe you could create a resource tag with the mining bonus resources (only copper?) and add the requirement 'plot resource tag matches' with inverse=true'?
I'm sorry I'm really not familiar with sql so I can't give you an exemple but in xml it would like:
To be honest, I'm quite clueless to set your XML post into action ... so I transcribed it first into SQL. It looks to me much more familiar now, but still ...
Code:
INSERT INTO ImprovementModifiers (ImprovementType, ModifierId)
VALUES ("IMPROVEMENT_MINE", "MACERATE_MINE_JJ");

INSERT INTO Modifiers (ModifierId, ModifierType, OwnerRequirementSetId, SubjectRequirementSetId)
VALUES ("MACERATE_MINE_JJ", "MODIFIER_SINGLE_PLOT_ADJUST_PLOT_YIELDS", "PLAYER_IS_HUMAN", "PLOT_HAS_REQUIREMENTS_JJ");
INSERT INTO ModifierArguments (ModifierId, Name, Value)
VALUES ("MACERATE_MINE_JJ", "YieldType", "YIELD_FOOD"),
       ("MACERATE_MINE_JJ", "Amount", -1);

INSERT INTO RequirementSets (RequirementSetId, RequirementSetType)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "REQUIREMENTSET_TEST_ALL");
INSERT INTO RequirementSetRequirements (RequirementSetId, RequirementId)
VALUES ("PLOT_HAS_REQUIREMENTS_JJ", "RESOURCE_NOT_BONUS_JJ");

INSERT INTO Requirements (RequirementId, RequirementType, Inverse)
VALUES ("RESOURCE_NOT_BONUS_JJ", "REQUIREMENT_PLOT_RESOURCE_CLASS_TYPE_MATCHES", 1);
INSERT INTO RequirementArguments (RequirementId, Name, Value)
VALUES ("RESOURCE_NOT_BONUS_JJ", "ResourceClassType", "CLASS_MACERATE_MINE_JJ");

INSERT INTO Tags (Tag, Vocabulary)
VALUES ("CLASS_MACERATE_MINE_JJ", "RESOURCE_CLASS");
INSERT INTO TypeTags (ResourceType, Tag)
VALUES ("RESOURCE_COPPER", "CLASS_MACERATE_MINE_JJ");
It is certainly interesting to learn something about Tags (which I hadn't until now), but I suspect the Resources as the game sees them (!= RESOURCE_COPPER) don't contain the "RESOURCE_NONE" - i.e. to the resourceless mines on hills the food-reduction wouldn't be applied to this way?? Or would it?

Is something wrong with the code I posted yesterday in post #485 ? (which I see as equivalent)

[Edit: changed "true" into the correct 1 inSQL]
.
 
Last edited:
SQL does not recognize "true" or "false". Integer 1 and 0 are used instead by SQL.

The game's XML parser translates Boolean "true" and "false" into 1 and 0 before inserting the XML rows into the SQL databases.

Where did you find RESOURCE_NONE ? I'm not seeing it anywhere in any of the game's base files nor in the Debug database.
 
Where did you find RESOURCE_NONE ? I'm not seeing it anywhere in any of the game's base files nor in the Debug database.
I cannot remember. I have a large collection of supposed to be useful code snippets from mods on CivFanatics, which contains:
Code:
g_RESOURCE_NONE               = -1;
g_RESOURCE_WHEAT           = GetGameInfoIndex("Resources", "RESOURCE_WHEAT");
It was "unlucky" from me to use "" in the context of "RESOURCE_NONE", because that looks like normal usage ("RESOURCE_WHEAT" etc.), but RESOURCE_NONE is not - as the snippet clearly shows. RESOURCE_NONE is only a local used token for an empty Resource. Thus my suspicion that ResourceType != "RESOURCE_COPPER" wouldn't cover resourceless mines.

Could you please have a look into the (latest) code in post #488 for still hiding errors inside? So I can use that as general template for quarries & pastures and continue.

.
 
Before doing all this have you tried the modifier? Are you sure you can actually have a -1 yield?
It's used in the game files for Mali but mines give production and it removes this. But will the -1 food do something if the mine doesn't give food? You should probably test this before.
And trying it is also the best way to know if there are errors.
 
Before doing all this have you tried the modifier? Are you sure you can actually have a -1 yield? It's used in the game files for Mali but mines give production and it removes this. But will the -1 food do something if the mine doesn't give food? You should probably test this before.
I see in the code of published mods (Infixo's Real Natural Disasters & FearSunn's Mines No Food) enough indication to think it works. It is FOOD and the yield is not reduced from that the improvement given itself, but from the underlying TERRAIN (Terrain_YieldChanges).
And trying it is also the best way to know if there are errors.
ABSOLUTELY. But I do not have civ6 yet. Here 2 quotes of recent explanations (on CivFanatics) why:
Spoiler :
I also play CIV since a really long time. If I had started playing civ6 3 years ago, I might be even be burned out before the development cycle ends ... whenever this will be ... :D ... "Que será, será Whatever will be, will be The future's not ours to see".
To keep the desire fresh (or the powder dry) I haven't even started PLAYING. Just like to read the fora, watch some gameplay videos & look into code fragments which are available in mods - here, not STEAM

civ4! 2005 I played several months vanilla. Great game!!! Had to pause. Bought in 2010 the two expansions and did a lot of modding. Excellent experience. Thought later, that was the perfect timing.
Came back 2016, decided to start playing & modding civ6 when it is ready ... wouldn't be more than 3 years ... :lol::lol: Also didn't think, that I'll be in a situation nobody expects / understands. :sad:
In short: I don't have the game yet and can't subscribe & download.
Yeah, it seems weird to be interested in modding a game one doesn't play (yet). :D Soon™.
When I finally start playing/modding civ6, I also want to buy a new PC with a Grafixcard able to run the game at ultraHD (3840x2160), so it does matter WHEN I do that.

In short: I don't have the game yet and can't install & test yet.

I think, nevertheless I can ask useful* questions and can 'frankenstein' useful* code (fragments) here in the forum while learning SQL which is necessary for things like modifying yields.

[ * useful for other readers]

.
 
Last edited:
I'm currently trying to create a modifier that reduces the gold and faith purchasing cost of all units.
I thought "MODIFIER_PLAYER_CITIES_ADJUST_UNITS_PURCHASE_COST" would work but that only effects gold costs.
Is anyone aware of an effect that reduces faith costs by domain? Or even by promotion class?
 
Not only would that affect the gold purchase cost but also the production cost. But you've forgotten text delimiters around DOMAIN_LAND so you'd likely get a fatal syntax error from SQL interpreting it as a column-name instead of argument-data.
 
Back
Top Bottom