The Great Unofficial Module Manager Help Thread! (2024)

IMPORTANT: PAGE UNDER CONSTRUCTION, NOT FINAL

Before I begin:

1. This is my own idea, it is in no way official, nor affiliated with any developer of ModuleManager.

2. I thought it would be helpful.

3. No one told me not to.

4. This is for you, @Ooglak Kerman. And all the others who wished to manage their modules, but could not.

So, I figured that many KSP players who use a lot of mods may not exactly have the mods just the way the want. Or maybe a budding modder wants to learn some stuff about CFG files.

Part 1: What is Module Manager?

ModuleManager is a mod created by @ialdabaothand currently maintained by @sarbian.

A large portion of KSP's data are stored in text files with the .cfg extension. This includes resource definitions, part functionality, science flavor text and gains, and much, much, more.

Sometimes, a mod may need to change this existing data as well as adding it's own. That is where Module Manager comes in to help. With ModuleManager, the text in CFG files can change what is actually loaded into the game from what is in the other files.

For example, Snacks, a life-support mods, adds some life support supplies to all crewed pods using ModuleManager.

THIS GUIDE WILL NOT TELL YOU HOW TO INSTALL MODULE MANAGER.

Part 2: The Node Structure

The CFG files are set up into a hierarchy of nodes. These nodes contain fields, where data is, and other nodes.

Let's take a look at the definition of the Liquid Fuel resource.

Spoiler

RESOURCE_DEFINITION
{
name = LiquidFuel
displayName = #autoLOC_500999 //#autoLOC_500999 = Liquid Fuel
abbreviation = #autoLOC_6002095 //#autoLOC_6002095 = LF
density = 0.005
unitCost = 0.8
hsp = 2010
flowMode = STACK_PRIORITY_SEARCH
transfer = PUMP
isTweakable = true
volume = 5
RESOURCE_DRAIN_DEFINITION
{
isDrainable = true
showDrainFX = true
drainFXPriority = 7
drainForceISP = 5
drainFXDefinition = gasDraining
}
}

At the top, in caps, we see "RESOURCE_DEFINITION". This is the type of node. As it does not exist within another node, we call it a top-level node.

Within it, are some other nodes and fields.

First, is the "name" field. This is not what is displayed, it is an internal name. It is very important, however, for selecting that node for later editing. It also has some other functions for things like functionality.

You may notice, that in the displayName and abbreviation fields, there is some #autoLOC_<numbers>. This uses the localization system, displaying a different value based on what language is selected for the game. This will be later discussed further.

So, we have those fields, but we also have the "RESOURCE_DRAIN_DEFINITION" node, with its own fields inside. There could be other nodes inside that, and you can go on forever.

Part 3: Selecting a Node for Editing

At the top of the previous example, we saw the line "RESOURCE_DEFINITION". In front of that, we could have put a few thing, and behind it, we could have put a lot more things.

If, at the front, we had an "@" character, we could select aRESOURCE_DEFINITION for editing. if we had a "+" character, it would make a copy and let us edit that. the "!" and "-" characters delete the selected node, but you still have to specify a little something. More detail on this later. Finally, the "%" character edits something if it already exists, and if not, creates it.

At the back, we could have put some square brackets. Inside those brackets, we could select a name of the specific node to edit, as there are lots of nodes of the same type. The name is the same as the "name" field specified in the initial creation of the node. You can put the "*" character inside the name, and it will represent any number of any characters. So, "abc*" would select "abc1", "abc2", "abcde", but not "ab3". Additionally, the "?" character can be any one random character. If you want to select every part, you can put just the "*" character into the square brackets.

After the square brackets, we can put a comma and then a number, or some other selectors. The numbers indicate which node to edit, if the node they are in have multiple with the same name. The selectors are: HAS, NEEDS, FOR, BEFORE, AFTER, FIRST, and FINAL. They will be discussed in more detail later.

After each of these words, there is some stuff in square brackets, and then a colon between everything.

Here's an example, from the Blueshift thread:

Let's look at each line.

