<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Chris McKee]]></title><description><![CDATA[Software Engineer. Stuff and nonsense. The usually short ramblings of Chris McKee.]]></description><link>https://chrismckee.co.uk/</link><image><url>https://chrismckee.co.uk/favicon.png</url><title>Chris McKee</title><link>https://chrismckee.co.uk/</link></image><generator>Ghost 1.15</generator><lastBuildDate>Sat, 22 Jun 2019 18:12:04 GMT</lastBuildDate><atom:link href="https://chrismckee.co.uk/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How to match HMACSHA256 between C# & Python]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Things are rarely simple or obvious when working across languages; especially when one is .net.<br>
Rather than waste time here's the code, in its long form.</p>
<h2 id="testparameters">Test parameters</h2>
<p>With a key <code>182634d8894831d5dbce3b3185c50881</code><br>
and a message or data value of <code>some random junk</code><br>
with both solutions we should receive  <code>d94ed997943420b7d5dfb9b31ae236b7b5225510d8f0314c54ad44fb5fd44a06</code></p>
<h2 id="c">C#</h2></div>]]></description><link>https://chrismckee.co.uk/how-to-match-hmacsha256-between-c-python/</link><guid isPermaLink="false">59ea67b860bd1036bf11b543</guid><category><![CDATA[python]]></category><category><![CDATA[c#]]></category><category><![CDATA[crypto]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 15 Mar 2017 20:28:41 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Things are rarely simple or obvious when working across languages; especially when one is .net.<br>
Rather than waste time here's the code, in its long form.</p>
<h2 id="testparameters">Test parameters</h2>
<p>With a key <code>182634d8894831d5dbce3b3185c50881</code><br>
and a message or data value of <code>some random junk</code><br>
with both solutions we should receive  <code>d94ed997943420b7d5dfb9b31ae236b7b5225510d8f0314c54ad44fb5fd44a06</code></p>
<h2 id="c">C#</h2>
<pre><code>public string HmacSHA256(string key, string data)
{
    string hash;
    ASCIIEncoding encoder = new ASCIIEncoding();
    Byte[] code = encoder.GetBytes(key);
    using (HMACSHA256 hmac = new HMACSHA256(code))
    {
        Byte[] hmBytes = hmac.ComputeHash(encoder.GetBytes(data));
        hash = ToHexString(hmBytes);
    }
    return hash;
}

public static string ToHexString(byte[] array)
{
    StringBuilder hex = new StringBuilder(array.Length * 2);
    foreach (byte b in array)
    {
        hex.AppendFormat(&quot;{0:x2}&quot;, b);
    }
    return hex.ToString();
}
</code></pre>
<p>Which will generate the same value for the same given inputs as:</p>
<h2 id="python273">Python 2.7/3</h2>
<pre><code>hmac.new(key.encode('utf-8'), data.encode('utf-8'), hashlib.sha256).hexdigest()
</code></pre>
</div>]]></content:encoded></item><item><title><![CDATA[Handy rsync for copying large amounts of data in linux]]></title><description><![CDATA[<div class="kg-card-markdown"><p>When copying to the local file system I always use the following rsync options:</p>
<pre><code>rsync -aWhv --no-compress --progress /source/ /destinationfolder/

--no-compress as it's on the same machine
--progress speaks for itself

-a preserves ownership &amp; permissions using archive flag    
-W copying whole files only
# and optional ones for watching
-h</code></pre></div>]]></description><link>https://chrismckee.co.uk/handy-rsync-for-copying-large-amounts-of-data-in-linux/</link><guid isPermaLink="false">59ea67b860bd1036bf11b542</guid><category><![CDATA[linux]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Thu, 07 Apr 2016 10:23:42 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>When copying to the local file system I always use the following rsync options:</p>
<pre><code>rsync -aWhv --no-compress --progress /source/ /destinationfolder/

--no-compress as it's on the same machine
--progress speaks for itself

