Artem's blog

Mainly .NET (C#, ASP.NET) and my projects

Archives for Programming Tips

Creating a programming language with Mathos Parser (2)

In this article, I would like to find out whether it is possible to construct a programming language with Mathos Parser. In general, the question is if a simple expression parser has the necessary things to easily convert it into a language.

The answer is yes, but the language will be very limited if additional features are not added. The reason for this is because what most languages have in common is some sort of  user/machine interaction, while an expression parser only allows you to parse mathematical things and is not really designed to interpret how to write to a file or allocate memory.

For example, imagine you want to create something similar to if statements  and you decide to treat an if as a function. You would use following code:

parser.LocalFunctions.Add("if", x =>
{
    if (x[0] == 1)
    {
        return x[1];
    }
    else
    {
        if (x.Length == 3)
        {
            return x[2];
        }
        else
        {
            return 0;
        }
    }
});

So, if whatever we pass into the first parameter is true, the value in the second parameter will be returned. This is quite cool, but it does not allow us to return a series of statements. Instead, we could design a new kind of if statement that would, depending on the result from this if function, execute the right method. Here is how I solved it:

let a = get()               # ask for user input

if(a>3,1, 0)                # it only returns a number
1-> write It is true        # these execute something depending on result
0-> write It is false

As you can see, the if statement is still there, but there is now a feature that will interpret the result and make something happen. You can also use \n to separate between different statements and also name a collection of statements, as shown below:

# Using statements as small methods
# The first result will not use statement,
# the second one will.

notTrue : title Not true \n write Your number is smaller than five (or equal to) \n pause

write Type a number between 1-10

let b be get()

if(b>5, 1, 0)
1-> title A New title! \n write Your number is greater than five! \n pause
0-> notTrue

Note that both examples use a function get(). It can also be implemented as a function:

parser.LocalFunctions.Add("get", x =>
{
    return System.Convert.ToDecimal(Console.ReadLine());
}
);

You might have noticed the use of statements (see notTrue statement). Their role is to simulate a method. Everything you enter into a statement will not be executed until you call it, so you can insert undefined variables into a statement when you define it and later assign them with a value. I have also added commands like write, title, pause, clear and end. These are extensions to the language and are interpreted in the method below:

static void command(Mathos.Parser.MathParser parser, string input, Dictionary<string, string> statement, ref decimal lastResult)
{
    try
    {
        input = Regex.Replace(input, "#\\{.*?\\}#", ""); // Delete Comments #{Comment}#
        input = Regex.Replace(input, "#.*$", ""); // Delete Comments #Comment

        input = Regex.Replace(input, @"[0-9]+\!", new MatchEvaluator(FactorialString));

        input = Regex.Replace(input, @"^\s+", "");

        if (input != "")
        {
            if (input.StartsWith("write"))
            {
                Console.WriteLine(input.Substring(6));
            }
            else if (input.StartsWith("title"))
            {
                Console.Title = input.Substring(6);
            }
            else if (input.StartsWith ("clear"))
            {
                Console.Clear();
            }
            else
            {
                if (input.Contains("->"))
                {
                    int index = input.IndexOf("->");

                    if (lastResult == System.Convert.ToDecimal(input.Substring(0, index)))
                    {
                        mCommand(parser, input.Substring(index + 2), statement, ref lastResult);
                    }
                }
                else
                {
                    if (input.Contains(":") && input.Contains(":=") == false)
                    {
                        int index = input.IndexOf(":");

                        statement.Add(input.Substring(0, index).Replace(" ", ""), input.Substring(index + 1, input.Length - index - 1));

                    }
                    else if (input.StartsWith("pause"))
                    {
                        Console.ReadKey();

                    }
                    else if (input.StartsWith("end"))
                    {
                        Environment.Exit(0);
                    }

                    else
                    {
                        foreach (var item in statement)
                        {
                            if (input.Contains(item.Key))
                            {
                                input = "";
                                mCommand(parser, item.Value, statement, ref lastResult);
                            }
                        }
                        lastResult = parser.ProgrammaticallyParse(input, identifyComments: false);
                        Console.WriteLine(lastResult);
                    }
                }
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine("An error occured. Message: " + e.Message);
    }
}

static void mCommand(Mathos.Parser.MathParser parser, string input, Dictionary<string, string> statement, ref decimal lastResult)
{
    input = input.Replace(@"\n", System.Environment.NewLine);

    System.IO.StringReader sr = new System.IO.StringReader(input);

    string _input = sr.ReadLine();

    while (_input != null)
    {
        command(parser, _input, statement, ref lastResult);
        _input = sr.ReadLine();
    }
    sr.Close();
}

Some programmers will certainly argue that the code above is not that optimized and is quite primitive. Well, it serves its purpose and makes Mathos Parser look more like a language.

In the next article I want to implement a while feature into this awesome programming language.

Conclusion: Just because something can parse expressions does not mean it can parse a series of statement. In order to fix this we can either choose to add some features externally, or, go into the parser itself and make it more adjusted to this particular task. This language does not alter Mathos Parser in any way.

Downloads:

Factorial notation in Mathos Parser (1)

In this article series, I would like to look at how Mathos Parser (a very simple expression parser) can be used to perform things that were not originally intended. Today, I am going to show what has to be done to make Mathos Parser able to interpret factorial notation, such as “4!

Already in the parser, we can solve this in at least two different ways:

  • creating a localFunction fact() that will take one parameter and return the factorial of that number
  • using FactorialPower(falling power) instead, that is 4!4 would be 24 and 4!1=4.

Both methods do not require you to change anything in the input string, but they might not be as close to the mathematical notation as we want it to be. Therefore, as a part of this article, I am going to illustrate the changes in the input string that have to be made, to make it understand 4!.

  1. Include Reg Ex name space as following:
    using System.Text.RegularExpressions;
  2. Add these two methods somewhere in the class:
    static decimal factorial(decimal x)
    {
        if(x==1 || x== 0)
        {
            return 1;
        }
        else
        {
            return x * factorial(x - 1);
        }
    }
    
    static string FactorialString(Match m)
    {
        return m.Value + "0";
    }
  3. Define the Mathos Parser and add a definition of the factorial operator including the way it should be executed. Note, at this stage, for this to work, the factorial number has to be in the form of 4!0 or 4!1 ((both result in 24).
    Mathos.Parser.MathParser parser = new Mathos.Parser.MathParser();
    
    parser.OperatorList = new List<string>() {"!" ,"%","^", "/", "*",  "-", "+"}; // removed ":" for division
    parser.OperatorAction.Add("!", (x, y) => factorial(x));
  4. Before the input string can be parsed, perform the following action (assuming you have defined a variable input with a value):
    input = Regex.Replace(input, @"[0-9]+\!", new MatchEvaluator(FactorialString));
  5. Parser the string and store the result:
    decimal result = parser.Parse(input);

This is how we can make Mathos Parser able to understand mathematical notation of factorial. In the next article of this series, we are going to look at how Mathos Parser can be used to construct a new programming language.

A possible change for machine code

In the recent issue, it was reported that machine codes are repeated approximately once per 50 different machines in SKGL 2.0.5.3. The reasons under investigation are:

  • small hash value allows even more collisions.
  • the machine information that is being hashed does not collect all hardware that can be changed.

The first reason is currently in focus, and I have tried to develop a piece of code that now increases the length of the machine code. It would be great if those of you who are able to test this on several machines could do so, and comment(either directly below this thread or here) how frequent the collisions are on different machines! Thank you in advance! 🙂

EDIT 2: This can be done by anyone using Windows:

  1. Download the software below (no installation required): (or download the exe file directly here) NOTE: In Google Chrome, it might tell that the file is dangerous because it is not commonly downloaded. Please right click and press keep.

Machinecode experiment

EDIT: You can also write the machine code you get on your own computer and post it below this thread. (hardware info using dxdiag would be awesome, but the machine code is more important at this point)

public class AnalysisOfMachineCode
{
    [TestMethod]
    public void test()
    {
        Debug.WriteLine(getMachineCode());
    }


    [SecuritySafeCritical]
    public static int getMachineCode()
    {
        ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_Processor");
        string collectedInfo = "";
        // here we will put the informa
        foreach (ManagementObject share in searcher.Get())
        {
            // first of all, the processorid
            collectedInfo += share.GetPropertyValue("ProcessorId");
        }

        searcher.Query = new ObjectQuery("select * from Win32_BIOS");
        foreach (ManagementObject share in searcher.Get())
        {
            //then, the serial number of BIOS
            collectedInfo += share.GetPropertyValue("SerialNumber");
        }

        searcher.Query = new ObjectQuery("select * from Win32_BaseBoard");
        foreach (ManagementObject share in searcher.Get())
        {
            //finally, the serial number of motherboard
            collectedInfo += share.GetPropertyValue("SerialNumber");
        }

        // patch luca bernardini
        if (string.IsNullOrEmpty(collectedInfo) | collectedInfo == "00" | collectedInfo.Length <= 3)
        {
            collectedInfo += getHddSerialNumber();
        }

        return getEightByteHash(collectedInfo, 1000000);
    }

    [SecuritySafeCritical]
    public static string getHddSerialNumber()
    {


        // --- Win32 Disk 
        ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\root\\cimv2", "select * from Win32_DiskPartition WHERE BootPartition=True");

        uint diskIndex = 999;
        foreach (ManagementObject partition in searcher.Get())
        {
            diskIndex = Convert.ToUInt32(partition.GetPropertyValue("Index"));
            break; // TODO: might not be correct. Was : Exit For
        }

        // I haven't found the bootable partition. Fail.
        if (diskIndex == 999)
            return string.Empty;



        // --- Win32 Disk Drive
        searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive where Index = " + diskIndex.ToString());

        string deviceName = "";
        foreach (ManagementObject wmi_HD in searcher.Get())
        {
            deviceName = wmi_HD.GetPropertyValue("Name").ToString();
            break; // TODO: might not be correct. Was : Exit For
        }


        // I haven't found the disk drive. Fail
        if (string.IsNullOrEmpty(deviceName.Trim()))
            return string.Empty;

        // -- Some problems in query parsing with backslash. Using like operator
        if (deviceName.StartsWith("\\\\.\\"))
        {
            deviceName = deviceName.Replace("\\\\.\\", "%");
        }


        // --- Physical Media
        searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia WHERE Tag like '" + deviceName + "'");
        string serial = string.Empty;
        foreach (ManagementObject wmi_HD in searcher.Get())
        {
            serial = wmi_HD.GetPropertyValue("SerialNumber").ToString();
            break; // TODO: might not be correct. Was : Exit For
        }

        return serial;

    }

    public static int getEightByteHash(string s, int MUST_BE_LESS_THAN = 1000000000)
    {
        //This function generates a eight byte hash

        //The length of the result might be changed to any length
        //just set the amount of zeroes in MUST_BE_LESS_THAN
        //to any length you want
        uint hash = 0;

        foreach (byte b in System.Text.Encoding.Unicode.GetBytes(s))
        {
            hash += b;
            hash += (hash << 10);
            hash ^= (hash >> 6);
        }

        hash += (hash << 3);
        hash ^= (hash >> 11);
        hash += (hash << 15);

        int result = (int)(hash % MUST_BE_LESS_THAN);
        int check = MUST_BE_LESS_THAN / result;

        if (check > 1)
        {
            result *= check;
        }

        return result;
    }

}

Two new videos about Serial Key Manager

This week I was able to record two new videos that describe the process of external validation of a license key using Serial Key Manager. Now, my final aim is to record a third, last video about the way the local time can be synced with a server to prevent user from gaining more days than allowed by a license.

Below are the videos:

An article about Licensing systems

This is an article about three different licensing systems, using C#.NET environment.

Title: Three different algorithms for constructing licensing systems, their advantages and disadvantages using C# .NET environment.

Abstract: A key validation algorithm is one of the important parts in the protection of a computer application. Even if an already existing API is to be used, it is important to understand its weaknesses in order to compare it with alternative ones. Therefore, in this article, three different categories will be described with clear definitions that will make it possible to distinguish between them and allow an analysis of currently existing APIs. Every category is accompanied with examples and in some cases suggestions for further development. The categories described in this article are Checksum based key validation, Pattern based key validation, and Information based key validation. It is going to be found that the choice of a key validation system depends on the information that is to be stored in the key. It is also concluded that at this point it would be better to use online key validation instead.

SKGL 2.0.5.3

Released a new patch for SKGL (now 2.0.5.3) which fixes the MachineCode error:

Release notes:

fixed bug https://skgl.codeplex.com/workitem/2166. Now, SKGL 2.0.5.3 although it will be find in the 2.0.5.2 solution. thanks to dprotopopov for bug report.

Summary: there was an issue with machine code calculation because of permission settings.

EDIT: fixed it for Virtual Box environment too.

Fix can be downloaded from: https://skgl.codeplex.com/releases/view/121143

NuGet users should have also received the update in the package manager.

Edit to the last section in Number Games

In my booklet, Algorithms via C#, a way to make the computer guess the numbers more efficiently is presented (see pp. 12-13). Let’s quickly remind ourselves about the problem: we want to make the computer guess a number, between 0 to 100, with minimal amount of questions. It is concluded that we should start with 50, then 25, then 12, etc., that is, divide 100 by 2^k  and depending on if the number is less than what computer guessed, we should either add or subtract this factor.

Everything is correct, but I would like to emphasize that this value can be computed without division.

⌊100/2^1⌋ = 50 = (110010)2
⌊100/2^2⌋ = 25 = (11001)2
⌊100/2^3⌋= 12 = (1100)2
⌊100/2^4⌋= 6 = (110)2
⌊100/2^5⌋= 3 = (11)2
⌊100/2^6⌋= 1 = (1)2

As you can see, in base 2, you simply remove the least significant bit each time. This might save time if you work in radix 2.

A simple way to integrate PayPal into ASP.NET MVC 4

This week I was working on PayPal integration in Serial Key Manager(http://serialkeymanager.com/). Some time I spent trying to understand how this can be accomplished using a server language, ASP.NET, since I have not been able to find a clear tutorial that would be easy to follow, So, in this guide I am going to outline how the entire process works and provide you with working examples!

1. Setting up the development tools

The first thing you need is to create a PayPal developer account so that you can access this page https://developer.paypal.com/webapps/developer/applications/myapps. When you press on Sandbox accounts to the left of the page, you will have the option to create two types of accounts: Personal or Business

  • Personal account will be used when you buy your product
  • Business account is the account that will receive the payment from the Personal account.

Depending on how much your product will cost, you will have to insert an appropriate amount of money into the Personal account. I think you can have as much as you like since it is only for testing purposes.

2. Creating the button

Now, you will have to create two Views in a Controller, one where you have the button and one where you have the validation mechanism. Let’s start with the button! Put the code below into any View. My View name is IPN in the User controller.

<!-- When you are done with all testing and want to change to the real PayPal, use following instead-->
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<!-- end of Real PayPal example-->

<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post">
	<fieldset>
		<input class="full-width" type="hidden" name="business" value="<!--enter the Business account email here-->">
		<input type="hidden" name="cmd" value="_xclick">
		<input type="hidden" name="item_name" value="The unlimited music download subscription">
		<input type="hidden" name="amount" value="9">
		<input type="hidden" name="no_shipping" value="1">
		<input type=hidden name=RETURNURL
			   value="http://example.com/User/IPN">
		<input type="hidden" name="return" value="http://example.com/User/IPN">
		<input type="hidden" name="notify_url" value="http://example.com/User/IPN">

		<button type="submit">Order now!</button>
	</fieldset>
</form>

3. Processing the information returned by PayPal

The example code is based on this code. Please take a look at it to see how it is done with several variables.

Now you need to create a new View in the controller, called IPN. Insert the following code:

public ActionResult IPN()
{

    var order = new Order(); // this is something I have defined in order to save the order in the database

    // Receive IPN request from PayPal and parse all the variables returned
    var formVals = new Dictionary<string, string>();
    formVals.Add("cmd", "_notify-synch"); //notify-synch_notify-validate
    formVals.Add("at", "this is a long token found in Buyers account"); // this has to be adjusted
    formVals.Add("tx", Request["tx"]);

    // if you want to use the PayPal sandbox change this from false to true
    string response = GetPayPalResponse(formVals, false);

    if (response.Contains("SUCCESS"))
    {
        string transactionID = GetPDTValue(response, "txn_id"); // txn_id //d
        string sAmountPaid = GetPDTValue(response,"mc_gross"); // d
        string deviceID = GetPDTValue(response, "custom"); // d
        string payerEmail = GetPDTValue(response,"payer_email"); // d
        string Item = GetPDTValue(response,"item_name");

        //validate the order
        Decimal amountPaid = 0;
        Decimal.TryParse(sAmountPaid, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out amountPaid);

        if (amountPaid == 9 )  // you might want to have a bigger than or equal to sign here!
        {
            if (orders.Count(d => d.PayPalOrderRef == transactionID) < 1)
            {
				//if the transactionID is not found in the database, add it
				//then, add the additional features to the user account
            }
            else
            {
				//if we are here, the user must have already used the transaction ID for an account
				//you might want to show the details of the order, but do not upgrade it!
            }
            // take the information returned and store this into a subscription table
            // this is where you would update your database with the details of the tran

            //return View();

        }
        else
        {
            // let fail - this is the IPN so there is no viewer
            // you may want to log something here
            order.Comments = "User did not pay the right ammount.";

			// since the user did not pay the right amount, we still want to log that for future reference.

            _db.Orders.Add(order); // order is your new Order
            _db.SaveChanges();
        }

    }
    else
    {
        //error
    }
    return View();
}

string GetPayPalResponse(Dictionary<string, string> formVals, bool useSandbox)
{

    string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr"
        : "https://www.paypal.com/cgi-bin/webscr";

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(paypalUrl);

    // Set values for the request back
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";

    byte[] param = Request.BinaryRead(Request.ContentLength);
    string strRequest = Encoding.ASCII.GetString(param);

    StringBuilder sb = new StringBuilder();
    sb.Append(strRequest);

    foreach (string key in formVals.Keys)
    {
        sb.AppendFormat("&{0}={1}", key, formVals[key]);
    }
    strRequest += sb.ToString();
    req.ContentLength = strRequest.Length;

    //for proxy
    //WebProxy proxy = new WebProxy(new Uri("http://urlort#");
    //req.Proxy = proxy;
    //Send the request to PayPal and get the response
    string response = "";
    using (StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII))
    {

        streamOut.Write(strRequest);
        streamOut.Close();
        using (StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream()))
        {
            response = streamIn.ReadToEnd();
        }
    }

    return response;
}
string GetPDTValue(string pdt, string key)
{

    string[] keys = pdt.Split('\n');
    string thisVal = "";
    string thisKey = "";
    foreach (string s in keys)
    {
        string[] bits = s.Split('=');
        if (bits.Length > 1)
        {
            thisVal = bits[1];
            thisKey = bits[0];
            if (thisKey.Equals(key, StringComparison.InvariantCultureIgnoreCase))
                break;
        }
    }
    return thisVal;

}

PayPal provides you with many variables, so I suggest that you take a look at how the response looks like. When you’ve found a value that you would like to save into the database, use the GetPDTValue function to retrieve that value.

Please note down the Activation token found in the Buyers account in Profile>My Selling Tools>Website preferences> Update. Then, enable auto return and payment data transfer. There, you will also find the Activation token which you should add to:

formVals.Add("at", "this is a long token found in Buyers account");

Vigenère cipher, programming contest

Yesterday I was solving an interesting question that has been used on the Swedish Computer Science contest – a programming contest, in 2010, which probably is simple, but interesting because it emphasises sequences, et cetera.

The question introduced the Vigenére cipher in a classical way, with two disks containing letters of the English alphabet. In the beginning, we know several things about the encrypted text, which are to help us when we are going to crack the message.
bokstavssnurra

  • The disks might have different number configurations, i.e. there is still a shift, which is unknown.
  • In order to “make it harder” for the enemy, each time we have obtained a letter, we continue by using a new shift, and this shift is increased by a constant value.
  • Fortunately, we get to know that each message contains the word “HEJ” – a Swedish word for “hello”, which might be used as  “bye”, I think.

Also, we get some examples as well, for instance:

Example 1:
Encrypted text: LRIJOUZRIYAQIRAG
Message: HEJVITARENFIKANU – means let’s take a “fika”

Example 2:
Encrypted text: GCGDJJI
Message: HEJHOPP – hello in an optimistic manner

There is also an example of this sequence,in Example 1, which is tells us that the difference is 9, 12, 15, 18… (common difference 3).

I’m solving this using a recurrence, and I’m not simplifying this arithmetic progression in any way, I just add d all the time.

The code below has passed all their tests, which are located at the end of this post.

        static void Main(string[] args)
        {
            /* 
             * Copyright (C) 2013 Artem Los,
             * All rights reserved.
             * 
             * This code-snippet can be found at: 
             *      http://clizware.net/
             */

            string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

            Console.Write("Enter the message: ");

            string message = Console.ReadLine();

            int H = alphabet.IndexOf("H");
            int E = alphabet.IndexOf("E");
            int J = alphabet.IndexOf("J");

            int dA = mod(alphabet.IndexOf(message[0]) - H, alphabet.Length);
            int dB = mod(alphabet.IndexOf(message[1]) - E, alphabet.Length);
            int dC = mod(alphabet.IndexOf(message[2]) - J, alphabet.Length);

            int init1 = dB - dA;
            int init2 = dC - dB;

            int dConst = init2 - init1;
            int dPrev = dC;

            Console.Write("Output message: HEJ");
            for (int i = 3; i < message.Length; i++)
            {
                init2 += dConst;
                dPrev = mod(dPrev + init2, alphabet.Length);

                int X = alphabet.IndexOf(message[i]);
                Console.Write(alphabet[mod(X - dPrev, alphabet.Length)]);
            }

            Console.ReadLine();
        }

        static int mod(int n, int b)
        {
            return n - b * (int)Math.Floor((double)n / b);
        }
    }

Example 1
RIPIWDUXRS
HEJSOVERNI

Example 2
IGNUFAKPXYVSF
HEJNUKOMMERDE

Example 3
PAJESQBIPOOPKAP
HEJKOMHITGENAST

Reference:
http://www.progolymp.se/Oldpage/arkiv/kval10.pdf
http://www.progolymp.se/Oldpage/arkiv/kvalsvar10.pdf

A new feature is coming to SKGL Project

In order to decrease the distribution of serial keys over ‘bad’ hacking sites, I would like to present a feature that probably will be released in SKGL 2.1.1.0 – Machine code locking. This means that each serial key will have support for machine code storage, so that the serial key is bounded to a single computer. As you know, the project is open source, and you can join it whenever you want to (http://skgl.codeplex.com/). If you think I should change something, please write to me or comment this post. Good Luck!

       static string getMachineCode()
        {
            /* 
             * Copyright (C) 2012 Artem Los, All rights reserved.
             * 
             * This code will generate a 5 digits long key, finger print, of the system
             * where this method is being executed. However, that might be changed in the
             * hash function "GetStableHash", by changing the amount of zeroes in
             * MUST_BE_LESS_OR_EQUAL_TO to the one you want to have. Ex 1000 will return 
             * 3 digits long hash.
             * 
             * Please note, that you might also adjust the order of these, but remember to
             * keep them there because as it is stated at 
             * (http://www.codeproject.com/Articles/17973/How-To-Get-Hardware-Information-CPU-ID-MainBoard-I)
             * the processorID might be the same at some machines, which will generate same
             * hashes for several machines.
             * 
             * The function will probably be implemented into SKGL Project at http://skgl.codeplex.com/
             * and Software Protector at http://softwareprotector.codeplex.com/, so I 
             * release this code under the same terms and conditions as stated here:
             * http://skgl.codeplex.com/license
             * 
             * Any questions, please contact me at
             *  * artem@artemlos.net
             */
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_Processor");
            string collectedInfo = ""; // here we will put the informa

            foreach (ManagementObject share in searcher.Get())
            {
                // first of all, the processorid
                collectedInfo += share.GetPropertyValue("ProcessorId").ToString ();
            }

            searcher.Query = new ObjectQuery("select * from Win32_BIOS");
            foreach (ManagementObject share in searcher.Get())
            {
                //then, the serial number of BIOS
                collectedInfo +=share.GetPropertyValue("SerialNumber").ToString ();
            }

            searcher.Query = new ObjectQuery("select * from Win32_BaseBoard");
            foreach (ManagementObject share in searcher.Get())
            {
                //finally, the serial number of motherboard
                collectedInfo+= share.GetPropertyValue("SerialNumber").ToString();
            }
            return GetStableHash(collectedInfo ).ToString ();
        }

        static public int GetStableHash(string s)
        {
            /*
             * modification of code from:
             * http://stackoverflow.com/questions/548158/fixed-length-numeric-hash-code-from-variable-length-string-in-c-sharp
             *
             * modified by Artem Los
             *
             */
            const int MUST_BE_LESS_OR_EQUAL_TO = 100000;
            uint hash = 0;

            foreach (byte b in System.Text.Encoding.Unicode.GetBytes(s))
            {
                hash += b;
                hash += (hash << 10);
                hash ^= (hash >> 6);
            }

            hash += (hash << 3);
            hash ^= (hash >> 11);
            hash += (hash << 15);

            int result = (int)(hash % MUST_BE_LESS_OR_EQUAL_TO);
            int check = MUST_BE_LESS_OR_EQUAL_TO / result;

            if (check > 1)
            {
                result *= check;
            }

            return result;
        }
Page 2 of 4:« 1 2 3 4 »