Friday 17 April 2015

An open posting to Xamarin

Before I start this post, let me fill in some gaps. For a short period of time, I contracted for Xamarin. It was a great experience and given the chance, I'd work for them like a shot again.

I've known the core of the team since the early days of the Mono projected, packaged for Fedora to include the mono bits and pieces, submitted more bug reports than are healthy and have supported them by purchasing the Xamarin mobile products.

I'm not going to stop buying the products as I believe that using .NET for cross platform mobile development is the way forward due to the rapid development cycle and coding style it promotes (why code 3 times in 3 languages for 3 platforms when you can code once in one language for 3 platforms - it's a no brainer)

Last night was the first meeting of the newly founded Xamarin Manchester group. It is a joint effort between McGregor Boyle (a bunch of really great recruiters) and myself with the support of Packt Publishing. I approached Xamarin to get a speaker or some sort of support and was advised to contact the UK team which I did (I know the guys well).

An email or so later and things looked good. Then silence. I'd given the dates and asked for someone to be there. Silence. Email reminder. Silence. It's as if they didn't want to know. Now I understand the constraints Xamarin work under, the number of people on the ground and the financial sides of things and I also know having been on the inside that they really do care about users.

I don't expect any special treatment, but an email from the UK people just to say "hey, we're booked up on that date, can you hold the fort?" would have been nice. Something as simple as that. A note of recognition of the hard work and organisation. But nothing. Not a dicky bird.

Well thanks. If this is the support you offer to a new group at a time where evangelism for an amazing product is low on the ground, then growth of numbers cannot be that important. Those at the meeting last night were not mobile developers, but web devs, desktop devs, scrum masters, architects and recruiters - the people who can influence to use a product or not.

They all enjoyed it but the overriding comment was why was there no-one from Xamarin there for the launch? I could answer everything thrown at me due to product knowledge and comments back indicated many thought I was part of the UK team because of my style, knowledge and fervour I spoke of the product line with. They could not believe I wasn't.

So look Xamarin, I'm going to wrap this up now as I have a deadline to meet and need to crack on coding. The next meeting is in 2 months time with one in September when we're going to try and organise a hackathon to demonstrate how simple it is to write using Xamarin. Show your support with actions. I'm not after t-shirts and mugs and monkeys (though they would be nice as freebees), I'm not after someone coming to the meetings now - you missed the boat with the launch and I'm also registered speaker.

Support us in the September hackathon - chances are we'll need VS licensed copies as most universities I know use VS. This is your big chance to get the noise out to students around Manchester (and possibly the UK if it works out - I'm happy to repeat it at other institutions if we can come to some sort of agreement over my costs).

I'm still hurting from last night, but hey we had fun. Talk to me.

Paul

Friday 11 July 2014

Text parsing within a simple app

By profession, I am a qualified lecturer in Chemistry. I've been doing it for years and one aspect which is key to understanding is the ability to understand concentration and the mole. To most people, a mole is a cute little creature that digs people's lawns up and that's about it. To a chemist, it's possibly one of the fundemental parts and it causes more problems than enough.

After teaching one particular group, I decided to sit down a write a chemical formula calculator. I know there are lots of these on the market but there was a problem. Some charge, some don't and some aren't very good. Key to mine would be a simple to use interface.

The user would enter the formula and then the number of moles required. The program would do what it needed to and report back it's answers. Easy enough.

As with any piece of software, the majority of the effort is in the design and understanding of the problem

The problem


Take the formula CuSO4.5H2O - this is a compound called copper (II) sulfate pentahydrate. If you did science at school, you'll possibly have grown crystals with it as it has a very attractive deep blue colour.

A chemist would look at this and work out how much it weights like this:

  1. There is a dot, this means that there are two parts to the formula
  2. On the left, there is a Cu, an S and an O followed by a 4. As there are no numbers before the Cu and the S this means there is only one of these.
  3. On the right there is an H followed by a 2 and then an O with nothing after it.
  4. Before the H though, there is a 5. This means that there is 5 lots of whatever follows, so there is now 10 lots of H and 5 lots of O
  5. Overall then, there is 1 Cu, 1 S, 9 O and 10 H.
  6. Find the mass of each element, multiply it by the number of it and add the lot together