-a preserves ownership &amp; permissions using archive flag    
-W copying whole files only
# and optional ones for watching
-h human-readable transfer rate and file sizes
-v keeps it verbose so we can see whats happening
</code></pre>
</div>]]></content:encoded></item><item><title><![CDATA[C# logo for stickers + stuff]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Back in early <strong>2013</strong> I was pasting stickers all over my Acer, as if it was some sort of third-rate thermal insulation, and I thought to myself, wouldn't it be nice if I could have a C# one.<br>
Annoyingly all the C# ones were god awful. But <a href="https://twitter.com/jwkratz">Jeremy Kratz</a> had</p></div>]]></description><link>https://chrismckee.co.uk/c-logo-for-stuff-and-stickers/</link><guid isPermaLink="false">59ea67b860bd1036bf11b541</guid><category><![CDATA[logo]]></category><category><![CDATA[c#]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Mon, 16 Nov 2015 20:35:44 GMT</pubDate><media:content url="https://chrismckee.co.uk/content/images/2015/11/logoheader.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://chrismckee.co.uk/content/images/2015/11/logoheader.jpg" alt="C# logo for stickers + stuff"><p>Back in early <strong>2013</strong> I was pasting stickers all over my Acer, as if it was some sort of third-rate thermal insulation, and I thought to myself, wouldn't it be nice if I could have a C# one.<br>
Annoyingly all the C# ones were god awful. But <a href="https://twitter.com/jwkratz">Jeremy Kratz</a> had made a nice C++ one while at MSFT and had <a href="https://dribbble.com/shots/799814-Standard-C-Logo#comment-2528860">kindly made it clear he wasn't bothered about the licence</a> something <a href="https://twitter.com/jwkratz/status/666287183431516160">confirmed recently</a>.<br>
Anyhoo I liked it and decided to try and replicate it in Illustrator then sort for print in PhotoShop, whacked in main shape and lines, added in a circle for the c with a bit of editing, and a # sign in a nice Visual Studio friendly font (Consolas Bold) and coloured it in VS livery.</p>
<p>And here it is,<br>
<img src="https://chrismckee.co.uk/content/images/2015/11/C-Logo-1.jpg" alt="C# logo for stickers + stuff"></p>
<p>I'd formatted a transparent PNG for RedBubble on an A4 document (which is their requirement) so I know these print fine.</p>
<p><a href="https://www.dropbox.com/s/uwmuzs8u0crnblu/C%23Logo.png?dl=00">Download PNG</a></p>
<p>In the UK and want a batch? I'd advise <a href="https://stickerapp.co.uk/">https://stickerapp.co.uk/</a> great service and high quality. 50 stickers at 7 wide x 7.7cm high with small die cut (cutline) is 36 quid. 50 at 5.3x5.8 cm would be 21; pretty neat.</p>
<p>I'll pop the vector version up if/when I dig it out.</p>
<p><strong>Licence wise</strong></p>
<p><a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/"><img alt="C# logo for stickers + stuff" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png"></a><br>
Use as you will, I'm not wholly arsed about attribution as the designs plagiarised but the <em>share alike</em> is important to keep it public. Do pretty much whatever you like; tattoo it to your butt for all I care.</p>
<p>Tada<br>
<img src="https://chrismckee.co.uk/content/images/2015/11/c073c0ac17cf30b610e128b53881a2df.jpg" alt="C# logo for stickers + stuff"></p>
</div>]]></content:encoded></item><item><title><![CDATA[Handy MongoDB C# Tools]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Just a few bits and bobs I've collected up lately.</p>
<p><strong>Aggregation</strong> is a neat feature in MongoDB and as with most mongo c# stuff it's often a small hurdle to implementing the same query you perform in BSON in the driver language…</p>
<p>Sooo just to get you started <a href="https://chrismckee.co.uk/mongo-aggregation-in-c/">https://chrismckee.</a></p></div>]]></description><link>https://chrismckee.co.uk/handy-mongodb-csharp-tools/</link><guid isPermaLink="false">59ea67b860bd1036bf11b53f</guid><category><![CDATA[mongodb]]></category><category><![CDATA[mongo]]></category><category><![CDATA[c#]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Thu, 12 Nov 2015 00:19:00 GMT</pubDate><media:content url="https://chrismckee.co.uk/content/images/2015/11/mongotools.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://chrismckee.co.uk/content/images/2015/11/mongotools.png" alt="Handy MongoDB C# Tools"><p>Just a few bits and bobs I've collected up lately.</p>
<p><strong>Aggregation</strong> is a neat feature in MongoDB and as with most mongo c# stuff it's often a small hurdle to implementing the same query you perform in BSON in the driver language…</p>
<p>Sooo just to get you started <a href="https://chrismckee.co.uk/mongo-aggregation-in-c/">https://chrismckee.co.uk/mongo-aggregation-in-c/</a><br>
Quite a good idea to mix this with Profiling so you can watch how it's querying etc...</p>
<p><strong>Pipeline Requests</strong> I like the pipe &amp; filters way of dealing with 'tasks' and for long queries, it can make for more readable queries; of course, someone's written a lib for that.</p>
<ul>
<li>Git: <a href="https://github.com/melkio/MongoDB.Extensions">https://github.com/melkio/MongoDB.Extensions</a></li>
<li>Nuget: Install-Package MongoDB.Extensions</li>
</ul>
<p><strong>Profiling</strong> If you're looking for a MongoDB equivalent of SQL Profiler look no further than MongoTail; pretty new and running on Python it allows you to quickly connect, set profiling level and start to output the queries. You can then, of course, grep away to reduce the output and pipe where you like.</p>
<ul>
<li>Git: <a href="https://github.com/mrsarm/mongotail">https://github.com/mrsarm/mongotail</a></li>
<li>Python Package Manager: pip install mongotail</li>
</ul>
<p>Of course, when you're writing your queries in MongoDB C# Driver, especially with linq, it can be a PITA…</p>
<ul>
<li>Git: <a href="https://github.com/mikeckennedy/mongodb-query-helper-for-dotnet">https://github.com/mikeckennedy/mongodb-query-helper-for-dotnet</a></li>
<li>Nuget: Install-Package MongoDB.QueryHelper</li>
</ul>
<p>Handy little library to use or extend on.</p>
<p><strong>Tools</strong></p>
<p>MongoChef <a href="http://3t.io/mongochef/">http://3t.io/mongochef/</a> seriously the best MongoDB management tool you can get these days after RoboMongo pretty much-abandoned development post v3.  Free licence for playing/open source gubbins, pretty fair 'user', rather than machine, licence when you pay to allow you to install it on however many laptops/pcs you use.</p>
<p>Download MongoDB to your local machine and install the client/tools (skip the server unless you really want to run that locally as well) in order to use the IntelliShell in MongoChef (nice handy interface, like SQL query window where you can type queries out with intellisense); it also has a Query Builder which can be handy, an aggregation query builder which is quite nice for building them up and reordering the pipeline before you commit it to code, and the ability to manage users and an often neglected feature in mongo clients AN EXPORT / IMPORT BUTTON.<br>
The only thing that bugs me about MongoChef is the export as json; if you store ID's or .net style GUIDs as your bson id it's encoded; robomongo would spit that out as a guid, mongochef in csv mode spits it out as a guid, in json mode spits it out as the weird bson format. Small irritation to be honest :)</p>
</div>]]></content:encoded></item><item><title><![CDATA[Simple MongoDB Aggregation in C#]]></title><description><![CDATA[Grouping/Aggregation in MongoDB using the C# Driver]]></description><link>https://chrismckee.co.uk/mongo-aggregation-in-c/</link><guid isPermaLink="false">59ea67b860bd1036bf11b540</guid><category><![CDATA[mongodb]]></category><category><![CDATA[mongo]]></category><category><![CDATA[aggregation]]></category><category><![CDATA[c#]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 11 Nov 2015 19:06:16 GMT</pubDate><media:content url="https://chrismckee.co.uk/content/images/2015/11/Capture.PNG" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><h1 id="groupingdatawithcount">Grouping Data with Count</h1>
<img src="https://chrismckee.co.uk/content/images/2015/11/Capture.PNG" alt="Simple MongoDB Aggregation in C#"><p><em>Note: This starts with the 1.10.1 version of the mongo driver; <a href="https://www.nuget.org/packages/mongocsharpdriver/1.10.1">https://www.nuget.org/packages/mongocsharpdriver/1.10.1</a> the v2 driver wraps the Async methods to syncronous to stay 'compatible' and as such is slower. So running 'synchronous' using v2 would be disadvantaged by the new driver while async with the async driver may have a minor benefit. The async is covered further down using Driver 2.1.1. <a href="https://www.nuget.org/packages/MongoDB.Bson/2.1.1">https://www.nuget.org/packages/MongoDB.Bson/2.1.1</a></em></p>
<p>Being in C# we tend to store our Collection dto using the type name; if you don't just swap <code>typeof(MyCollection).Name</code> for the collection's name as a string.</p>
<p>To query an aggregate we need to select the collection then pass the aggregate pipeline in. This is represented by the <code>match</code>, <code>group</code> and <code>sort</code> variables.</p>
<h3 id="v1101mongodriver">V1.10.1 Mongo Driver</h3>
<pre><code>      // MongoUtil.GetMongoDatabase simply gets an instance of mongodb database
      var _db = MongoUtil.GetMongoDatabase(&quot;mongodb://somedb:port/mydata?safe=true&quot;);
      var col = _db.GetCollection&lt;BsonDocument&gt;(typeof(MyCollection).Name);

      // You can add a query within the match to reduce the result set; this is basically your where clause
      var match = new BsonDocument { { &quot;$match&quot;, new BsonDocument { } } };

      // We group by setting, in this instance, the group by clause to our field UserId 
      // (it's a GUID but could be anything).    
      // We prefix with this with $. Then set our variable name to  count on as 
      // NumberOfReferencedUsers (overly descriptive?)
      var group = new BsonDocument
          {
            {
             &quot;$group&quot;, new BsonDocument
              {
                {&quot;_id&quot;, &quot;$UserId&quot;},
                {&quot;NumberOfReferencedUsers&quot;, new BsonDocument {{&quot;$sum&quot;, 1}}}
              }
            }
          };

      // We want to sort decending so we'll sort by our count with `-1`; ascending would be `1`
      var sort = new BsonDocument { { &quot;$sort&quot;, new BsonDocument { { &quot;NumberOfReferencedUsers&quot;, -1 } } } };
      // Create our pipeline array then feed it into an instance of AggregateArgs and pass to the aggregate method.
      var pipeline = new[] { match, group, sort };
      var mongoArgs = new AggregateArgs { Pipeline = pipeline };
      var res = col.Aggregate(mongoArgs).ToList();

      // BSONDoc is dynamic enough so we'll enumerate with tolist and get on with things.
      foreach (var x in res)
      {
          // You can grab the entries by their key name and cast, call other stuff etc like usual. 
          // There's also the `TryGetElement` and `GetElement`, same again for value.
          var id = (Guid)x[&quot;_id&quot;];
          Console.WriteLine($&quot;{id},{dealerName},{x[&quot;NumberOfReferencedUsers&quot;]}&quot;);
      }
</code></pre>
<h2 id="v2asyncmongodriver">V2 Async Mongo Driver</h2>
<p>The async (forced to resolve as I whacked this in a console app) is a little more fluent and a little less nested.</p>
<pre><code>     var db = new MongoContext(&quot;mongodb://server:port/mydata?safe=true&quot;);
     db.Connect();


      var col = db.Database.GetCollection&lt;BsonDocument&gt;(typeof(MyCollection).Name);

      // Again this is the 'where clause' so add the other side of the match query
      // If we wanted to only get results with more than 3 matches we could query
      // var match = new BsonDocument{{&quot;NumberOfReferencedUsers&quot;, new BsonDocument {{&quot;$gt&quot; , 3}} }};
      // and we'd have to reorder the Aggregate call so match came after group or NumberOfReferencedUsers 
      // wouldn't have a value to filter on
      var match = new BsonDocument();

      var group = new BsonDocument
      {
        {&quot;_id&quot;, &quot;$UserId&quot;},
        {&quot;NumberOfReferencedUsers&quot;, new BsonDocument {{&quot;$sum&quot;, 1}}}
      };

      var sort = new BsonDocument {{&quot;NumberOfReferencedUsers&quot;, -1}};

      // Fluent and oh yes less code. Tasty
      var aggregate = col.Aggregate().Match(match).Group(group).Sort(sort);

      // ToListAsync() would require you to precede the method with await and for your class to also be awaitable
      // and all the usual async stuff applies. Here it's in a console app so its just called. 
      var res = aggregate.ToListAsync().Result;

      foreach (var x in res)
      {
        try
        {
          var id = (Guid)x[&quot;_id&quot;];
          Console.WriteLine($&quot;{id},{dealerName},{x[&quot;NumberOfReferencedUsers&quot;]}&quot;);
        }
        catch (Exception ex)
        {
        }
      }
</code></pre>
<p>In case you're interested this is the 'context' the mongo util creates; I had to quickly rewrite it for the V2 driver but it doesn't change that much.</p>
<pre><code>    internal class MongoContext
    {
      private readonly string _connectionString;
      private string _databaseName;
      private MongoClient _mongoClient;

      public MongoContext(string connectionString)
      {
        _connectionString = connectionString;
        BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
      }

      public IMongoDatabase Database { get; private set; }

      public void Connect()
      {
        _databaseName = MongoUrl.Create(_connectionString).DatabaseName;
        if (string.IsNullOrWhiteSpace(_databaseName))
        {
          throw new Exception(&quot;Could not determine database name from connection string&quot;);
        }
        _mongoClient = new MongoClient(_connectionString);
        Database = _mongoClient.GetDatabase(_databaseName);
      }
    }
</code></pre>
<p>With the pipeline it's pretty much up-to-you; and happily the v2 library reduces the need to create more BsonDocument objects than necessary.</p>
<h4 id="refs">Refs:</h4>
<ul>
<li><a href="https://docs.mongodb.org/getting-started/csharp/aggregation/">https://docs.mongodb.org/getting-started/csharp/aggregation/</a></li>
<li><a href="https://docs.mongodb.org/manual/reference/sql-aggregation-comparison/">https://docs.mongodb.org/manual/reference/sql-aggregation-comparison/</a></li>
</ul>
</div>]]></content:encoded></item><item><title><![CDATA[Creating & Mounting new drives in Ubuntu / Azure]]></title><description><![CDATA[<div class="kg-card-markdown"><p><em>Leading note: The drive creation is based on using Azure with an Ubuntu 14.04 LTS release. This stuff doesn't change very often but sometimes ubuntu changes the advice and occasionally includes features or options that might not exist in other releases.</em></p>
<h2 id="createasiteadiskormore">Create a Site &amp; A disk (or more)</h2></div>]]></description><link>https://chrismckee.co.uk/creating-mounting-new-drives-in-ubuntu-azure/</link><guid isPermaLink="false">59ea67b860bd1036bf11b53e</guid><category><![CDATA[azure]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 21 Oct 2015 15:20:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p><em>Leading note: The drive creation is based on using Azure with an Ubuntu 14.04 LTS release. This stuff doesn't change very often but sometimes ubuntu changes the advice and occasionally includes features or options that might not exist in other releases.</em></p>
<h2 id="createasiteadiskormore">Create a Site &amp; A disk (or more)</h2>
<p>Ok, this bits all azure based, so hang fire or skip to the next bit if you've done this, or are in some other VM/cloud place or ssh'd into a hardware box.</p>
<h2 id="partitioningformattingandmountingthedrives">Partitioning, Formatting and Mounting the drive(s)</h2>
<p>You've added the drives, your machines ticking along nicely, so SSH in and let's get going.</p>
<p>Now I usually type <code>sudo su</code> which basically chucks you into root mode; if you're uncomfortable with that just imagine I typed <code>sudo</code> before each command.</p>
<p>First, type <code>blkid</code></p>
<p>Now before you ATTACH your new drive <code>blkid</code> looks like this</p>
<pre><code>/dev/sr0: LABEL=&quot;rd_rdfe_stable.150630-2348&quot; TYPE=&quot;udf&quot;
/dev/sda1: LABEL=&quot;cloudimg-rootfs&quot; UUID=&quot;3156d3f3-c771-498f-89f3-c204d36c46d6&quot; TYPE=&quot;ext4&quot;
/dev/sdb1: UUID=&quot;ab77eb25-3fe1-401f-a0da-60a45169b168&quot; TYPE=&quot;ext4&quot;
</code></pre>
<p><strong>sda1</strong> is the system drive, never store anything you want to keep here (other than the configs etc for services).</p>
<p><strong>sdb1</strong> is a temporary drive azure attaches to each machine by default. Usually about 69G and linked to /mnt; the size increases with VM size. You can read about that here <a href="http://blogs.msdn.com/b/mast/archive/2013/12/07/understanding-the-temporary-drive-on-windows-azure-virtual-machines.aspx">http://blogs.msdn.com/b/mast/archive/2013/12/07/understanding-the-temporary-drive-on-windows-azure-virtual-machines.aspx</a></p>
<p>Typing <code>lshw -C disk</code> will display all the attached disks... this is more accurate as blkid does not tend to pick-up new drives without a reboot or you doing something to alter the state.</p>
<p>After typing lshw -C disk we see (at the bottom of the list)</p>
<pre><code>  *-disk
       description: SCSI Disk
       physical id: 0.0.0
       bus info: scsi@5:0.0.0
       logical name: /dev/sdc
       size: 60GiB (64GB)
       configuration: sectorsize=512
</code></pre>
<h3 id="createapartition">Create a partition</h3>
<p>Type <code>fdisk /dev/sdc</code><br>
Various noise will appear followed by a prompt; hitting m shows you the options.</p>
<pre><code>Command (m for help): m
Command action
   a   toggle a bootable flag
   b   edit bsd disklabel
   c   toggle the dos compatibility flag
   d   delete a partition
   l   list known partition types
   m   print this menu
   n   add a new partition
   o   create a new empty DOS partition table
   p   print the partition table
   q   quit without saving changes
   s   create a new empty Sun Disklabel
   t   change a partition's system id
   u   change display/entry units
   v   verify the partition table
   w   write table to disk and exit
   x   extra functionality (experts only)
</code></pre>
<p>We want a new partition; so press <code>n</code> followed by hitting <code>enter</code>.<br>
Then <code>p</code> and hit <code>enter</code> again for a primary partition.<br>
Then assuming you don't want to mess with the defaults hit enter for the following...</p>
<ul>
<li><code>Partition number (1-4, default 1):</code></li>
<li><code>First sector (2048-125829119, default 2048):</code></li>
<li><code>Last sector, +sectors or +size{K,M,G} (2048-125829119, default 125829119):</code></li>
</ul>
<p>You'll then be presented with the <code>Command (m for help):</code> prompt again; press <code>w</code> and hit <code>enter</code> to write your changes.</p>
<pre><code>The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
</code></pre>
<p>Cool, we've made a partition, now we need to format it.</p>
<p>Type <code>mkfs -t ext4 /dev/sdc1</code> and hit <code>enter</code>.</p>
<pre><code>mke2fs 1.42.9 (4-Feb-2014)
Discarding device blocks: done
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
3932160 inodes, 15728384 blocks
786419 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
480 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
</code></pre>
<p>Now we can mount it; first, create a folder (path) you want to mount to; in this instance, I'll create a folder called data in the root and mount that to sdc1 (our new drive sdc, partition 1).</p>
<pre><code>mkdir /data
mount /dev/sdc1 /data
</code></pre>
<p>You can now use this drive by going to the data folder at the root. If you reboot the machine at this point it will unmount the drive. Which takes us to...</p>
<h2 id="makethatmountmorepermanentwithfstab">Make that mount more permanent with FSTAB</h2>
<p>The new <a href="https://help.ubuntu.com/community/UsingUUID">ubuntu recommendation</a> is that you use the UUID from this output rather than the path, so that's what's demonstrated here.</p>
<p>We've altered the world and typing <code>blkid</code> will now show us our new goodness.</p>
<pre><code>root@host:/# blkid
/dev/sr0: LABEL=&quot;rd_rdfe_stable.150630-2348&quot; TYPE=&quot;udf&quot;
/dev/sda1: LABEL=&quot;cloudimg-rootfs&quot; UUID=&quot;3156d3f3-c771-498f-89f3-c204d36c46d6&quot; TYPE=&quot;ext4&quot;
/dev/sdb1: UUID=&quot;ab77eb25-3fe1-401f-a0da-60a45169b168&quot; TYPE=&quot;ext4&quot;
/dev/sdc1: UUID=&quot;cd5aaf52-5483-4f9d-a0d6-836f26c23a09&quot; TYPE=&quot;ext4&quot;
</code></pre>
<p>_Random tip as well as blkid you can also type <code>ls -l /dev/disk/by-uuid</code> which lists the drives + uuids`</p>
<p><em>Make sure you enter your own UUID, copy + paste fatigue could kick your arse here</em></p>
<p>So we want to edit fstab, type <code>nano /etc/fstab</code> to open in nano. You can open in <code>VI</code> if you prefer, or whatever.<br>
The file will look like this...</p>
<pre><code># CLOUD_IMG: This file was created/modified by the Cloud Image build process
UUID=3156d3f3-c771-498f-89f3-c204d36c46d6       /        ext4   defaults,discard        0 0

# CLOUD_IMG: This file was created/modified by the Cloud Image build process
# The following is used to dynamically configured additional
# NICs. Do not remove unless you know what you are doing.
none /etc/network/interfaces.dynamic.d tmpfs   nodev,noexec,nosuid,size=64K 0 0
/dev/sdb1       /mnt    auto    defaults,nobootwait,comment=cloudconfig 0       2
</code></pre>
<p>Add a line at the end like this (but with your UUID)</p>
<p><code>UUID=cd3aaf52-5483-4f9d-a0d6-836f26c23a09 /data ext4 defaults 0 1</code></p>
<p>The format of this is pretty simple.</p>
<ul>
<li><code>UUID</code> or you can put /dev/sdb1 format, identifies the drive.</li>
<li><code>/data</code> is the mountpoint</li>
<li><code>ext4</code> is the file-system type we specified above when formatting.</li>
<li><code>defaults</code> is an option shortcut, so it sets these options rw, <code>suid, dev, exec, auto, nouser, async</code>. You can replace it with any of the [mount-options](<a href="http://man7.org/linux/man-pages/man8/mount.8.html#FILESYSTEM-INDEPENDENT_MOUNT">http://man7.org/linux/man-pages/man8/mount.8.html#FILESYSTEM-INDEPENDENT_MOUNT</a> OPTIONS) normally available</li>
<li><code>dump flag</code> - Enable or disable backing up of the device/partition (the command dump). This field is usually set to 0, which disables it.</li>
<li><code>pass order</code> - Controls the order in which fsck checks the device/partition for errors at boot time. The root device should be 1. Other partitions should be 2, or 0 to disable checking.</li>
</ul>
<p>Save and exit the file... <code>esc</code> then <code>:wq</code> in vim or <code>CTRL+X then enter in nano/pico</code></p>
<p>Typing <code>umount -a</code> will mount all available drives in fstab, in this case they're all mounted bar our new one so go nuts.</p>
<h2 id="recoveringfromfailure">Recovering from failure</h2>
<p>Your config is wrong or your external drive is buggered, but you still want your VM to start or you can't really fix it... more so in azure where VM's don't have a console emulator so you can diagnose issues (pay your support bill and watch as they can't tell either). So we need to alter the default settings in fstab for our new drive so we boot regardless of its presence.</p>
<p>This is where the aptly names <code>nofail</code> comes in.</p>
<blockquote>
<p>fsck normally does not check whether the device actually exists before calling a file system specific checker. Therefore non-existing devices may cause the system to enter file system repair mode during boot if the filesystem specific checker returns a fatal error. The /etc/fstab mount option nofail may be used to have fsck skip non-existing devices. fsck also skips non-existing devices that have the special file system type auto</p>
</blockquote>
<h3 id="references">References</h3>
<ul>
<li><a href="https://help.ubuntu.com/community/Fstab">https://help.ubuntu.com/community/Fstab</a></li>
<li><a href="http://man7.org/linux/man-pages/man5/fstab.5.html">http://man7.org/linux/man-pages/man5/fstab.5.html</a></li>
<li><a href="http://www.eazynet.de/nofail_option_in_etc_fstab">http://www.eazynet.de/nofail_option_in_etc_fstab</a></li>
<li><a href="http://unix.stackexchange.com/questions/53456/what-is-the-difference-between-nobootwait-and-nofail-in-fstab">http://unix.stackexchange.com/questions/53456/what-is-the-difference-between-nobootwait-and-nofail-in-fstab</a></li>
<li><a href="http://unix.stackexchange.com/questions/44027/how-to-fix-boot-failure-due-to-incorrect-fstab?rq=1">http://unix.stackexchange.com/questions/44027/how-to-fix-boot-failure-due-to-incorrect-fstab?rq=1</a></li>
<li>[<a href="http://man7.org/linux/man-pages/man8/mount.8.html">http://man7.org/linux/man-pages/man8/mount.8.html</a>](<a href="http://man7.org/linux/man-pages/man8/mount.8.html#FILESYSTEM-INDEPENDENT_MOUNT">http://man7.org/linux/man-pages/man8/mount.8.html#FILESYSTEM-INDEPENDENT_MOUNT</a> OPTIONS)</li>
</ul>
</div>]]></content:encoded></item><item><title><![CDATA[What the fuck woke my PC up]]></title><description><![CDATA[<div class="kg-card-markdown"><p>My PC hates hibernating, in fact, it hibernates for a whopping minute then wakes up due to the genius default driver power management settings.</p>
<p>A quick way to find the culprit.<br>
Open command prompt and ask...</p>
<pre><code>C:\Users\Chris&gt;powercfg -lastwake
Wake History Count - 1
Wake History [0]</code></pre></div>]]></description><link>https://chrismckee.co.uk/what-the-fuck-woke-my-pc-up/</link><guid isPermaLink="false">59ea67b860bd1036bf11b53d</guid><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 15 Jul 2015 20:03:12 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>My PC hates hibernating, in fact, it hibernates for a whopping minute then wakes up due to the genius default driver power management settings.</p>
<p>A quick way to find the culprit.<br>
Open command prompt and ask...</p>
<pre><code>C:\Users\Chris&gt;powercfg -lastwake
Wake History Count - 1
Wake History [0]
Wake Source Count - 0
</code></pre>
<p>Of course, if it had woke up it would tell you what caused it.<br>
My network card had reset its settings during some update and had decided it should wake my pc up; machine shuts down, router says hey where did you go, machine powers back up.<br>
One check-box and bang, fixed.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Updating / Restoring Nuget Packages FAST]]></title><description><![CDATA[<div class="kg-card-markdown"><p>The VS NuGet client is great for browsing for new packages; in fact it works pretty well for upgrading when your on a small project. But it locks the UI, lags out, if it errors it does so in a useless fashion, the moment you get past a few projects</p></div>]]></description><link>https://chrismckee.co.uk/updating-restoring-nuget-packages-fast/</link><guid isPermaLink="false">59ea67b860bd1036bf11b53a</guid><category><![CDATA[nuget]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 01 Apr 2015 11:58:38 GMT</pubDate><media:content url="https://chrismckee.co.uk/content/images/2015/04/spaceshit.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://chrismckee.co.uk/content/images/2015/04/spaceshit.jpg" alt="Updating / Restoring Nuget Packages FAST"><p>The VS NuGet client is great for browsing for new packages; in fact it works pretty well for upgrading when your on a small project. But it locks the UI, lags out, if it errors it does so in a useless fashion, the moment you get past a few projects it becomes unbarably slow (especially updating cross solution) and half of the time you just want to stamp on it.</p>
<h2 id="restoringnugetpackages">Restoring Nuget Packages</h2>
<p>Create a file, call it say Restore.bat, open it in notepad or whatever text editor you like.</p>
<p>My file sits below the source so say <code>c:\project\myproj</code></p>
<pre><code>@cd src
@echo Starting Restore
@.\.nuget\nuget.exe restore .\myproj.sln -source &quot;https://www.nuget.org/api/v2/&quot;  -NonInteractive -RequireConsent -verbosity detailed
@echo All done
@cd ..
</code></pre>
<p>Quick DOS explanation; the @ symbol suppresses printing out the command being called.<br>
So from the <code>myproj</code> folder I cd into src, print out <code>Starting Restore</code> then call nuget from the .nuget folder (you need to obviously have this around) and sets the source to the standard nuget source. In our case we have our own. You might want to tail on to that a myget repo or multiple.</p>
<h2 id="upgradingyournugetrepos">Upgrading your Nuget Repos</h2>
<p>As with restore my solution is sat at <code>c:\project\myproj</code><br>
You have to have all the existing versions of packages downloaded before you can upgrade as nuget uses the packages to determine the dependencies (probably part of why its slow). So it may be prudent to add the restore step prior to the update.</p>
<pre><code>@cd src
@echo Starting Update
@.\.nuget\nuget.exe update .\myproj.sln -source &quot;https://mynugetrepo.com/nuget/&quot;  -NonInteractive -verbosity detailed
@echo All done
@cd ..
</code></pre>
<p>The source in the above example is set to a custom nuget store so we just upgrade the ones from our store.</p>
<p>You may want to change that for the main store <code>https://www.nuget.org/api/v2/</code> but with this you may want to restrict the id's of the projects you upgrade or set the <code>-safe</code> flag to avoid major updates.<br>
Instead of setting the source manually you can set the <a href="https://docs.nuget.org/consume/Command-Line-Reference#update-command-options">-ConfigFile PATH</a> flag and use the configuration in your nuget configuration file.</p>
<p>So above you'd swap -source xxx to -configfile ..nuget\nuget.config , by default with no source it would use the nuget.config within your APPDATA folder.</p>
</div>]]></content:encoded></item><item><title><![CDATA[NuGet from command line error - Microsoft.Build.Exceptions.InvalidProjectFileException]]></title><description><![CDATA[<div class="kg-card-markdown"><pre><code>Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project &quot;E:\_PROJECTS\x\c\src\Services\Azure\.nuget\nuget.targets&quot; was not found. Confirm that the path in the &lt;Import&gt; declaration is correct, and that the file exists on disk.  E:\_PROJECTS\x\c\src\Services\Azure\x\x.</code></pre></div>]]></description><link>https://chrismckee.co.uk/nuget-from-command-line-error-microsoft-build-exceptions-invalidprojectfileexception/</link><guid isPermaLink="false">59ea67b860bd1036bf11b53b</guid><category><![CDATA[nuget]]></category><category><![CDATA[msbuild]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 01 Apr 2015 11:48:01 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><pre><code>Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project &quot;E:\_PROJECTS\x\c\src\Services\Azure\.nuget\nuget.targets&quot; was not found. Confirm that the path in the &lt;Import&gt; declaration is correct, and that the file exists on disk.  E:\_PROJECTS\x\c\src\Services\Azure\x\x.csproj
   at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(String errorSubCategoryResourceName, IElementLocation elementLocation, String resourceName, Object[] args)
   at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(IElementLocation elementLocation, String resourceName, Object arg0)
   at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImports(String directoryOfImportingFile, String importExpressionEscaped, ProjectImportElement importElement)
   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)
   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)
   at Microsoft.Build.Evaluation.Evaluator`4.Evaluate()
   at Microsoft.Build.Evaluation.Evaluator`4.Evaluate(IEvaluatorData`4 data, ProjectRootElement root, ProjectLoadSettings loadSettings, Int32 maxNodeCount, PropertyDictionary`1 environmentProperties, ILoggingService loggingService, IItemFactory`2 itemFactory, IToolsetProvider toolsetProvider, ProjectRootElementCache projectRootElementCache, BuildEventContext buildEventContext, ProjectInstance projectInstanceIfAnyForDebuggerOnly)
   at Microsoft.Build.Evaluation.Project.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation)
   at Microsoft.Build.Evaluation.Project.Initialize(IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings)
   at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings)
   at NuGet.Common.MSBuildProjectSystem.GetProject(String projectFile)
   at NuGet.Commands.UpdateCommand.GetMSBuildProject(String packageReferenceFilePath)
   at NuGet.Commands.UpdateCommand.ExecuteCommand()
   at NuGet.Commands.Command.Execute()
   at NuGet.Program.Main(String[] args)