First, it edits the parts with a specific set of nodes. Curly braces indicate that we are going a level in. Then, we edit a module node with the name "WBIWarpEngine". Again, curly braces. Finally, we edit the warpSpeedSkillMultiplier field to be 0.6.

Remember to make sure that each opening curly brace is paired with a closed curly brace. This is one of the most common mistakes!

Part 4: Selecting Fields

Fields also need to have the selection character at the front, and can have the other selectors or numbers applied to them. Oh, and the number can be the star symbol to select all of them. If there is no number, the first one is used. These go before the new value, like this:

@WhatEverThisIs, 3:NEEDS[xyz] = abc

Part 5: Other Selectors

There are a few things you can put after each selected node or field:

1. HAS

HAS will only make the patch apply to parts with some condition.

After the word goes a set of square brackets. Inside, you can put: <character><node/fieldType>[<name>].

The character can be @, # or !.

If the character is @, then the patch will only run on parts with that node. If the character is !, then the patch will only run on parts without that node. The # character will be covered later, when we get to variables.

The node type should be self-explanatory. is it a PART? MODULE? RESOURCE?

The name is just the same as the name field when selecting a part.

2. FOR

This one's simple, a mod name goes in the box. This lets Module Manager know that the patch is for that mod.

3. NEEDS

For this selector, inside the box goes the name of a mod. The patch will only run if that mod is installed. The ! character can be used to make the patch only run if the mod is not installed, and the | character acts like a logical OR gate, so either of two mods can be installed and the patch will run.

To determine whether a mod exists:

A. if there is a patch, that runs at all, with the FOR selector carrying a name that is the same as what is in the NEEDS box

B. Or, if there is a folder in GameData with the name you are looking for.

4-5. BEFORE and AFTER

Mod names go in the box.

These make the patch run before or after patches with FOR selectors of the mod name. Useful to avoid pouring the drink before getting out a cup, so to speak.

6-7. FIRST and FINAL

Simply put, these just make the patches run before or after everything else. No square brackets needed.

COMMUNITY UPDATING

As it seems others have begun to add things to this, I will quote them here in the OP. Thanks, everyone!

On 6/5/2022 at 7:06 AM, Aelfhe1m said:

Contributions for this thread:

Selecting Nodes - or how to use :HAS

Consider the following nodes partially extracted from the stock files:

Reveal hidden contents

