void doItemCheck(int method)
        {
            if (filename != "ItemInfo.shn")
            {
                MessageBox.Show("ItemInfo.shn is not open; please open it and select it as the current tab before opening the Item Validator");
            }
            else
            {
                String input = "";
                if (method == 1) // get text from clipboard
                {
                    if (!Clipboard.ContainsText(TextDataFormat.UnicodeText))
                    {
                        MessageBox.Show("Your clipboard is empty; is should be filled with records of a merchant file. Example:\n#Record 0  ShortSword bla one -   - -\n#record 3 blabla two   -   -   -");
                    }
                    else
                    {
                        input = Clipboard.GetText(TextDataFormat.UnicodeText);
                    }
                }
                else // get text from textbox
                {
                    input = richTextBox1.Text;
                }
                if (input == "")
                {
                    MessageBox.Show("Input appears to be empty (empty textbox or clipboard)\nFunction aborted.");
                }
                else
                {
                    richTextBox2.Text = ""; // clear output log

                    //use helper for extra functions shared between More Tools features
                    helper myLittleHelper = new helper();

                    List <String> parsed = myLittleHelper.parseDatas(input, '\n');
                    List <SHNDecrypt.More_Tools.helper.merchantRow> m = myLittleHelper.parseMerchantDatas(parsed);
                    String outstr     = "";
                    int    wrongItems = 0;
                    String wrongList  = "";
                    int    rownum     = m.Count;
                    for (int xint = 0; xint < rownum; xint++)
                    {
                        for (int xint2 = 0; xint2 < 6; xint2++)
                        {
                            // if item slot == '-' then skip this item
                            // that should really save time for empty item slots
                            if (m[xint].items[xint2] == "-")
                            {
                                continue;
                            }
                            bool found = false;
                            foreach (DataGridViewRow row in rows)
                            {
                                String compareString = "";
                                try
                                {
                                    compareString = rows[row.Index].Cells[1].Value.ToString();
                                }
                                catch (Exception ee)
                                {
                                    String wrongStr = "[ " + (wrongItems + 1) + " ] Record # " + m[xint].rowID + ", item slot " + xint2 + " => item name '" + m[xint].items[xint2] + "'";
                                    wrongList += wrongStr + "\n";
                                    break;
                                }
                                if (compareString == m[xint].items[xint2])
                                {
                                    found = true;
                                    break;
                                }
                            }
                            if (!found)
                            {
                                m[xint].items[xint2] = "-";
                                wrongItems++;
                            }
                        }
                    }
                    outstr = myLittleHelper.writeMerchantRowsToClipboard(m);
                    if (method == 1) // copy back to clipboard
                    {
                        Clipboard.SetText(outstr, TextDataFormat.UnicodeText);
                    }
                    else // display in form's textbox
                    {
                        richTextBox1.Text = outstr;
                    }
                    String logstr = "Done.";
                    String txtstr = "Done.";
                    if (method == 1)
                    {
                        txtstr += " New merchant data has been copied to your clipboard";
                        logstr += " Clipboard has been modified.";
                    }
                    logstr += "\n";
                    txtstr += "\n";
                    if (wrongItems == 0)
                    {
                        txtstr += "There were no invalid items in the shop.\n";
                        logstr += "There were no invalid items in the shop.\n";
                    }
                    else
                    {
                        txtstr += "There were " + wrongItems + " invalid items that were removed.";
                        logstr += "There were " + wrongItems + " invalid items that were removed.";
                        logstr += "\n\nThe following items were removed:\n";
                        logstr += wrongList;
                    }
                    label1.Text       = "Done! " + wrongItems + " invalid items removed!";
                    richTextBox2.Text = logstr;
                }
            }
        }
        private void executeExpression()
        {
            String str = textBox1.Text;

            if (str == "")
            {
                log("Expression was empty -- could not execute.");
            }
            else
            {
                log("\nExecuting expression...");
                string explanation = "Proper input: [Lvl(s)] [optype] [opvalue]\ndelimited by space\nLvl(s) can be '4' to specify the lvl 4, or '2~4' to inclusively specify all levels 2, 3, and 4. can also be something like '>4' to mean all lvls greater than 4, or '<100', for less than lvl 100\nOpcodes acceptable: '=' '+' '-' '*' '/'\nOpvalue is the amount to add / multiply / etc, and this value can be float (ex. 9, 2.1, 0.5, etc)\n\nThis function changes all exp in mobInfoServer.shn by the specified optype to the specified opvalue where the level is within the specified lvl range";
                string examples    = "\n\nExamples:\n1 = 10000000 set exp for lvl 1s (slime only?) to 10,000,000\n>100 * 50    multiply exp by 50 for monsters lvls 101+\n1~150 = 1    set exp for all monsters (lvls 1-150) to 1\n>4 * 1515\t\tMultiply exp of all monsters lvl 5+ by 1515\n75~90  * 2.5\t\tMultiply exp of all monsters lvls 75-90 by 2.5";
                explanation += examples;
                // set row[x]exp to value *,+,etc opvalue
                int   changed = 0;
                char  optype  = '=';
                float opvalue = 1.0f;
                int   minLvl  = 0;
                int   maxLvl  = 500;

                //use helper for extra functions shared between More Tools features
                helper ineedhelp = new helper();


                /**     ////////////
                 * //         now get input
                 **/
                /////////////

                // the input for this: [Lvl(s)] [optype] [opvalue]
                // delimited by a space
                // example: 80~90 * 5
                // the above example multiplies exp for all lvls 80-90 (inclusive) by 5
                // other examples:
                // 1 = 10000000 set exp for lvl 1s (slime only?) to 10,000,000
                // >100 * 50    multiply exp by 50 for monsters lvls 101+
                // 1~150 = 1    set exp for all monsters (lvls 1-150) to 1
                List <string> data = ineedhelp.parseDatas(str, ' ');

                // need 3 arguments
                if (data.Count != 3)
                {
                    MessageBox.Show("Incorrect number of arguments; you need 3 arguments and only " + data.Count + " were found.\n" + explanation);
                    log("Execution failed.");
                    log("Incorrect number of arguments; you need 3 arguments and only " + data.Count + " were found.");
                    return;
                }

                // now check that the level parameter is OK and get lvl range
                if (data[0].IndexOf("~") != -1)
                {
                    if (data[0].IndexOf(">") != -1 || data[0].IndexOf("<") != -1)
                    {
                        MessageBox.Show("Problem in syntax: cannot have both '~' and either '>' or '<' in level parameter\n\n" + explanation);
                        log("Execution failed.");
                        log("Syntax error: cannot use both '~' and '<' / '<'");
                        return;
                    }
                    string strmin         = "";
                    string strmax         = "";
                    bool   fulcrumReached = false;
                    int    l = data[0].Length;
                    for (int xint = 0; xint < l; xint++)
                    {
                        if (data[0][xint] == '~')
                        {
                            fulcrumReached = true;
                        }
                        else
                        {
                            if (fulcrumReached)
                            {
                                strmax += data[0][xint];
                            }
                            else
                            {
                                strmin += data[0][xint];
                            }
                        }
                    }
                    if (strmin == "")
                    {
                        MessageBox.Show("The minimum level was invalid!\nYou entered '" + strmin + "' before '~'");
                        log("Execution failed.");
                        log("Minimum level invalid; you entered '" + strmin + "' before '~'");
                        return;
                    }
                    else if (strmax == "")
                    {
                        MessageBox.Show("The maximum level was invalid!\nYou entered '" + strmax + "' after '~'");
                        log("Execution failed.");
                        log("Maximum level invalid; you entered '" + strmax + "' before '~'");
                        return;
                    }
                    try
                    {
                        minLvl = int.Parse(strmin);
                    }
                    catch (Exception ee)
                    {
                        MessageBox.Show("The minimum level you entered seemed be in an unaccaptable format (included some non-numerical characters?)\nYour minLvl: '" + strmin + "'");
                        log("Execution failed.");
                        log("Minimum level invalid: Excpetion triggered. The number you entered was in an unacceptable format (included non-numerical characters?)\nYour minLvl: '" + strmin + "'");
                        return;
                    }
                    try
                    {
                        maxLvl = int.Parse(strmax);
                    }
                    catch (Exception ee)
                    {
                        MessageBox.Show("The maximum level you entered seemed be in an unaccaptable format (included some non-numerical characters?)\nYour maxLvl: '" + strmax + "'");
                        log("Execution failed.");
                        log("Maximum level invalid: Excpetion triggered. The number you entered was in an unacceptable format (included non-numerical characters?)\nYour maxLvl: '" + strmax + "'");
                        return;
                    }
                }
                else if (data[0].IndexOf(">") != -1)
                {
                    try
                    {
                        string newint = "";
                        int    l      = data[0].Length;
                        for (int xint = 1; xint < l; xint++)
                        {
                            newint += data[0][xint];
                        }
                        minLvl  = int.Parse(newint);
                        minLvl += 1; // so > this lvl
                    }
                    catch (Exception ee)
                    {
                        MessageBox.Show("The level you specified contained illegal / non-numerical characters and was therefore invalid\nYour specified level: '" + data[0] + "'");
                        log("Execution failed.");
                        log("Invalid level specified; level contained illegal / non-numerical characters\nYour specified level: '" + data[0] + "'");
                        return;
                    }
                }
                else if (data[0].IndexOf("<") != -1)
                {
                    try
                    {
                        string newint = "";
                        int    l      = data[0].Length;
                        for (int xint = 1; xint < l; xint++)
                        {
                            newint += data[0][xint];
                        }
                        maxLvl  = int.Parse(newint);
                        maxLvl -= 1; // so < this lvl
                    }
                    catch (Exception ee)
                    {
                        MessageBox.Show("The level you specified contained illegal / non-numerical characters and was therefore invalid\nYour specified level: '" + data[0] + "'");
                        log("Execution failed.");
                        log("Invalid level specified; level contained illegal / non-numerical characters\nYour specified level: '" + data[0] + "'");
                        return;
                    }
                }
                else
                {
                    try
                    {
                        minLvl = int.Parse(data[0]);
                        maxLvl = int.Parse(data[0]);
                    }
                    catch (Exception ee)
                    {
                        MessageBox.Show("The level you specified contained illegal / non-numerical characters and was therefore invalid\nYour specified level: '" + data[0] + "'");
                        log("Execution failed.");
                        log("Invalid level specified; level contained illegal / non-numerical characters\nYour specified level: '" + data[0] + "'");
                        return;
                    }
                }
                if (data[1].Length == 0)
                {
                    MessageBox.Show("You must specify an optype! (currently optype is empty!)\n" + explanation);
                    log("Execution failed.");
                    log("You must specify an operator/optype! You may see Help for more information.");
                    return;
                }
                optype = data[1][0];
                try
                {
                    opvalue = float.Parse(data[2]);
                }
                catch (Exception ee)
                {
                    MessageBox.Show("The opvalue you specified contained illegal / non-numerical characters and was therefore invalid\nYour specified opvalue: '" + data[2] + "'");
                    log("Execution failed.");
                    log("The operation value you specified contained illegal / non-numerical characters and was therefore invalid.\nYour specified value: '" + data[2] + "'");
                    return;
                }



                /**     so now
                 *          actually do the modification
                 * **/

                if (rows.Count < 1)
                {
                    MessageBox.Show("Error: no rows in datagrid");
                    log("Execution failed.");
                    log("Error: no rows in datagrid; you must not have any .shn files open?");
                    return;
                }
                if (optype == '=')
                {
                    foreach (DataGridViewRow row in this.rows)
                    {
                        try
                        {
                            if (row.Cells[0].Value == null)
                            {
                                continue;
                            }
                            int id = int.Parse(row.Cells[0].Value.ToString());
                            if (monLvls[id] >= minLvl & monLvls[id] <= maxLvl)
                            {
                                row.Cells[9].Value = (UInt32)opvalue;
                                changed++;
                            }
                        }
                        catch (Exception ee)
                        {
                            MessageBox.Show("Problem performing exp modification (setting equal to)...\n" + ee.StackTrace);
                            log("Execution failed.");
                            log("Exception: Failed to perform exp modification for optype '=' (set equal to)");
                        }
                    }
                }
                else if (optype == '+')
                {
                    foreach (DataGridViewRow row in this.rows)
                    {
                        try
                        {
                            if (row.Cells[0].Value == null)
                            {
                                continue;
                            }
                            int id = int.Parse(row.Cells[0].Value.ToString());
                            if (monLvls[id] >= minLvl & monLvls[id] <= maxLvl)
                            {
                                row.Cells[9].Value = UInt32.Parse(row.Cells[9].Value.ToString()) + (UInt32)opvalue;
                                changed++;
                            }
                        }
                        catch (Exception ee)
                        {
                            MessageBox.Show("Problem performing exp modification for addition...\n" + ee.StackTrace);
                            log("Execution failed.");
                            log("Exception: Failed to perform exp modification for optype '+' (addition)");
                        }
                    }
                }
                else if (optype == '-')
                {
                    foreach (DataGridViewRow row in this.rows)
                    {
                        try
                        {
                            if (row.Cells[0].Value == null)
                            {
                                continue;
                            }
                            int id = int.Parse(row.Cells[0].Value.ToString());
                            if (monLvls[id] >= minLvl & monLvls[id] <= maxLvl)
                            {
                                row.Cells[9].Value = UInt32.Parse(row.Cells[9].Value.ToString()) - (UInt32)opvalue;
                                changed++;
                            }
                        }
                        catch (Exception ee)
                        {
                            MessageBox.Show("Problem performing exp modification for subtraction...\n" + ee.StackTrace);
                            log("Execution failed.");
                            log("Exception: Failed to perform exp modification for optype '-' (subtraction)");
                        }
                    }
                }
                else if (optype == '*')
                {
                    foreach (DataGridViewRow row in this.rows)
                    {
                        try
                        {
                            if (row.Cells[0].Value == null)
                            {
                                continue;
                            }
                            int id = int.Parse(row.Cells[0].Value.ToString());
                            if (monLvls[id] >= minLvl & monLvls[id] <= maxLvl)
                            {
                                row.Cells[9].Value = (UInt32)(float.Parse(row.Cells[9].Value.ToString()) * opvalue);
                                changed++;
                            }
                        }
                        catch (Exception ee)
                        {
                            MessageBox.Show("Problem performing exp modification for multiplication...\n" + ee.StackTrace);
                            log("Execution failed.");
                            log("Exception: Failed to perform exp modification for optype '*' (multiplication)");
                        }
                    }
                }
                else if (optype == '/')
                {
                    foreach (DataGridViewRow row in this.rows)
                    {
                        try
                        {
                            if (row.Cells[0].Value == null)
                            {
                                continue;
                            }
                            int id = int.Parse(row.Cells[0].Value.ToString());
                            if (monLvls[id] >= minLvl & monLvls[id] <= maxLvl)
                            {
                                row.Cells[9].Value = (UInt32)(float.Parse(row.Cells[9].Value.ToString()) / opvalue);
                                changed++;
                            }
                        }
                        catch (Exception ee)
                        {
                            MessageBox.Show("Problem performing exp modification for division...\n" + ee.StackTrace);
                            log("Execution failed.");
                            log("Exception: Failed to perform exp modification for optype '/' (division)");
                        }
                    }
                }
                else
                {
                    MessageBox.Show("Opcode unknown! Acceptable values:\n=\n+\n-\n*\n/");
                    log("Execution failed.");
                    log("Unkown operator; you entered an invalid operator: '" + data[1] + "'");
                    return;
                }
                MessageBox.Show("Done! Changed exp for " + changed + " monsters!\n\nRan with these parameters:\nminLvl = " + minLvl + "\nmaxLvl = " + maxLvl + "\noptype = " + optype + "\nopvalue = " + opvalue + "\t (UInt32: " + (UInt32)opvalue + " )");
                log("Execution succeeded!");
                log("Changed exp for " + changed + " monsters!\nExpression log: " + str);
            }
        }
        void sortItems(int method)
        {
            String input = "";

            if (method == 1) // get text from clipboard
            {
                if (!Clipboard.ContainsText(TextDataFormat.UnicodeText))
                {
                    MessageBox.Show("Your clipboard is empty; is should be filled with records of a merchant file. Example:\n#Record 0  ShortSword bla one -   - -\n#record 3 blabla two   -   -   -");
                }
                else
                {
                    input = Clipboard.GetText(TextDataFormat.UnicodeText);
                }
            }
            else // get text from textbox
            {
                input = richTextBox1.Text;
            }
            if (input == "")
            {
                MessageBox.Show("Input appears to be empty (empty textbox or clipboard)\nFunction aborted.");
                return;
            }

            //use helper for extra functions shared between More Tools features
            helper cantHelpMyself = new helper();

            // get items as a list
            List <String> lines   = cantHelpMyself.parseDatas(input, '\n');
            List <String> myItems = new List <String>();
            List <String> rowNums = new List <String>(); // preserve row nums

            for (int xint = 0, l = lines.Count; xint < l; xint++)
            {
                List <String> merchParts = cantHelpMyself.parseDatas(lines[xint], '\t');
                if (merchParts.Count > 1)
                {
                    rowNums.Add(merchParts[1]);
                }
                for (int zint = 2, l2 = merchParts.Count; zint < l2; zint++)
                {
                    if (merchParts[zint] != "" && merchParts[zint] != "-" && merchParts[zint] != "\r")
                    {
                        myItems.Add(merchParts[zint]);
                    }
                }
            }

            // write items out in the order they were picked up
            int    l3         = rowNums.Count;
            int    l4         = myItems.Count;
            int    yint       = 0;
            String outstr     = "";
            int    failsafe   = 1000; // after adding 1000 items to list, break out of while loop
            int    itemsAdded = 0;
            List <SHNDecrypt.More_Tools.helper.merchantRow> outRows = new List <SHNDecrypt.More_Tools.helper.merchantRow>();

            while (yint < l3 && itemsAdded < failsafe)
            {
                SHNDecrypt.More_Tools.helper.merchantRow newRow = new SHNDecrypt.More_Tools.helper.merchantRow();
                newRow.rowID = int.Parse(rowNums[yint]);
                newRow.items = new String[6];
                for (int xint = 0, max = (l4 - itemsAdded < 6 ? (l4 - itemsAdded) : (6)); xint < max; xint++)
                {
                    newRow.items[xint] = myItems[itemsAdded];
                    itemsAdded++;
                }
                outRows.Add(newRow);
                yint++;
            }

            outstr = cantHelpMyself.writeMerchantRowsToClipboard(outRows);
            String outstr2 = "Text sorted.";

            if (method == 1) // copy back to clipboard
            {
                Clipboard.SetText(outstr, TextDataFormat.UnicodeText);
                outstr2 += "\nOutput: Clipboard";
            }
            else // display in form's textbox
            {
                richTextBox1.Text = outstr;
                outstr2          += "\nOutput: Textbox";
            }
            richTextBox2.Text = outstr2;
            label1.Text       = outstr2;
        }