</code></pre>
<p>The issue is depth; the nesting of projects in deeper folders for organisation seems to play havoc with the build file.<br>
Pop open the CSProj file causing the issue,<br>
alter the default path<br>
<code>SolutionDir Condition=&quot;$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'&quot;&gt;..\&lt;/SolutionDir&gt;</code> in the cs proj file.</p>
<p><strong>Basically when you nest folders AFTER creating projects you'll need to do this.</strong></p>
<p>Sorted.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Set Up TeamCity on Ubuntu 14 LTS]]></title><description><![CDATA[<div class="kg-card-markdown"><h2 id="prepessentials">Prep essentials</h2>
<p>Change versions to latest as required...</p>
<ul>
<li>JetBrains version is on this page: <a href="https://www.jetbrains.com/teamcity/download/">https://www.jetbrains.com/teamcity/download/</a></li>
<li>Postgres Driver version is on this page: <a href="http://jdbc.postgresql.org/_">http://jdbc.postgresql.org/_</a></li>
</ul>
<p><strong>SSH into your server and let's begin.</strong></p>
<p><strong>Go root, type</strong> <code>sudo su</code>.</p>
<blockquote>
<p>Cheat mode (skip to : Create a Database</p></blockquote></div>]]></description><link>https://chrismckee.co.uk/setup-teamcity-8-1-on-ubuntu-14-lts/</link><guid isPermaLink="false">59ea67b760bd1036bf11b534</guid><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Mon, 30 Mar 2015 15:37:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><h2 id="prepessentials">Prep essentials</h2>
<p>Change versions to latest as required...</p>
<ul>
<li>JetBrains version is on this page: <a href="https://www.jetbrains.com/teamcity/download/">https://www.jetbrains.com/teamcity/download/</a></li>
<li>Postgres Driver version is on this page: <a href="http://jdbc.postgresql.org/_">http://jdbc.postgresql.org/_</a></li>
</ul>
<p><strong>SSH into your server and let's begin.</strong></p>
<p><strong>Go root, type</strong> <code>sudo su</code>.</p>
<blockquote>
<p>Cheat mode (skip to : Create a Database Config file for PostGres)<br>
<code>wget https://gist.githubusercontent.com/ChrisMcKee/a45e5cd5d7d9b8f9fa00/raw/2b4a8fea3fcff9e6675e560e908fa785d6ac2697/teamcitysetup.sh &amp;&amp; chmod +x teamcitysetup.sh &amp;&amp; ./teamcitysetup.sh</code></p>
</blockquote>
<pre><code>apt-get update
apt-get install -y openjdk-7-jre-headless curl mercurial git
</code></pre>
<p>Set the Java Path ala this post <a href="https://chrismckee.co.uk/neither-the-java_home-nor-the-jre_home-environment-variable-is-defined/">/neither-the-java_home-nor-the-jre_home-environment-variable-is-defined/</a></p>
<h2 id="installteamcity">Install TeamCity</h2>
<p>Check website for current version and substitute.</p>
<pre><code>wget -c http://download.jetbrains.com/teamcity/TeamCity-8.1.5.tar.gz -O /tmp/TeamCity-8.1.5.tar.gz
tar -xvf /tmp/TeamCity-8.1.5.tar.gz -C /srv
rm -rf /tmp/TeamCity-8.1.5.tar.gz
mkdir /srv/.BuildServer
</code></pre>
<h3 id="createateamcityuser">Create a TeamCity user</h3>
<pre><code>useradd -m teamcity
chown -R teamcity /srv/TeamCity
chown -R teamcity /srv/.BuildServer
</code></pre>
<h3 id="createinitdscript">Create init.d script</h3>
<pre><code>wget https://gist.githubusercontent.com/sandcastle/9282638/raw/teamcity-init.sh -O /etc/init.d/teamcity
chmod 775 /etc/init.d/teamcity
update-rc.d teamcity defaults
</code></pre>
<h3 id="downloadpostgresodbcdriverforteamcity">Download PostGres ODBC driver for TeamCity</h3>
<pre><code>mkdir -p /srv/.BuildServer/lib/jdbc
mkdir -p /srv/.BuildServer/config
wget http://jdbc.postgresql.org/download/postgresql-9.3-1102.jdbc41.jar -O /srv/.BuildServer/lib/jdbc/postgresql-9.3-1102.jdbc41.jar
</code></pre>
<h3 id="changeownershipoffiles">Change ownership of files</h3>
<pre><code>sudo chown -R teamcity /srv/TeamCity
sudo chown -R teamcity /srv/.BuildServer
</code></pre>
<h2 id="createadatabaseconfigfileforpostgres">Create a Database Config file for PostGres</h2>
<h4 id="install">Install</h4>
<pre><code>apt-get update &amp;&amp; apt-get install -y postgresql postgresql-contrib
</code></pre>
<p>Open Postgres shell</p>
<pre><code>sudo su - postgres
psql
</code></pre>
<p>Enter the following to create the user and teamcity db (note your password you'll need it for the config)</p>
<pre><code>create role `teamcity` with login password 'my-very-secure-password';
create database `teamcity` owner `teamcity`;
</code></pre>
<p>Type <code>\q</code> and hit enter to exit PostGres shell.<br>
Then type <code>exit</code> to un-assume the Postgres user, and let's reset postgres aswell (you should still be root at this point, sudo if not) <code>/etc/init.d/postgresql restart</code></p>
<pre><code>nano /srv/.BuildServer/config/database.properties
</code></pre>
<p>Paste this in (or type it, if you're a sadist)</p>
<pre><code>connectionUrl=jdbc:postgresql://127.0.0.1/teamcity
connectionProperties.user=teamcity
connectionProperties.password=my-very-secure-password
</code></pre>
<p>Start that stuff up.</p>
<pre><code>/etc/init.d/postgresql start (if its not started)
/etc/init.d/teamcity start
</code></pre>
<p>Done</p>
</div>]]></content:encoded></item><item><title><![CDATA[Forcing SSLv3 Upstream in NGINX... fml]]></title><description><![CDATA[Forcing SSLv3 Upstream in NGINX]]></description><link>https://chrismckee.co.uk/forcing-sslv3-upstream-in-nginx-fml/</link><guid isPermaLink="false">59ea67b760bd1036bf11b535</guid><category><![CDATA[ssl]]></category><category><![CDATA[nginx]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Fri, 27 Mar 2015 10:44:39 GMT</pubDate><media:content url="https://chrismckee.co.uk/content/images/2015/03/poodle.gif" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://chrismckee.co.uk/content/images/2015/03/poodle.gif" alt="Forcing SSLv3 Upstream in NGINX... fml"><p>Sometimes you have to make sacrifices; often I wish I could place IT professionals at large Banks on a sodding Altar and cut their balls off.</p>
<p>Anyway. In some rare horrible occasions, you need to force the type of SSL/TLS used for an upstream. You do that as follows.</p>
<pre><code>upstream shittyserver {
   server 8.8.8.8:443;
}

server {
	listen 443;
	server_name dodgyproxy.com;
	  
	access_log  /var/log/nginx/access.log;
	error_log   /var/log/nginx/error.log;
	rewrite_log on;
	
	ssl on;
	ssl_certificate     /etc/certs/mycert;
	ssl_certificate_key /etc/certs/mykey;
	
	
	location / {
	    proxy_pass  https://shittyserver;
	    proxy_redirect default;
	    proxy_ssl_protocols SSLv3;
	    
	    proxy_set_header   Host &quot;shittyservershttphostname&quot;; 
	    proxy_set_header   X-Forwarded-Proto  https;
	        
	    proxy_set_header   SSL_PROTOCOL $ssl_protocol;
	    proxy_set_header   SSL_CLIENT_CERT $ssl_client_cert;
	    proxy_set_header   SSL_CLIENT_VERIFY $ssl_client_verify;
	    proxy_set_header   SSL_SERVER_S_DN $ssl_client_s_dn;
	  }
}

</code></pre>
</div>]]></content:encoded></item><item><title><![CDATA[Neither the JAVA_HOME nor the JRE_HOME environment variable is defined]]></title><description><![CDATA[Neither the JAVA_HOME nor the JRE_HOME environment variable is defined]]></description><link>https://chrismckee.co.uk/neither-the-java_home-nor-the-jre_home-environment-variable-is-defined/</link><guid isPermaLink="false">59ea67b760bd1036bf11b532</guid><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Tue, 09 Dec 2014 22:51:26 GMT</pubDate><media:content url="https://chrismckee.co.uk/content/images/2014/12/ubshell.JPG" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://chrismckee.co.uk/content/images/2014/12/ubshell.JPG" alt="Neither the JAVA_HOME nor the JRE_HOME environment variable is defined"><p>If you need a different version or are targeting a different version of Java, change version number accordingly the rest is the same.</p>
<p>Going in hard; let's get some root on<br>
<code>sudo su</code> Enter password if you need to.</p>
<p>If you prefer, you can enter sudo before each command.</p>
<h3 id="installjava">Install Java</h3>
<pre><code>apt-get install openjdk-7-jre-headless
</code></pre>
<h3 id="findjava">Find Java</h3>
<blockquote>
<p>Little tip:<br>
Installing <code>locate</code> helps a whole lot on Linux, in Ubuntu, it's usually installed by default <em>(if it's not, Ubuntu will tell you to apt-get install locate)</em></p>
</blockquote>
<p>In the case of Java Ubuntu (and Debian based releases) installs Java into <code>/usr/lib/jvm</code> so navigating to it, <code>cd /usr/lib/jvm</code> then <code>ls</code> will give you your folder path. There should be one with a long version than a short one like this...</p>
<pre><code>ls /usr/lib/jvm
default-java  java-1.7.0-openjdk-amd64  java-7-openjdk-amd64
</code></pre>
<h3 id="setthepaths">Set the paths</h3>
<p>Make a note of the paths then:</p>
<pre><code>nano /etc/profile
</code></pre>
<p>Then add your paths before the if statement.</p>
<pre><code>  export PATH=$PATH:/usr/lib/jvm/java-7-openjdk-amd64/bin
  export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