PART{name = cupolaCrewCapacity = 1TechRequired = commandModules// snip extra fieldsMODULE{name = ModuleCommandminimumCrew = 1}RESOURCE{name = ElectricChargeamount = 200maxAmount = 200}MODULE{name = ModuleScienceExperimentexperimentID = crewReportinteractionRange = 2// snip}// snip}EXPERIMENT_DEFINITION{id = crewReporttitle = #autoLOC_501009 //#autoLOC_501009 = Crew ReportbaseValue = 5scienceCap = 5dataScale = 1requireAtmosphere = FalsesituationMask = 63biomeMask = 7RESULTS{default = #autoLOC_501258 //#autoLOC_501258 = You record the crew's assessment of the situation.KerbinSrfLandedLaunchpad = #autoLOC_501259 //#autoLOC_501259 = We don't seem to be moving very fast right now.// many more results }}

How would we select the cupola part to change it?

The most common way you will see this done in MM patches is

@PART[cupola]

This is actually a special shortcut for

@PART:HAS[#name[cupola]]

Because it is a shortcut for selecting nodes based on their name fields it won't work for nodes that don't have a name field like the EXPERIMENT_DEFINITION node in the above example. To select those you need to identify a field with a useful value and then explicitly refer to it in the HAS clause:

@EXPERIMENT_DEFINITION:HAS[#experiment_id[crewReport]]

You can also select nodes based on whether or not they contain a certain subnode. For example the cupola PART node above has several MODULE subnodes (as do almost all PART nodes), so the following patch would affect it:

@PART:HAS[@MODULE[ModuleCommand]]

This selector will affect every PART node that has at least one MODULE subnode that has a name field with the vale "ModuleCommand" (remember [X] is a shortcut for :HAS[#name[X]])

We can also multiple conditions. e.g.

@PART[*]:HAS[@MODULE[ModuleCommand]],RESOURCE[ElectricCharge])

This breaks down as - select all PART nodes that have a name field with any value (* is a wildcard), and a MODULE subnode with a name field containing the value "ModuleCommand" and a RESOURCE subnode with a name field with the value "ElectricCharge".

In this example the "," represents AND. MM also allows you to use "&" for AND so this could also be written as

@PART[*]:HAS[@MODULE[ModuleCommand]]&RESOURCE[ElectricCharge])

Which you choose to use is a matter of personal preference as they will behave identically.

Unfortunately MM only recognises OR in a limited number of places. You can use it inside the name shortcut or in a :NEEDSclause but it won't work inside of a :HAS clause. So the following will work (MM uses "|" to mean OR)

@PART[cupola|Mark1co*ckpit]@PART:NEEDS[modA|modB]

but this WON'T work:

@PART:HAS[@RESOURCE[ElectricCharge|MonoPropellant]]

You would need to write separate patches for each resource type

@PART:HAS[@RESOURCE[ElectricCharge]] {}@PART:HAS[@RESOURCE[MonoPropellant]] {}

b. Choosing which subnodes to edit

:HAS is also used within the contents of a patch filter which subnodes are affected by a given change.

Suppose for example we wanted to changed the minimum number of crew required to operate a cupola in the above PART example. First you would use a selector to choose the cupola PART node, then inside the contents of the patch you would use another selector to choose the ModuleCommand MODULE subnode:

@PART[cupola]{@MODULE[ModuleCommand]{@minimumCrew = 0}}

Because both PART and MODULE have name fields we can use the shorthand [X] form here. We could also have written out the patch in the full form:

@PART:HAS[#name[cupola]]{@MODULE:HAS[#name[ModuleCommand]]{@minimumCrew = 0}}

but that takes more typing.

If a subnode does not have a name field or there are multiple subnodes with the same value in the name field then you will need to use a HAS to identify the specific subnode based on some other unique value.

For example suppose we have a part with two experiments - a temperatureScan and abarometerScan. This would look like:

Reveal hidden contents

PART{name = foo...MODULE{name = ModuleScienceExperimentexperimentID = temperatureScanexperimentActionName = Log Temperature}MODULE{name = ModuleScienceExperimentexperimentID = barometerScanexperimentActionName = Log Pressure Data}}

To change the temperatureScan's action name we would use:

@PART[foo]{@MODULE[ModuleScieneExperiment]:HAS[#experimentID[temperatureScan]]{@experimentActionName = Take the temperature}}

Notice how we first use :HAS[@MODULE[ModuleScienceExperiment] to identify that we want to affect ModuleScienceExperiment subnodes then we use an extra :HAS[#experimentID[temperatureScan]] sub-clause to narrow this down to just the MODULES with an experimentID field with the value "temperatureScan".

NOTE we use @ when selecting based on subnodes and # to select based on fields

If instead of only modifying the foo PART, we wanted to modify all PARTs that had a temperatureScan experiment MODULE then we would repeat the selector on the main node as well:

@PART:HAS[@MODULE[ModuleScienceExperiment]:HAS[#experimentID[temperatureScan]]]{@MODULE[ModuleScieneExperiment]:HAS[#experimentID[temperatureScan]]{@experimentActionName = Take the temperature}}

c. Selecting nodes that do not match a specific criterium

Suppose we want to select all PART nodes that do not have a "bulkheadProfile" field:

@PART:HAS[~bulkheadProfile[]]

or all PART nodes that do not contain a MODULE subnode with name "ModuleCommand"

@PART:HAS[!MODULE[ModuleCommand]]

Notice that we use ~ when comparing fields and ! when comparing subnodes.

d. Lists of fields

Consider the following node

RESULTS{message = Onemessage = Twomessage = Threemessage = four}

Suppose we wanted to change "Two" to "2". How would we do that? MM provides indexers to distinguish between identical options

@RESULTS{@message,1 = 2}

Here the ",1" means the second message field (indexes count up from 0).You can also count from the end using negative indexes (",-1" = last value, ",-2" the second last and so on). The wildcard index ",*" means select ALL.

We can also modify specific values within fields that have a list of values. For example:

PART{name = foonode_stack_top = 0.0, .9, 0.0, 0.0, 1.0, 0.0, 2}

Suppose we want to change the .9 in the second value to 1.0

@PART[foo]{@node_stack_top[1] = 1.0}

The use of the index here will work for any field where the values are separated by commas. But what if the mod author had used a different separator?

PART{name = foootherfield = one|two|three|four}

then we specify both the index and the separator

@PART[foo]{@otherfield[2,|] = 3}// resultPART{name = foootherfield = one|two|3|four}

On 6/7/2022 at 9:02 AM, Aelfhe1m said:

Making a patch only apply if a given mod is installed

MM uses :NEEDS to mark that a patch should only be processed if the mods it needs are present. Each patch may only have a single NEEDS statement, but more than one mod can be specified within the needs.

@PART:NEEDS[Tweakscale,ModularFuelTanks]

The above example is a patch that would only be applied if BOTH Tweakscale and ModularFuelTanks were found in your GameData folder.

Patches can also specify that they need a given mod NOT to be installed.

@PART:NEEDS[!Tweakscale,!ModularFuelTanks]

In this case the "!" character stands for NOT and is specifying that this patch should only be applied if Tweakscale and ModularFuelTanks are NOT present.

You can of course mix and match both required and not required

@PART:NEEDS[ModularFuelTanks,!Tweakscale]

NEEDS can also recognise the "|" character to mean OR

@PART:NEEDS[Tweakscale|ModularFuelTanks]

This specifies that the patch should be applied if EITHER Tweakscale or ModularFuelTanks are installed (or both it's not exclusive)

MM "knows" which mods are installed based on several tests:

  • there is a DLL with the specified name somewhere inside the game's folder
  • there is a folder with that name inside GameData
  • there is another patch that has a :FOR[] statement containing the mod name
  • there is special code inside the mod's DLL (assembly)to tell MM to add a name to its list of recognised mods

So for example MM would believe that Tweakscale was installed if:

  • it found a file called Tweakscale.dll
  • it found a folder called GameData/Tweakscale
  • it found another patch with :FOR[Tweakscale]
  • if another mod had code inside its DLL that told MM Tweakscale existed

MM includes a full list of all the mods it has found near the start of its logfile (KSP/Logs/ModuleManager/ModuleManager.log)

NEEDS can also be used to check for subfolders within GameData

@PART:NEEDS[TriggerTech/KerbalAlarmClock]

Because of the way Module Manager detects mods it is VERY important to make sure that you completely delete a mods folder and all its related files when removing a mod. An empty folder will still cause MM to treat a mod as being present and it will apply any patches related to that mod which can lead to errors or unexpected behaviours.

Also all patch authors need to be careful to use FOR correctly, since Module Manager uses this to detect the presence of a mod. ONLY the original mod should use FOR[Modname], ALL other mods or personal patches should use BEFORE, AFTER or NEEDS when referring to the name of another mod.

Controlling the order in which patches are applied - FIRST, BEFORE, FOR, AFTER, LAST, FINAL

When doing patching Module Manager starts by scanning through the GameData folder to find all the contained patches. Then:

  • Nodes with no operator are loaded by the KSP GameDatabase first.
  • Patches for modname values in NEEDS, BEFORE, AFTER that don't exist are removed.
  • All patches with :FIRST are applied.
  • All patches without an ordering directive (:FIRST, :BEFORE, :FOR, :AFTER, :LAST, :FINAL) are applied.
  • For each recognised modname:
    • All patches with :BEFORE are applied
    • All patches with :FOR are applied
    • All patches with :AFTER are applied
  • All patches with :LAST are applied in order
  • All patches with :FINAL are applied

If two patches have the same priority in the above list then they will be sorted based on the filename of the files containing the patch or if they are in the same file then the order with which they appear in that file.

Consider the following (very contrived) example:

The Great Unofficial Module Manager Help Thread! (1)

Module Manager will produce the following patch log for this KSP install:

Reveal hidden contents

[LOG 16:42:11.513] Log started at 2022-06-07 16:42:11.513[LOG 16:42:12.729] Checking Cache[LOG 16:42:12.971] SHA generated in 0.236s[LOG 16:42:12.971] SHA = 31-D6-78-79-56-5F-51-6E-3C-70-41-04-16-B4-39-AC-47-A0-3B-5D-38-B9-8E-2F-56-CC-07-52-46-6D-76-49[LOG 16:42:12.972] Pre patch init[LOG 16:42:13.173] compiling list of loaded mods...Mod DLLs found: Name Assembly Version Assembly File Version KSPAssembly Version SHA256 Assembly-CSharp 0.0.0.0 0.0.0.0 1.12 9be4953fe5b14018d2f62ce040c188da90f05d1e1fbaf1a2262775a63cd5607e ModuleManager 4.2.1.0 4.2.1.0 2.5 2eb4963f73a5255163953a270026f50a8f1a7dd27f4bb0dd69dd4699d0f2268b KSPSteamCtrlr 0.0.1.35 0.0.1.35 1675fa4fcb61d014eb1babe7eed703e7f76a1008537ee57ca7cec65cd9ff94acNon-DLL mods added (:FOR[xxx]): ModA HandwaviumMods by directory (sub directories of GameData): ModB Squad SquadExpansionMods added by assemblies:[LOG 16:42:13.174] Loading Physics.cfg[LOG 16:42:13.176] Extracting patches[LOG 16:42:13.198] Deleting root node in file ModB/MMPatches node: !RESOURCE_DEFINITION[newResource]:NEEDS[WarpDrive] as it can't satisfy its NEEDS[LOG 16:42:13.293] Applying patches[LOG 16:42:13.295] :INSERT (initial) pass[LOG 16:42:13.367] :FIRST pass[LOG 16:42:13.370] Applying update ModA/morepatches/@PART[HandwaviumTank]:FIRST to ModB/Resrources/res.cfg/PART[HandwaviumTank][LOG 16:42:13.377] :LEGACY (default) pass[LOG 16:42:13.380] Applying copy ModA/morepatches/+PART[HandwaviumTank]:NEEDS[Handwavium] to ModB/Resrources/res.cfg/PART[HandwaviumTank][LOG 16:42:13.383] :BEFORE[ASSEMBLY-CSHARP] pass[LOG 16:42:13.383] :FOR[ASSEMBLY-CSHARP] pass[LOG 16:42:13.383] :AFTER[ASSEMBLY-CSHARP] pass[LOG 16:42:13.383] :BEFORE[HANDWAVIUM] pass[LOG 16:42:13.383] Applying copy ModA/patches/+PART[HandwaviumTank]:BEFORE[Handwavium] to ModB/Resrources/res.cfg/PART[HandwaviumTank][LOG 16:42:13.384] :FOR[HANDWAVIUM] pass[LOG 16:42:13.384] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to ModB/Resrources/res.cfg/RESOURCE_DEFINITION[newResource][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[LiquidFuel][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[Oxidizer][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[SolidFuel][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[MonoPropellant][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[XenonGas][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[ElectricCharge][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[IntakeAir][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[EVA Propellant][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[Ore][LOG 16:42:13.385] Applying update ModB/Resrources/res/@RESOURCE_DEFINITION:FOR[Handwavium] to Squad/Resources/ResourcesGeneric.cfg/RESOURCE_DEFINITION[Ablator][LOG 16:42:13.385] :AFTER[HANDWAVIUM] pass[LOG 16:42:13.385] :BEFORE[KSPSTEAMCTRLR] pass[LOG 16:42:13.385] :FOR[KSPSTEAMCTRLR] pass[LOG 16:42:13.385] :AFTER[KSPSTEAMCTRLR] pass[LOG 16:42:13.385] :BEFORE[MODA] pass[LOG 16:42:13.385] :FOR[MODA] pass[LOG 16:42:13.386] Applying update ModA/morepatches/@PART[fuelTankSmallFlat]:FOR[ModA] to Squad/Parts/FuelTank/Size1_Tanks/fuelTankT100.cfg/PART[fuelTankSmallFlat][LOG 16:42:13.387] :AFTER[MODA] pass[LOG 16:42:13.387] :BEFORE[MODB] pass[LOG 16:42:13.387] :FOR[MODB] pass[LOG 16:42:13.387] :AFTER[MODB] pass[LOG 16:42:13.387] Applying copy ModA/patches/+PART[HandwaviumTank]:AFTER[ModB] to ModB/Resrources/res.cfg/PART[HandwaviumTank][LOG 16:42:13.388] :BEFORE[MODULEMANAGER] pass[LOG 16:42:13.388] :FOR[MODULEMANAGER] pass[LOG 16:42:13.388] :AFTER[MODULEMANAGER] pass[LOG 16:42:13.388] :BEFORE[SQUAD] pass[LOG 16:42:13.388] :FOR[SQUAD] pass[LOG 16:42:13.388] :AFTER[SQUAD] pass[LOG 16:42:13.388] Applying update ModB/MMPatches/@RESOURCE_DEFINITION[newResource]:AFTER[Squad] to ModB/Resrources/res.cfg/RESOURCE_DEFINITION[newResource][LOG 16:42:13.388] :BEFORE[SQUADEXPANSION] pass[LOG 16:42:13.388] :FOR[SQUADEXPANSION] pass[LOG 16:42:13.388] :AFTER[SQUADEXPANSION] pass[LOG 16:42:13.389] :LAST[HANDWAVIUM] pass[LOG 16:42:13.389] Applying update ModA/morepatches/@PART:HAS[@RESOURCE[newResource]]:LAST[Handwavium] to ModB/Resrources/res.cfg/PART[HandwaviumTank][LOG 16:42:13.392] Applying update ModA/morepatches/@PART:HAS[@RESOURCE[newResource]]:LAST[Handwavium] to ModB/Resrources/res.cfg/PART[LargeHandwaviumTank][LOG 16:42:13.392] Applying update ModA/morepatches/@PART:HAS[@RESOURCE[newResource]]:LAST[Handwavium] to ModB/Resrources/res.cfg/PART[LargeHandwaviumTank][LOG 16:42:13.392] Applying update ModA/morepatches/@PART:HAS[@RESOURCE[newResource]]:LAST[Handwavium] to ModB/Resrources/res.cfg/PART[SmallHandwaviumTank][LOG 16:42:13.396] :FINAL pass[LOG 16:42:13.396] Done patching[LOG 16:42:13.397] Saving Cache[LOG 16:42:13.552] Saving cache[LOG 16:42:13.874] ModuleManager: 21 patches applied[LOG 16:42:13.874] Ran in 1.145s[LOG 16:42:13.907] Done!

Notice for example that BEFORE[Handwavium],FOR[Handwavium] and AFTER[Handwavium] all occurred before FOR{ModA] but that LAST[Handwavium] occurred after all the BEFORE/FOR/AFTER passes (and before FINAL)

Edited by SkyFall2489

The Great Unofficial Module Manager Help Thread! (2024)

References

Top Articles
Latest Posts
Article information

Author: Kerri Lueilwitz

Last Updated:

Views: 5628

Rating: 4.7 / 5 (47 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Kerri Lueilwitz

Birthday: 1992-10-31

Address: Suite 878 3699 Chantelle Roads, Colebury, NC 68599

Phone: +6111989609516

Job: Chief Farming Manager

Hobby: Mycology, Stone skipping, Dowsing, Whittling, Taxidermy, Sand art, Roller skating

Introduction: My name is Kerri Lueilwitz, I am a courageous, gentle, quaint, thankful, outstanding, brave, vast person who loves writing and wants to share my knowledge and understanding with you.