This sort of calculation can be performed in a matter of moments by any chemistry student - in fact, a non-chemist can do it as long as they know what each element weights, it's just simple maths

A program though has to handle things differently...

For a start, elements always start with a capital letter, but don't have to just have one letter. Brackets also have to be understood, and what happens if there is a dot at the end?

With a bit of logic and quite a bit of paper, the solution wasn't that hard...

Knowing the problem, the solution can be found. First off, let's define some data for the elements

I'm doing this by first creating a string array for the elements and then a double array for the masses. I also have a List of type element which will be used to store the elements in (makes life simpler when doing comparisons - I did not use the list to store in initially for reasons which should become clear later)

public class element
{
  public string el;
  public double num;           
  public element(string e, double n)
  {
     this.el = e;
     this.num = n;
  }
}

List <element> elem = new List();
       
string[] elements = new string[] {"H","He",
  "Li","Be","B","C","N","O","F","Ne",
  "Na","Mg","Al","Si","P","S","Cl","Ar",
  "K","Ca","Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu",
  "Zn","Ga","Ge","As","Se","Br","Kr",
  "Rb","Sr","Y","Zr","Nb","Mo","Tc","Ru","Rh","Pd","Ag",
  "Cd","In","Sn","Sb","Te","I","Xe",
  "Cs","Ba","La",
  "Ce","Pr","Nd","Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er",
  "Tm","Yb","Lu",
  "Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb",
  "Bi","Po","At","Rn",
  "Fr","Ra","Ac",
  "Th","Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm",
  "Md","No","Lr",
  "Rf","Db","Sg","Bh","Hs","Mt", "Ds", "Rg"};
       
double [] atmass = new double[111] {1.0079,4.0026,
  6.941,9.01218,10.8,12.011,14.0067,15.9994,18.9984,20.179,
  22.9898,24.305,26.9815,28.0855,30.9738,32.06,35.453,39.948,
  39.0983,40.08,44.9559,47.88,50.9415,51.996,54.9380,55.847,
  58.9332,58.69,63.546,65.38,69.72,72.59,74.9216,78.96,79.904,83.8,
  85.4679,87.62,88.9059,91.22,92.9064,95.94,98,101.07,102.9055,
  106.42,107.868,112.41,114.82,118.69,121.75,127.6,126.9045,131.29,
  132.9054,137.33,138.9055,
  140.12,140.9077,144.24,145,150.36,151.96,157.25,158.9254,162.5,
  164.9304,167.26,168.9342,173.04,174.967,
  178.49,180.9479,183.85,186.207,190.2,192.22,195.08,196.9665,
  200.59,204.383,207.2,208.9804,209,210,222,
  223,226.0254,227.0278,
  232.0381,231.0359,238.0289,237.0482,244,243,247,247,251,252,
  257,258,259,260,
  261,262,263,264,265,266,267,268 };

 string [] numbers = new string[10] {"0","1","2","3",
                                     "4","5","6","7",
                                     "8","9"};


That's the elements and atomic weights all in. I've also added in another array which just stores numbers. These are to be used later on as well.

Test 1 - the text box

The first test that needs to be carried out is not on any sort of formula, but on the text entry box itself. There are a few tests that can be done here. The two simplest are to check if there is something actually in there and then if what's in there is valid (in other words, has the user entered an invalid element). These are two easy tasks. Other checks are also performed (for example missing braces)