</code></pre>
</div>]]></content:encoded></item><item><title><![CDATA[Dear Umbraco… I Can Haz Content?!]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Basic mission; code not my own.</p>
<p>Create an advert type; consisting of URL and Image. Additional requirement created setting the type of advert (using uComponents) An AdvertContainer (Doc Type)</p>
<p>With two 'types' of advert (i.e. 3rdparty/mpu)</p>
<p>ThirdParty contains JS (no image/URL)<br>
MPU contains Image/URL</p>
<p><code>var nodes</code></p></div>]]></description><link>https://chrismckee.co.uk/dear-umbraco-i-can-haz-content/</link><guid isPermaLink="false">59ea67b760bd1036bf11b52a</guid><category><![CDATA[cms]]></category><category><![CDATA[icontentservice]]></category><category><![CDATA[umbraco]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Wed, 13 Mar 2013 12:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Basic mission; code not my own.</p>
<p>Create an advert type; consisting of URL and Image. Additional requirement created setting the type of advert (using uComponents) An AdvertContainer (Doc Type)</p>
<p>With two 'types' of advert (i.e. 3rdparty/mpu)</p>
<p>ThirdParty contains JS (no image/URL)<br>
MPU contains Image/URL</p>
<p><code>var nodes = GetMultiNodeSelection(1101, &quot;adverts&quot;);</code></p>
<p>Foists off into some god awful linq abuse…</p>
<pre><code>private IEnumerable&lt;IContent&gt; GetMultiNodeSelection(int id, string property)
{
    var node = _contentService.GetById(id);
    if (node.HasProperty(property))
    {
        var nodeProperty = node.Properties[property];
        var nodeIds = nodeProperty.Value.ToString().Split(',');
        return nodeIds.Select(nodeId =&gt; _contentService.GetById(int.Parse(nodeId))).ToList();
    }
    return null;
}
</code></pre>
<p>Apparently the between the methods this creates 646,908 hits in 44,111 hidden methods without source?! Most of this crap appears to be between .net and IIS having a bun fight.</p>
<p>Tripped and fell into Umbraco</p>
<pre><code>public IContent GetById(int id)
{
    using (IContentRepository repository = this._repositoryFactory.CreateContentRepository(this._uowProvider.GetUnitOfWork()))
    {
        return repository.Get(id);
    }
}
</code></pre>
<p>Feel like a kid on a long journey; are we there yet. I know theres a fucking database in here somewhere.</p>
<pre><code>public TEntity Get(TId id)
{
    Guid guid = (id is int) ? this.ConvertIdToGuid(id) : this.ConvertStringIdToGuid(id.ToString());  -- 41 Hits!? 
    IEntity byId = this._cache.GetById(typeof(TEntity), guid);
    if (byId != null)
    {
        return (TEntity) byId;
    }
    TEntity entity = this.PerformGet(id);
    if (entity != null)
    {
        this._cache.Save(typeof(TEntity), entity);
    }
    return entity;
}
</code></pre>
<p>INTO</p>
<pre><code>protected override IContent PerformGet(int id)
{
    Sql sql = this.GetBaseQuery(false).Where(this.GetBaseWhereClause(), new object[] { new { Id = id } })
                .Where&lt;DocumentDto&gt;(x =&gt; x.Newest).OrderByDescending&lt;ContentVersionDto&gt;(x =&gt; x.VersionDate);
    DocumentDto dto = base.Database.Fetch&lt;DocumentDto, ContentVersionDto, ContentDto, NodeDto&gt;(sql).FirstOrDefault&lt;DocumentDto&gt;();
    if (dto == null)
    {
        return null;
    }
    return this.CreateContentFromDto(dto, dto.ContentVersionDto.VersionId);
}
</code></pre>
<p>Getting bored now, how fucking deep is this well</p>
<pre><code>Umbraco.Core.Persistence.Repositories.RepositoryBase&lt;TId,TEntity&gt;.Get(TId id)
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId)
{
    IContentType contentType = this._contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);//The slowest bit
    IContent content = new ContentFactory(contentType, this.NodeObjectTypeId, dto.NodeId).BuildEntity(dto);
    if (dto.TemplateId.get_HasValue() &amp;&amp; (dto.TemplateId.Value &gt; 0))
    {
        content.Template = this._templateRepository.Get(dto.TemplateId.Value);
    }
    content.Properties = this.GetPropertyCollection(dto.NodeId, versionId, contentType);
    ((ICanBeDirty) content).ResetDirtyProperties();
    return content;
}
</code></pre>
<p>erm am I in a fucking hole within a hole here or what</p>
<p><code>public TEntity Get(TId id) // See above</code></p>
<p>Ah fun so now were in a different PerformGet</p>
<pre><code>Umbraco.Core.Persistence.Repositories.ContentTypeRepository.PerformGet(int id)
protected override IContentType PerformGet(int id)
{
    Func&lt;DocumentTypeDto, ITemplate&gt; selector = null;
    Sql baseQuery = this.GetBaseQuery(false);
    baseQuery.Where(this.GetBaseWhereClause(), new object[] { new { Id = id } });
    baseQuery.OrderByDescending&lt;DocumentTypeDto&gt;(x =&gt; x.IsDefault);
    DocumentTypeDto dto = base.Database.Fetch&lt;DocumentTypeDto, ContentTypeDto, NodeDto&gt;(baseQuery).FirstOrDefault&lt;DocumentTypeDto&gt;();
    if (dto == null)
    {
        return null;
    }
    IContentType type = new ContentTypeFactory(this.NodeObjectTypeId).BuildEntity(dto);
    type.AllowedContentTypes = base.GetAllowedContentTypeIds(id);
    type.PropertyGroups = base.GetPropertyGroupCollection(id);
    ((ContentType) type).PropertyTypes = base.GetPropertyTypeCollection(id);
    List&lt;DocumentTypeDto&gt; source = base.Database.Fetch&lt;DocumentTypeDto&gt;(&quot;WHERE contentTypeNodeId = @Id&quot;, new object[] { new { Id = id } });
    if (Enumerable.Any&lt;DocumentTypeDto&gt;(source))
    {
        if (selector == null)
        {
            selector = template =&gt; this._templateRepository.Get(template.TemplateNodeId);
        }
        type.AllowedTemplates = source.Select&lt;DocumentTypeDto, ITemplate&gt;(selector).ToList&lt;ITemplate&gt;();
    }
    foreach (ContentType2ContentTypeDto dto2 in base.Database.Fetch&lt;ContentType2ContentTypeDto&gt;(&quot;WHERE childContentTypeId = @Id&quot;, new object[] { new { Id = id } }))
    {
        type.AddContentType(base.Get(dto2.ParentId));
    }
    ((ICanBeDirty) type).ResetDirtyProperties();
    return type;
}
</code></pre>
<p>Now theres a name ICanBeDirty … funny, the deeper this goes the dirtier I feel.</p>
<pre><code>Umbraco.Core.Persistence.Repositories.ContentTypeBaseRepository&lt;TId,TEntity&gt;.GetPropertyGroupCollection(int id)
protected PropertyGroupCollection GetPropertyGroupCollection(int id)
{
    Sql sql = new Sql();
    sql.Select(new object[] { &quot;*&quot; }).From&lt;PropertyTypeGroupDto&gt;().LeftJoin&lt;PropertyTypeDto&gt;().On&lt;PropertyTypeGroupDto, PropertyTypeDto&gt;(left =&gt; left.Id, right =&gt; right.PropertyTypeGroupId, new object[0]).LeftJoin&lt;DataTypeDto&gt;().On&lt;PropertyTypeDto, DataTypeDto&gt;(left =&gt; left.DataTypeId, right =&gt; right.DataTypeId, new object[0]).Where&lt;PropertyTypeGroupDto&gt;(x =&gt; (x.ContentTypeNodeId == id)).OrderBy&lt;PropertyTypeGroupDto&gt;(x =&gt; x.Id);
    List&lt;PropertyTypeGroupDto&gt; dto = base.Database.Fetch&lt;PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto&gt;(new Func&lt;PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto&gt;(new GroupPropertyTypeRelator().Map), sql);
    PropertyGroupFactory factory = new PropertyGroupFactory(id);
    return new PropertyGroupCollection(factory.BuildEntity(dto));
}
</code></pre>
<p>Now for a bit of JIT overhead… annnnnnnnnnnnnnnd</p>
<pre><code>Umbraco.Core.Models.PropertyType..cctor
static PropertyType()
{
    NameSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, string&gt;(x =&gt; x.Name);
    AliasSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, string&gt;(x =&gt; x.Alias);
    DescriptionSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, string&gt;(x =&gt; x.Description);
    DataTypeDefinitionIdSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, int&gt;(x =&gt; x.DataTypeDefinitionId);
    DataTypeControlIdSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, Guid&gt;(x =&gt; x.DataTypeId);
    DataTypeDatabaseTypeSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, DataTypeDatabaseType&gt;(x =&gt; x.DataTypeDatabaseType);
    MandatorySelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, bool&gt;(x =&gt; x.Mandatory);
    HelpTextSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, string&gt;(x =&gt; x.HelpText);
    SortOrderSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, int&gt;(x =&gt; x.SortOrder);
    ValidationRegExpSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, string&gt;(x =&gt; x.ValidationRegExp);
    PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo&lt;PropertyType, int&gt;(x =&gt; x.PropertyGroupId);
}
</code></pre>
<p>hmm bit more JIT overhead… annnnnnnnnnnnnnnd</p>
<pre><code>public static PropertyInfo GetPropertyInfo&lt;TSource, TProperty&gt;(Expression&lt;Func&lt;TSource, TProperty&gt;&gt; propertyLambda)
{
    return PropertyInfoCache.GetOrAdd(new LambdaExpressionCacheKey(propertyLambda), delegate (LambdaExpressionCacheKey x) {
        Type type = typeof(TSource);
        MemberExpression body = propertyLambda.Body as MemberExpression;
        if (body == null)
        {
            if (propertyLambda.Body.GetType().get_Name() != &quot;UnaryExpression&quot;)
            {
                throw new ArgumentException(string.Format(&quot;Expression '{0}' refers to a method, not a property.&quot;, propertyLambda));
            }
            UnaryExpression expression2 = propertyLambda.Body as UnaryExpression;
            if (expression2 != null)
            {
                MemberExpression operand = expression2.Operand as MemberExpression;
                if (operand == null)
                {
                    throw new ArgumentException(&quot;The type of property could not be infered, try specifying the type parameters explicitly. This can happen if you have tried to access PropertyInfo where the property's return type is a value type, but the expression is trying to convert it to an object&quot;);
                }
                body = operand;
            }
        }
        PropertyInfo member = body.Member as PropertyInfo;
        if (member == null)
        {
            throw new ArgumentException(string.Format(&quot;Expression '{0}' refers to a field, not a property.&quot;, propertyLambda));
        }
        if ((type != member.ReflectedType) &amp;&amp; !type.IsSubclassOf(member.ReflectedType))
        {
            throw new ArgumentException(string.Format(&quot;Expresion '{0}' refers to a property that is not from type {1}.&quot;, propertyLambda, type));
        }
        return member;
    });
}
</code></pre>
<p>Hey were now using something in the system. Well kinda, mixed in with more usage of the above method.</p>
<p>In a tiny portion of application warm up 81.7% of time is spent in JIT overhead; now we can pretty much ignore that (kinda) as we know profilers disable native imaging which means the system will have to jump to JIT. Can't quite ignore the fucking horrendous pile of code it takes JUST to get a tiny bit of data.</p>
<p>---|| SQL SQL SQL</p>
<p>AND WHERE OFF &gt;</p>
<pre><code>SELECT *
FROM [cmsDocument]
INNER JOIN [cmsContentVersion]
ON [cmsDocument].[versionId] = [cmsContentVersion].[VersionId]
INNER JOIN [cmsContent]
ON [cmsContentVersion].[ContentId] = [cmsContent].[nodeId]
INNER JOIN [umbracoNode]
ON [cmsContent].[nodeId] = [umbracoNode].[id]
WHERE ([umbracoNode].[nodeObjectType] = 'c66ba18e-eaf3-4cff-8a22-41b16d66a972')
AND (umbracoNode.id = @0)
AND ([cmsDocument].[newest]='True')
ORDER BY [cmsContentVersion].[VersionDate] DESC

--

SELECT *
FROM [cmsContentTypeAllowedContentType]
WHERE ([cmsContentTypeAllowedContentType].[Id] = 1167)

--

SELECT *
FROM [cmsContentTypeAllowedContentType]
WHERE ([cmsContentTypeAllowedContentType].[Id] = 1166)

--

SELECT *
FROM [cmsPropertyTypeGroup]
LEFT JOIN [cmsPropertyType]
ON [cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]
LEFT JOIN [cmsDataType]
ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]
WHERE ([cmsPropertyTypeGroup].[contenttypeNodeId] = 1167)
ORDER BY [cmsPropertyTypeGroup].[id]

