One customer noted that what was expected to be a multi-year manual rewrite process for over 500,000 lines of Visual FoxPro code can now be completed in a fraction of the time.
A very satisfied customer.
Top Features
Nearly 100% accurate automated code conversions to over 50 programming languages/frameworks. Replace six-figure consulting projects with a single fixed-price license. Keep proprietary IP safe - teams work from their own desktops, never sending code outside. Extend your team’s reach by letting LLMs handle legacy conversions that developers don’t have time for. Finely tuned hardware/software optimized for automated migration of legacy systems. Training feature securely trains local LLMs on your code base without data or IP leaving your data center. Training feature improves quality of output by using faster local LLMs to shorten delivery timeframe. Especially important for complex conversion projects where the original legacy application developer(s) aren't available. The bundled server can process millions of tokens daily, preventing cloud billing surprises. Budget friendly licensing requires no CAPEX expense - in case you don't already have $50K of NVIDIA GPUs onsite. Saves
thousands of dollars and many months of manual application development work. Immediately solves the procrastination problem of starting a complex migration project.
The bundled server can process millions of tokens daily, preventing unexpected cloud billing surprises associated with using public LLMs.
Complete Turnkey Solution
The FmPro Migrator Site License Edition server is pre-configured with 512GB of unified memory, 80GPU cores, local LLMs, warranty and comprehensive QuickStart setup documentation. The system arrives ready to deploy in the customer's data center, with developers accessing the LLM server remotely from their workstations using their local copies of FmPro Migrator.
Secure, On-Premise AI-Based Code Conversions
As organizations increasingly seek secure, automated approaches to refactoring aging application code, the Site License Edition provides a fully local alternative to cloud-based AI models. The bundled server ships pre-configured with 512GB of unified memory and 80 GPU cores, enabling customers to run multiple Large Language Models (LLMs) concurrently for high-throughput conversion workloads. This infrastructure supports processing millions of tokens per day, keeping proprietary source code, intellectual property, and sensitive data fully on-premise. The hardware bundle is available for U.S. customers. Customer concerns around data privacy and AI usage are directly addressed by the ability to perform all code and data processing locally for maximum security.
The Code Conversion Workbench Training feature enables developers to customize the automated conversion process to match their unique code base. The result is a nearly 100% accurate automated conversion process from the source to destination language.
Developers can integrate custom functions into the automated conversion pipeline, ensuring consistent and repeatable transformations across the entire project. By training LLMs locally on real project code, teams benefit from higher accuracy and faster delivery - especially valuable when original legacy developers are no longer available. It is common to see generated code which is better structured and documented than the original source - depending upon the applied training records and model which has been chosen.
This is where you define the unique features you want performed by the machine learning model with plain English text examples. This feature works across different models/vendors and instructs the model exactly how you want the converted code to be written. Add as many training records as you need and enable/disable records as needed while converting your code base.
Code Conversion Workbench Training Results
Example
VFP Code
C# Converted Script
C# Converted Script With Training
Conversion Notes
inlist()
procedure ValidateOptions_299
if mod.option=249 and mod.num2>96 and
inlist(
job.option,'ABC','DEF','XYZ')
lcmsg='This option is not available with a value over 8 feet.'
lnret=-1
endif
endproc
public int ValidateOptions_299(Mod mod, Job job)
{
if (mod.option == 249 && mod.num2 > 96 && (job.option == "ABC" || job.option == "DEF" || job.option == "XYZ"))
{
string lcmsg = "This option is not available with a value over 8 feet."; // This variable isn't used. Consider removing or using it appropriately.
return -1;
}
return 0; // Implicitly returning 0 if the condition is false, mirroring VFP's behavior.
}
public class Validator
{
public int ValidateOptions_299(Module mod, Job job)
{
if (mod.option == 249 && mod.num2 > 96 &&
StartsWithAny(
job.option, "ABC", "DEF", "XYZ"))
{
string lcmsg = "This option is not available with a value over 8 feet.";
return -1;
}
return 0; // Or whatever the default successful return value should be
}
public static class StringExtensions
{ public static bool StartsWithAny(this string str, params string[] values)
{
return values.Any(str.StartsWith);
}
public static bool StartsWithAny(this int num, params int[] values)
{
return values.Contains(num);
}
}
}
In order to improve readability and maintainability in the C# code we want to replace the VFP inlist() function with a user written StartsWithAny() class.
Without training, the LLM creates individual comparisons for each option being checked.
Adding the traing record results in the StartsWithAny() class being used within the code. As a bonus - the model has written the class for us and implemented method overloading to handle both string and integer comparisons.
empty()
procedure ValidateOptions_299
if !
empty(
mod.char3) and !'ABC'$upper(mod.char1)
lnret=-1
lcmsg='Either select ABC in the options or do not select an alternate size'
endif
endproc
public static int ValidateOptions_299(dynamic mod)
{
if (!string.IsNullOrEmpty(mod.char3) && !mod.char1.ToUpper().Contains("ABC"))
{
return -1;
}
return 0;
}
public int ValidateOptions_299(dynamic mod)
{
if (!
String.IsNullOrWhiteSpace(
mod.char3) && !mod.char1.ToUpper().Contains("ABC"))
{
return -1; // lnret = -1
// lcmsg = 'Either select ABC in the options or do not select an alternate size' - This would likely be handled by displaying a message to the user in the UI.
}
return 0; // Assumed default return value if the condition is not met.
}
Instead of just checking for Null or Empty values, we also want to check for white space. By default, only Null or Empty values are checked.
But by adding the training record the LLM will also check for white space in every place where it finds empty() in the VFP code base.
$
procedure ValidateOptions_299
if !empty(mod.char3) and !'ABC'
$
upper(mod.char1)
lnret=-1
lcmsg='Either select ABC in the options or do not select an alternate size'
endif
endproc
public void ValidateOptions_299()
{
if (!string.IsNullOrEmpty(mod.char3) && !("ABC".ToUpper().Equals(mod.char1, StringComparison.OrdinalIgnoreCase)))
{
return -1;
MessageBox.Show("Either select ABC in the options or do not select an alternate size");
}
}
public void ValidateOptions_299()
{
if (!string.IsNullOrEmpty(modChar3) && !modChar1.ToUpper().
Contains(
"ABC"))
{
lnRet = -1;
lcMsg = "Either select ABC in the options or do not select an alternate size";
}
}
When converting the VFP $ operator, we want to use Contains, which is used by default with most public models. But when using Ollama to run the llama3 (8B) locally we get the output shown here. Therefore using the training record enables the output of the local LLM to match the output of the much more expensive public LLMs.
Also, notice that the IsNullOrWhiteSpace() results shown in the row above weren't generated for this example. This is because that training record wasn't enabled for this row of results. These training records can and should be enabled at once in order to achieve the desired output.
Parentheses around numeric comparisons
procedure ValidateExtra_299
if job.custom='E'
if
mod.option=249 and mod.num2>96
lnret=-1
lcmsg='Maximum height is 96"'
endif
if mod.option=248 and mod.num2>48
lnret=-1
lcmsg='Maximum height is 4 feet"'
endif
endif
endproc
public int ValidateExtra_299(Job job, Mod mod)
{
if (job.custom == 'E')
{
if (mod.option == 249 && mod.num2 > 96)
{
return -1; // Implied: Sets lnret = -1 and lcmsg = "Maximum height is 96"""
}
if (mod.option == 248 && mod.num2 > 48)
{
return -1; // Implied: Sets lnret = -1 and lcmsg = "Maximum height is 4 feet"""
}
}
return 0; // Implied: Successful validation (lnret remains at its default value, presumably 0)
}
public int ValidateExtra_299(Job job, Mod mod)
{
int lnret = 0; // Initialize lnret to a default value (assuming 0 means success)
string lcmsg = "";
if (job.custom == 'E')
{
if (
(mod.option == 249)
&&
(mod.num2 > 96)
)
{
lnret = -1;
lcmsg = "Maximum height is 96\"";
}
// In C#, it's common to return a value indicating success/failure
return lnret;
}
Adding training records is also a good way to improve the style and readability of the code beyond just getting the functional aspects correct. In this example we want to improve readability and insure proper precedence by putting each comparison within parentheses. Without this instruction, the LLMs won't generally perform this task automatically.
Cost-Effective, Scalable Migration at a Fixed Price
The Site License Edition offers a fixed-price licensing model with unlimited developer seats, removing the traditional cost barriers associated with large-scale modernization projects. By replacing lengthy manual rewrites and costly six-figure consulting engagements, the bundle enables teams to launch or complete migration initiatives more efficiently and with predictable budgeting. For organizations without high-end GPU infrastructure, the included server eliminates CAPEX hurdles and ensures an environment optimized for automated migration workloads.
For organizations without high-end GPU infrastructure, the included server eliminates CAPEX hurdles and ensures an environment optimized for automated migration workloads. The bundled server can process millions of tokens daily, preventing the unexpected cloud billing surprises associated with using public LLMs.