void calculate(object sender, EventArgs e)
{
   if (formula.Text.Length == 0)
   {
      MessageBox.Show("Error : You haven't entered a formula",
                      "Formula error",
                      MessageBoxButtons.OK,MessageBoxIcon.Error);
      return;
   }


The simplest of errors - if the calculate button has been pressed, nothing can happen if there is nothing to work with

   if ((formula.Text.Contains("(") && !formula.Text.Contains(")"))||
        (formula.Text.Contains(")") && !formula.Text.Contains("(")))
   {
      MessageBox.Show("Error : You have a missing brace within your
                       formula. Please recheck",
                      "Bracket error", MessageBoxButtons.OK,
                      MessageBoxIcon.Error);
      return;
   }


A quick check to ensure that the braces match up. This only checks to make sure there is a ( and a ), but not the number of them. It would be quite trivial to add in a number of braces check.

   if (formula.Text.Length == 1)
   {
      bool test = true;   
      foreach (string element in elements)
      {
         if (formula.Text.Contains(element))
         {
            test = false;
             continue;
         }
      }
      if (test == true)
      {
         MessageBox.Show("Error : Your formula contains an
                         unknown element",
                         "Unknown element", MessageBoxButtons.OK,
                         MessageBoxIcon.Error);
         return;
      }
    }


Let's make sure that the elements entered in the formula actually exist shall we...

    if (formula.Text.Contains("."))
    {
       int pos = formula.Text.IndexOf(".");
       if (pos == formula.Text.Length)
       {
          MessageBox.Show("Error : You have a period followed by
                          nothing",
                          "Period error", MessageBoxButtons.OK,
                          MessageBoxIcon.Error);
          return;
       }
     }


Okay, we have a dot in the formula. Let's do a quick sanity check - is there anything after it?

     string dupeform = formula.Text;

     if (dupeform.Contains("("))
        dupeform = dupeform.Remove(dupeform.IndexOf("("), 1);
     if (dupeform.Contains(")"))
        dupeform = dupeform.Remove(dupeform.IndexOf(")"), 1);
     if (dupeform.Contains("."))
        dupeform = dupeform.Remove(dupeform.IndexOf("."), 1);
     for (int a = 0; a < dupeform.Length; ++a)
     {
        foreach (string n in numbers)
        {
          if (dupeform.Contains(n))
             dupeform = dupeform.Remove(dupeform.IndexOf(n), 1);
        }
     }


This part may strike as being a bit odd. I've made a duplicate copy of the validated text and have then removed all of the numbers, braces and periods - it's just a sanity check. It's now clear why I've created a string containing numbers
   
       dupeform = formula.Text + "#";
   search(dupeform, false);
   results();
}


The duplicate is then passed to the search routine and the results method called

The Search routine

Now that the code has through the formula, it's time to do the leg work and find out what the mass of the compound is.

The search is split into two parts - the first divides up the formula, the second identifies the element.

The search is also a recursive search - it makes more sense to parse the first part of a formula, then parse the rest instead of doubling up the code in order to do the same thing. I'm not a fan of recursive functions as the logic is not always that clear with them, but in this case, it's a good idea to use it