--

SELECT *
FROM [cmsPropertyTypeGroup]
LEFT JOIN [cmsPropertyType]
ON [cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]
LEFT JOIN [cmsDataType]
ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]
WHERE ([cmsPropertyTypeGroup].[contenttypeNodeId] = 1166)
ORDER BY [cmsPropertyTypeGroup].[id]

--

SELECT *
FROM [cmsPropertyType]
INNER JOIN [cmsDataType]
ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]
WHERE ([cmsPropertyType].[contentTypeId] = 1167)

--

SELECT *
FROM [cmsPropertyType]
INNER JOIN [cmsDataType]
ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]
WHERE ([cmsPropertyType].[contentTypeId] = 1166)

--

SELECT *
FROM [cmsDocumentType]
RIGHT JOIN [cmsContentType]
ON [cmsContentType].[nodeId] = [cmsDocumentType].[contentTypeNodeId]
INNER JOIN [umbracoNode]
ON [cmsContentType].[nodeId] = [umbracoNode].[id]
WHERE ([umbracoNode].[nodeObjectType] = 'a2cb7800-f571-4787-9638-bc48539a0efb')
AND (umbracoNode.id = @0)
ORDER BY [cmsDocumentType].[IsDefault] DESC

--

SELECT [cmsContentType2ContentType].[parentContentTypeId], [cmsContentType2ContentType].[childContentTypeId] FROM [cmsContentType2ContentType] WHERE childContentTypeId = @0

