public string Run(string input, int startAt = 0)
        {
            Match match = xpoMatch.Match(input, startAt);

            if (match.Success)
            {
                string xml     = match.Value;
                string varName = match.Groups[1].Value.Trim();
                formName = match.Groups[2].Value.Replace('\"', ' ').Replace('\'', ' ').Trim();

                methodName = MetaData.extractPreviousXMLElement("Name", match.Index, input);

                if (MetaData.isCodeProtectedByMenuItem(input, match.Index))
                {
                    this.log("Clicked method protected by menu item.");
                    return(this.Run(input, match.Index + match.Length));;
                }

                if (xml.ToLowerInvariant().Contains(".menuitemname") ||
                    xml.ToLowerInvariant().Contains(".run(" + varName + ")"))
                {
                    this.log("Already uses menu item.");
                    return(this.Run(input, match.Index + match.Length));;
                }

                if (MetaData.isFormLookup(formName))
                {
                    this.log("Is lookup form");
                    return(this.Run(input, match.Index + match.Length));
                }

                if (MetaData.isFormDialog(formName))
                {
                    this.log("Is dialog form");
                    return(this.Run(input, match.Index + match.Length));
                }

                var datasources = MetaData.getFormRootDataSources(formName);

                if (datasources.Count == 0)
                {
                    this.log("Has no data sources");
                    return(this.Run(input, match.Index + match.Length));
                }

                bool allDatasourcesTmp = true;
                foreach (var table in datasources)
                {
                    if (MetaData.isTablePersisted(table))
                    {
                        allDatasourcesTmp = false;
                    }
                }

                if (allDatasourcesTmp)
                {
                    this.log("Only has temporary data sources");
                    return(this.Run(input, match.Index + match.Length));;
                }

                var menuItems = MetaData.getMenuItemsFromFormName(formName);
                if (menuItems.Count == 0)
                {
                    this.log("Has no menu item, but datasources: " + getMenuItemsAsString(datasources), "Warning");
                    return(this.Run(input, match.Index + match.Length));;
                }
                string menuItem = string.Empty;

                if (menuItems.Count == 1)
                {
                    menuItem = menuItems[0];
                    this.log("Has one menu item:" + menuItem + ", and datasources: " + getMenuItemsAsString(datasources), "Fixable");
                }

                if (menuItem == string.Empty && datasources.Count == 1)
                {
                    var formRef = MetaData.tableFormRef(datasources[0]);
                    if (formRef != string.Empty &&
                        menuItems.Contains(formRef))
                    {
                        if (MetaData.isFormUsingArgsMenuItemNameAndMenuItem(formName, formRef))
                        {
                            this.log("FormRef points to menu item, but form uses args.menuItemName() and menuitemdisplaystr(" + formRef + ")", "Warning");
                            return(this.Run(input, match.Index + match.Length));;
                        }
                        menuItem = formRef;
                        this.log("Has one data source with formRef: " + menuItem + ", and datasources: " + getMenuItemsAsString(datasources) + ", and menu items:" + getMenuItemsAsString(menuItems), "Fixable");
                    }
                }

                if (menuItem == string.Empty && menuItems.Contains(formName))
                {
                    menuItem = formName;
                    if (MetaData.isFormUsingArgsMenuItemName(formName))
                    {
                        this.log("Has multiple menu items:" + getMenuItemsAsString(menuItems) + ", and datasources: " + getMenuItemsAsString(datasources) + ", and form uses args.menuItemName().", "Warning");
                        return(this.Run(input, match.Index + match.Length));;
                    }
                    this.log("Updated. Has menu item with same name as form. Menu items:" + getMenuItemsAsString(menuItems) + ", and datasources: " + getMenuItemsAsString(datasources), "Fixable");
                }

                if (menuItem != string.Empty)
                {
                    int pos           = xml.IndexOf(';');
                    int nextLineStart = xml.ToLowerInvariant().IndexOfAny("abcdefghijklmnopqrstuvwxyz".ToCharArray(), pos);
                    if (nextLineStart > 0)
                    {
                        string whitespace = xml.Substring(pos, nextLineStart - pos);
                        xml = xml.Insert(nextLineStart, whitespace);
                        xml = xml.Insert(nextLineStart, varName + ".menuItemName(menuItemDisplayStr(" + menuItem + "))");
                        string updatedInput = input.Remove(match.Index, match.Length);
                        updatedInput = updatedInput.Insert(match.Index, xml);
                        Hits++;
                        return(this.Run(updatedInput, match.Index + match.Length));
                    }
                    else
                    {
                        this.log("Cannot update file due to format", "Error");
                    }
                }
                else
                {
                    this.log("Has multiple menu items:" + getMenuItemsAsString(menuItems) + ", and datasources: " + getMenuItemsAsString(datasources), "Warning");
                }

                return(this.Run(input, match.Index + match.Length));
            }

            return(input);
        }