void search(string formula, bool dot)
{
   int mult1 = 1, mult2 = 1, s = 0, p = 0, bs = 0, be = 0, bn = 0;
   bool hasdot = formula.Contains(".") ? true:false;
   bool hasbrace = formula.Contains("(") ? true : false;
   int point = hasdot == true ? formula.IndexOf(".") + 1 : 0;
       
   if (hasbrace == true)
   {
      int k = 0;
      for (k = 0; k < formula.Length; ++k)
      {
         if (formula[k] == '(')
            bs = k;
         if (formula[k] == ')')
            be = k;
      }
      k = formula.IndexOf(")") + 1;
      if (formula[k] >= '0' && formula[k] <= '9')
      {
          int c = 0;
          while (formula[k + c] >= '0' && formula[k + c] <= '9')
             c++;
          bn = Int32.Parse(formula.Substring(k, c));
      }
      else
          bn = 1;
    }


Is there a number outside of a bracket? If there is, what is it? The start and end points of the braces are also found and stored here
           
    if (hasdot == true && dot == true)
    {
       if (formula[point] >= '0' && formula[point] <= '9')
       {
          int c = 0;
          while(formula[point + c] >= '0' &&
                formula[point + c] <= '9')
             c++;
          mult1 = Int32.Parse(formula.Substring(point, c));
          s = point + 1;
       }
     }
     else
     {
        if (formula[0] >= '0' && formula[0] <= '9')
        {
           int c = 0;
           while(formula[c] >= '0' && formula[c] <= '9')
              c++;               
           mult1 = Convert.ToInt32(formula.Substring(0, c));
           s = 1;
         }
     }


Here the number at the start is being found. If nothing is there, mult1 remains at 1 - this is used to multiply the mass found by.

The hard part now starts - first is that it's vital to remember that an element can have more than one character, so let's set up some simple variables to help

string twoelem = "   "; // three spaces
double newmass = 0;
           
if (hasdot == true && dot == false)
   p = formula.IndexOf(".");
else
   p = formula.Length + 1;


The if clause really just sets the length of the string to be searched. The searching is all done with one large loop...

int loop = s;
{
   while (loop < p)
   {
      if (loop + 1 > p || formula[loop] == '#')
         break;

      if (loop == bs)
      {
         while (loop < be)
         {
            if (formula[loop + 1] >= 'a')
            {
               twoelem = formula.Substring(loop, 2);
               loop += 2;
            }
            else
            {
               twoelem = formula.Substring(loop, 1);
               loop++;
            }

            if (formula[loop] >= '0' && formula[loop] <= '9')
            {
               int c = 0;
               while (formula[loop + c] >= '0' &&
                      formula[loop + c] <= '9')
                  c++;
               if (twoelem == "")
               {
                  if (formula[loop + c + 1] < 'a')
                     twoelem = formula.Substring(loop + c, 1);
                  else
                     twoelem = formula.Substring(loop + c, 2);
               }
               mult2 = Int32.Parse(formula.Substring(loop, c));
               loop += c;
            }
            newmass = atommass(twoelem) * mult2 * bn;
            elem.Add(new element(twoelem, newmass));
            newmass = 0;
            mult2 = 1;
         }
      }
     
      if (formula[loop + 1] >= 'a')
      {     
         twoelem = formula.Substring(loop, 2);
         loop += 2;
      }
      else
      {
         twoelem = formula.Substring(loop, 1);
         loop++;
      }

      if (formula[loop] >= '0' && formula[loop] <= '9')
      {
         int c = 0;
         while (formula[loop + c] >= '0' &&
                formula[loop + c] <= '9')
            c++;
           
         if (twoelem == "")
         {
            if (formula[loop + c + 1] < 'a')
               twoelem = formula.Substring(loop + c, 1);
            else
               twoelem = formula.Substring(loop + c, 2);
         }
         mult2 = Int32.Parse(formula.Substring(loop, c));
         loop += c;
      }
      newmass = atommass(twoelem) * mult2 * mult1;
      elem.Add(new element(twoelem, newmass));
      newmass = 0;
      mult2 = 1;
   }
}


And finally, let's do the recursion...

if (dot == false && hasdot == true)
   search(formula, true);

Using Resources within your Winform application

Typically, there are two types of resources available to any piece of software - those held within the code and those outside of the code. Both have their advantages and both their disadvantages.

If a resource (say an image) is compiled into the final assembly, the final assembly can be huge, but the nice thing is that everything is inside the assembly, so no danger pictures or sounds going missing causing the final application not work

If a resource is outside of the application, the benefit is a smaller assembly size, but everything needs to be loaded in which slows things down and has an added draw back of the application failing if a resource is missing.

A big advantage though of the resource being outside of the compiled binary is that if the development or proof of concept is done in VB.NET, the final version can be written in C# and use the same resources used.

Resources are handled using the System.Resources class. The following example loads a file which is a resource. In this case, it loads a picture

var executingAssembly = Assembly.GetExecutingAssembly();
try
{
   var resourceStream =
      executingAssembly.GetManifestResourceStream(xml.picname);
   pictureBox1.Image = new Bitmap(resourceStream);
}
catch (System.ArgumentException)
{
   MessageBox.Show("Unable to find element picture",
                   "Picture not found", MessageBoxButtons.OK);
}


xml.picname is read in from another method and just contains the name of an image held in the resources directory.

Number on textbox with Winforms

The WinForm textbox is a useful widget. You can enter just about anything into it. It is possible to set a flag and make it into a password entry box where all input is substituted for something else (such as an asterix). However, there is a limitation - you can't use it for numbers only. Okay, you could use a number up/down widget, but then there is a problem of having the up/down arrows.

There are two ways of using a textbox for numbers only. The first is to read the contents and use RegEx, but this is a bit of a pain and you have to understand RegEx. A much simpler method is to extend the Textbox class

class NumberBox : TextBox
{
   public NumberBox()
   {
      this.CausesValidation = true;
      this.Validating += new CancelEventHandler(TextBox_Validation);
   }

   private void TextBox_Validation(object sender, CancelEventArgs e)
   {
      try
      {
         int value = System.Int32.Parse(this.Text);
      }
      catch (System.Exception)
      {
          e.Cancel = true;
      }
   }
}


Pretty much, that's all there is to it - if you enter a number, all is well. Enter text and it won't let you

Passing information around - using an Interface

One aspect of C# which has room for improvement is that of inheritance. In C++, a class can inherit as many other classes as it needs to. This multiple inheritance is sadly lacking in C# - the most that can be inherited is a single class.

The way C# gets around this problem is by using interfaces. Interfaces are special - you can define methods in there, but that's about it. Think of it as a C header file - it contains the prototypes for functions but not the variables.

interface Isettings
{
    void loadsettings(bool group);
    void resetsettings();
    void saveSettings(bool group);
}

public class foo : Form, Isettings
{
   public foo()
   {
   }

   public void loadsettings(bool group)
   { 
  

Here, the class foo inherits the System.Windows.Form class as well as the Isettings interface (it happens to define the method properly here - but the interface can be used anywhere and as many interfaces can be inherited as well.

Another method is to simply define a class and then create a new instance of it in whatever other class needs it - this can be performed in one of two ways

public class common
{
   public int intro, meth, result, discuss, addition;
   public decimal final;
   public string date;
   public bool groups;
}

public class MainForm
{
   public MainForm()
   {
      this.InitializeComponent();
   }
   common data;
   // more code
}


I've not created a new instance of common here, just created a local pointer to it. If anything is used from this pointer which has not been given a value (for example if I did the following and result has not been defined int fish = result * 10;), then the final result may not be what is expected.

As it is a pointer, you're working on the stack and odd things happen when you're on the stack... If you change something, it's stored and everyone gets the change

The final method is a to create a new instance of a class

var settings = new XmlReaderSettings();

A completely new instance of the class XmlReaderSettings has been created here - the structure, methods and anything defined in XmlReaderSettings has been replicated in settings. If settings is changed, it does not change XmlReaderSettings

It is possible to pass either the pointer to the class or the instance of the class to another method in the same way as you would pass any other type

var settings = new XmlReaderSettings();
m.Text = some_function(settings);
//
private string some_function(XmlReaderSettings settings)
{
   //
}

Using XML Part 2

XML does not have to be as simple as the previous example. XML can be serialized. Serialization allows the user to read or write data to an object which can then be later manipulated. A good example of this would be a school mark book.

A class contains 10 students. Every day, they have 5 lessons which they may or may not have homework in. If there is a homework, the mark has to be stored. This is a perfect example for serialized data. To start with, the XML file would look like this:

<student>
   <name></name>
   <date></date>
   <absent></absent>
   <lesson1></lesson1>
   <lesson2></lesson2>
   <lesson3></lesson3>
   <lesson4></lesson4>
   <lesson5></lesson5>
</student>


The code has to be tagged in the source files as [Serializable] in order for the code to work.

To deserialize code from XML, it is as simple as this (FormList is a class which is used to hold the serialized XML)

FormList f;
f = null;

var s = new XmlSerializer(typeof(FormList));
var r = new StreamReader(place + "designer-test.xml");
f = (FormList)s.Deserialize(r);
r.Close();


The FormList looks like this

[Serializable]
[XmlRoot("Forms")]
public class FormList
{
    private List forms;

    public FormList()
    {
       forms = new List();
    }
    [XmlElement("Form")]
    public FormData[] Forms
    {
       get { return this.forms.ToArray(); }
       set { this.forms = new List(value); }
    }
}


[Serializable]
public class FormData
{
   public List elements;
   public List question;
       
   public FormData()
   {
      elements = new List();
      question = new List();
   }

   public string WinName { get; set; }
   public int WinWidth { get; set; }
   public int WinHeight { get; set; }
   public string WinTitle { get; set; }
   public int BackLink { get; set; }
   public int ForwardLink { get; set; }
   public int PageNumber { get; set; }
   public int ElementNos { get; set; }

   [XmlElement("Element")]
   public Element[] Elements
   {
      get { return this.elements.ToArray(); }
      set { this.elements = new List(value); }
   }

   [XmlElement("Question")]
   public Qs[] questions
   {
      get { return this.question.ToArray(); }
      set { this.question = new List(value); }
   }
}


Forms uses FormData which is what that does the leg work. Note it is the class that is Serializable not the methods.

Using XML - Part 1

The best way to understand XML is to look at two different XML files. The first one is a simple one

<?xml version="1.0"?>
<configure>
  <ljmu>
     <Introduction>20</Introduction>
     <Method>10</Method>
     <Results>20</Results>>
     <Discussion>40</Discussion>
     <Additional>10</Additional>
     <date>28-11-2007</date>
  </ljmu>
  <access>
     <Introduction>20</Introduction>
     <Method>10</Method>
     <Results>20</Results>
     <Discussion>40</Discussion>
     <Additional>10</Additional>
     <date>28-11-2007</date>   
  </access>
</configure>


It is simple enough to parse through a structure like this. ident is the node to be searched for and attr is the node. XmlReader.Create(conpath, settings, null) creates a reader stream.

public int dotheread(string ident, string attr)
{
   var settings = new XmlReaderSettings();
   var reader = XmlReader.Create(conpath, settings, null);
           
   int retval = -1;
     
   reader.MoveToAttribute(attr);
           
   while (reader.Read())
   {
      if (reader.NodeType == XmlNodeType.Element)
      {
         if (reader.Name == ident)
         {   
                reader.Read();
            retval = Convert.ToInt32(reader.Value);
            break;
         }
      }
    }               
                       
    reader.Close();
           
    if (retval == -1)
    {
       DialogResult result;
       result = MessageBox.Show(this, "Unable to find the element",
                                "D'oh!", MessageBoxButtons.OK);
    }
           
    return retval;
}


Writing XML like this is also very simple

var xmlWriter =  new XmlTextWriter(conpath,null);
           
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("configure");
   xmlWriter.WriteStartElement("ljmu");
      xmlWriter.WriteElementString("Introduction","20");
      xmlWriter.WriteElementString("Method","10");
      xmlWriter.WriteElementString("Results","20");
      xmlWriter.WriteElementString("Discussion","40");
      xmlWriter.WriteElementString("Additional","10");
      xmlWriter.WriteElementString("Date", dateToday);
   xmlWriter.WriteEndElement();
   xmlWriter.WriteStartElement("access");
      xmlWriter.WriteElementString("Introduction","20");
      xmlWriter.WriteElementString("Method","10");
      xmlWriter.WriteElementString("Results","20");
      xmlWriter.WriteElementString("Discussion","40");
      xmlWriter.WriteElementString("Additional","10");
      xmlWriter.WriteElementString("Date", dateToday);
   xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
           
xmlWriter.Close(); 
  

This is a very simple example, but it can be much more entertaining...