--


SELECT [cmsDocumentType].[contentTypeNodeId], [cmsDocumentType].[templateNodeId], [cmsDocumentType].[IsDefault] FROM [cmsDocumentType] WHERE contentTypeNodeId = @0

--

SELECT *
FROM [cmsContentTypeAllowedContentType]
WHERE ([cmsContentTypeAllowedContentType].[Id] = 1165)

--

SELECT *
FROM [cmsPropertyTypeGroup]
LEFT JOIN [cmsPropertyType]
ON [cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]
LEFT JOIN [cmsDataType]
ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]
WHERE ([cmsPropertyTypeGroup].[contenttypeNodeId] = 1165)
ORDER BY [cmsPropertyTypeGroup].[id]

--

SELECT *
FROM [cmsPropertyType]
INNER JOIN [cmsDataType]
ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]
WHERE ([cmsPropertyType].[contentTypeId] = 1165)

--

SELECT *
FROM [cmsPropertyData]
INNER JOIN [cmsPropertyType]
ON [cmsPropertyData].[propertytypeid] = [cmsPropertyType].[id]
WHERE ([cmsPropertyData].[contentNodeId] = 1172)
AND ([cmsPropertyData].[versionId] = '7dbfb821-05b4-443e-a616-0cb5d126acad')


--

SELECT *
FROM [cmsPropertyData]
INNER JOIN [cmsPropertyType]
ON [cmsPropertyData].[propertytypeid] = [cmsPropertyType].[id]
WHERE ([cmsPropertyData].[contentNodeId] = 1171)
AND ([cmsPropertyData].[versionId] = '6f80d6cd-d1ac-4793-bca3-4343f34f9515')

--

SELECT *
FROM [cmsPropertyData]
INNER JOIN [cmsPropertyType]
ON [cmsPropertyData].[propertytypeid] = [cmsPropertyType].[id]
WHERE ([cmsPropertyData].[contentNodeId] = 1170)
AND ([cmsPropertyData].[versionId] = '510748fa-e6f5-4164-b237-8cea211bff31')
</code></pre>
<p>Ooook so less of a quick dive; more like being drowned. To add some context; Node: 1173 consists of 5 records which build up a media element in umbraco (file/width/height/etc); the query was to</p>
<p>To query this one bit of the required data from the db Umbraco creates this query...</p>
<pre><code>SELECT  *
FROM    [cmsPropertyData]
        INNER JOIN [cmsPropertyType] ON [cmsPropertyData].[propertytypeid] = [cmsPropertyType].[id]
WHERE   ( [cmsPropertyData].[contentNodeId] = 1173 )
        AND ( [cmsPropertyData].[versionId] = '87089cf2-f3fb-48c0-904a-346c56d14f2a' )
</code></pre>
<p>In fairness, once started, with A LOT of the site not actually making use of umbraco it performs ok. The nodes being loaded in this instance was simply pulling the content of an advert container. Which consists of 3 adverts; an advert consisting of a dropdown (3 items in it to set the type), a media picker (1 image) and a url.</p>
<p>Bit of a double edged blade; if you use umbraco doctypes for everything (think blog style/comments/date filters/long trees lots of properties) it blows and flamethrows memory till there's nothing left; if you treat umbraco like a repository your reliant on the API being stable, set in stone, and eventually, and probably not as far away as you'd like it, to be able to debug it without being dropped into a mass of generic/anonymous methods/linq hell.</p>
<p>Bleh</p>
</div>]]></content:encoded></item><item><title><![CDATA[Lowercase Routes in ASP.net MVC4]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Back in MVC2 days I wrote a post on setting up a project with lowercase urls / redirecting and a workaround for IIS6. Luckily these days we have MVC4 which is a tad friendlier… to a degree.</p>
<p>In the Route collection registration area (Most likely in App_Start lest you've moved</p></div>]]></description><link>https://chrismckee.co.uk/lowercase-routes-in-asp-net-mvc4/</link><guid isPermaLink="false">59ea67b760bd1036bf11b531</guid><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Tue, 05 Mar 2013 12:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Back in MVC2 days I wrote a post on setting up a project with lowercase urls / redirecting and a workaround for IIS6. Luckily these days we have MVC4 which is a tad friendlier… to a degree.</p>
<p>In the Route collection registration area (Most likely in App_Start lest you've moved it) you can now simply add <code>routes.LowercaseUrls = true;</code> (<a href="http://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.lowercaseurls.aspx">http://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.lowercaseurls.aspx</a> )</p>
<p>The big bugger about this is (and theres a bug in codepex for it here <a href="http://aspnetwebstack.codeplex.com/workitem/685?PendingVoteId=685">http://aspnetwebstack.codeplex.com/workitem/685?PendingVoteId=685</a>) when you add an MVC Area the bloody thing stops working.</p>
<p>In which case you'll want to use <a href="http://nuget.org/packages/LowercaseRoutesMVC4/">http://nuget.org/packages/LowercaseRoutesMVC4/</a> which does the trick.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Self Referencing Table Joins in FluentNHibernate]]></title><description><![CDATA[<div class="kg-card-markdown"><p>A common usage of the self-referencing joins is the use of 1 table for regions and subregions; its also the laziest example that comes to mind.</p>
<p><img src="https://chrismckee.co.uk/content/images/2014/11/tblRegion.png" alt=""></p>
<p>Entity</p>
<pre><code>using System.Collections.Generic;
using Domain.Base;

public class Region : DomainObject&lt;int, Region&gt;
{
    private IList&lt;Region&gt; _subRegion = new List&</code></pre></div>]]></description><link>https://chrismckee.co.uk/self-referencing-table-joins-in-fluentnhibernate/</link><guid isPermaLink="false">59ea67b760bd1036bf11b52c</guid><category><![CDATA[fluentnhibernate]]></category><category><![CDATA[fn]]></category><category><![CDATA[nhibernate]]></category><category><![CDATA[self-join]]></category><category><![CDATA[self-reference]]></category><category><![CDATA[self-referencing]]></category><dc:creator><![CDATA[Chris McKee]]></dc:creator><pubDate>Tue, 19 Feb 2013 12:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>A common usage of the self-referencing joins is the use of 1 table for regions and subregions; its also the laziest example that comes to mind.</p>
<p><img src="https://chrismckee.co.uk/content/images/2014/11/tblRegion.png" alt=""></p>
<p>Entity</p>
<pre><code>using System.Collections.Generic;
using Domain.Base;

public class Region : DomainObject&lt;int, Region&gt;
{
    private IList&lt;Region&gt; _subRegion = new List&lt;Region&gt;();
    public virtual string Name { get; set; }

    public virtual IList&lt;Region&gt; SubRegion
    {
        get { return _subRegion; }
        set { _subRegion = value; }
    }
}
</code></pre>
<p>ClassMap</p>
<pre><code>using Domain;
using FluentNHibernate.Mapping;

public class RegionMappingClass : ClassMap&lt;Region&gt;
{
    public RegionMappingClass()
    {
        Id(x =&gt; x.Id).GeneratedBy.Identity();
        Map(x =&gt; x.Name).Not.Nullable().Length(50);
        HasMany&lt;Region&gt;(x =&gt; x.SubRegion).KeyColumn(&quot;ParentRegionId&quot;).Cascade.All();
    }
}
</code></pre>
<p>Fixture / Persistence Specification</p>
<pre><code>using System;
using System.Collections.Generic;
using Domain;
using FluentNHibernate.Testing;
using NUnit.Framework;

[TestFixture]
[Category(&quot;DataIntegration&quot;)]
public class RegionMappingFixture : IntegrationTestBase
{
    [Test]
    public void CanCreateRegions()
    {
        var region = new Region()
                         {
                             Name = &quot;Gtr Manchester&quot;
                         };

        Session.Save(region);

        region.SubRegion.Add(new Region() {Name = &quot;Test B&quot;});
        region.SubRegion.Add(new Region() {Name = &quot;Test C&quot;});

        Session.Save(region);

        FlushAndClear();

        Assert.NotNull(region.Id);
    }

    [Test]
    public void CanMapRegion()
    {
        new PersistenceSpecification&lt;Region&gt;(Session)
            .CheckProperty(x =&gt; x.Name, &quot;Gtr Manchester&quot;)
            .CheckList(x =&gt; x.SubRegion, new List&lt;Region&gt; {new Region() {Name = &quot;Bolton&quot;}, new Region() {Name = &quot;Bury&quot;}})
            .VerifyTheMappings();
    }
}
</code></pre>
<p>Small caveat; this code is supplied as a sample, the tests here are the minimum and nothing more</p>
</div>]]></content:encoded></item></channel></rss>