Sloth, the online BCF viewer

I am a vocal proponent of the BIM Collaboration Format. I think issue tracking is what is missing in the building industry, and the BCF provide a standard to do just that. In the meantime, more and more tools are supporting BCF, with the notable exception of Autodesk products, even if add-ons can fill this gap for Revit and Navisworks.

Yet, convincing people to leave their spreadsheet-based ways of working to go on BCF-based workflows still need some form of paper-based reports extracted from these BCF issues. Most of the BCF-based tools lacks this sort of reporting. In this regard, BIM Collab is the best one, and provide the ability to create PDF and Excel reports. But even BIM Collab won’t support Word documents, or the ability to use a custom template.

A while ago, I built a small utility to create Word reports from BCF files. However, this tool doesn’t support BCF 2.0, and lack the ability to create Excel reports. It was more than time to upgrade it. Instead of improving upon it, I decide to rebuild it, this time as a web-based tool, to make it more accessible.

So, I introduce you my very first “web-app”, Sloth, an online BCF reports generator.

Sloth BCF

You can upload a BCF file and see the resulting report in your browser, showing the main information in your issue: Tittle, author and creation date, along with the first screenshot in your issue.

Uploading a BCF file

Once your issues are loaded in your browser, you can export them in a report in a Word or Excel format, writing down all information found in this BCF file. Sloth use basic styles in Microsoft Word to highlight titles and dates.

Export a Word report

You can also upload a Microsoft Word template (.dotx) before exporting the Word report. Your template will be used to create this report.

Add a Word template

To read these BCF files, I am using the XbimBCF .Net library developed by the openbim.org team.  Xbim is following to the letter the BCF specification, adding every necessary check to ensure that all mandatory values are here, between the assigned limits. A few solutions don’t support these specifications, you will end up with the following error message if you try to upload a BCF file from them:

Error in the BCF file

I have tested Sloth with BCF files created in bimsync, Tekla BIMSight, BIMcollab and Solibri. I assume that BIMCollab’s Revit and Navisworks plugins will work as well, please let me know if it is not the case.

As usual, the application is open-source, licensed under the MIT Licence. You can find the source on GitHub. Please don’t hesitate to report any issues you might find, and happy reporting!

Revit plugins updates and new features

As usual during this time of the year, I published the new version of my plugins for Revit.

Align

The big improvement this year is the ability to align any type of elements, annotations or tags. I must thank Deyan Nenov and his large contribution to the source code for this new feature.

From now on, you can select any kind of element and align or distribute them evenly. This feature use the bounding box of the element in the view as a reference.

Align or distribute all elements

The Align command is still view-dependent, so using it in section view or in a plan view will not have the same effect on the overall position of a given element. A word of caution however, the align function can be unreliable in a 3D view.

View-dependent align functions

Of course, you can still use it to align or distribute your tags and annotations, and it even works with viewports:

Align viewports

Along with these improvement, Align now fully support Area tags, and a few bugs have been eliminated. You can now use Align even if on tag without a leader, and multi-leader text are now fully supported, and some selection subtlety have been introduced.

Align tags and texts

I haven’t tested it with all categories, if you find something weird, please let me know, I would be happy to fix it.

You can find this new version on the Autodesk App Store.

Room Finishing

Along with the support for Revit 2018, I corrected an issue where a skirting board was created even if the room was not bound by a wall. From now on, Room Finishing will not create a skirting board along room bounding lines.

Support room with room boundary lines

Room Finishing is also available on the App Store.

Time Stamper

The Time Stamper plugin got a few improvements this year along with the usual bug smashing.

You can now choose between applying your time stamp to every element, or just the one visible in the view. This will give you the ability to filter on which element you want to apply a stamp.

You can also choose to keep or override an existing value, this should help you keep the history of a given element.

A few bugs where corrected, making the creation of the four shared parameters far more reliable. Groups are now supported.

Support for groups

Time Stamper is now available here.

These new versions are now available on the Autodesk App Store. Don’t hesitate to report any issue you might find in them or ask for improvement.

These plugins are open source, you can find the source code here, here and here. Feel free to use it on your own project or contribute to these projects.

Linking documents to a model

These days, there is a lot of ideas around using a building information model for facilities management. Among these ideas, a recurring theme is to integrate documents, mostly technical sheets, directly into the model.

Aside from the fact that I don’t see how a model build to design, analyse, and coordinate a building could be use directly in facilities management, there is also some non-trivial technical problems to overcome to have any documents properly linked to your model, whether you are using Revit, Navisworks, or an IFC viewer.
Below is a list of these technical problems, and some though on how to solve them.

Adding a link in Revit

Adding a link in Revit is fairly straightforward, you just have to use a “URL” parameter (shared or built in), and type in your link. Since a technical sheet is generally the same for every building element of a given type, it makes more sense to me to add it in a type parameter.

Door Type URL parameter

Door Type URL parameter

As you can see, I type in a relative path to my technical documentation, this allows me to move around the entire “As-built documentation” folder (models and technical sheets in PDF) without breaking the links. I end up with a pretty simple folder structure, with a model at its root, and the technical sheets nicely ordered in one folder per category.

The folder structure

The folder structure

If you click on the small “…” button in Revit, your linked technical document will immediately open in the associate viewer, here, Acrobat Reader.

How to open the linked technical sheet

How to open the linked technical sheet

Adding a link without Revit

Selecting equipment and material is generally done through spreadsheets or building economy software, and by people who could not be proficient with Revit. Therefore, I have searched for solution to do it outside Revit.
The new Flux Scheduler is an application based on Flux, which allows us to create online schedules from data uploaded through the Revit Flux plugin.

The Flux Scheduler

The Flux Scheduler

By using this Flux Scheduler, I could upload my doors on Flux, create a door schedule directly on Flux, use Excel to add the URL link, and upload back these values in Revit

Type the URL in Excel before uploading them in Revit

Type the URL in Excel before uploading them in Revit

Delivering a Navisworks model

Once exported to Navisworks, the “Link” button will display a small link button on every linked object, which open the linked technical sheet.

The link in Navisworks

The link in Navisworks

However, you must keep your Navisworks model in the same location in your “As-Build Documentation” folder structure as your initial Revit model to keep the relative links functional. In our case, we end up with the following folder structure:

The folder structure with a Navisworks model

The folder structure with a Navisworks model

Delivering an IFC model

If you export this Revit model to IFC, and open it in Solibri Model Viewer, you can display the link, but not click on it. However, by writing a “\” before the link in Revit, Solibri Model Viewer recognize it as link and you can open the technical sheet with a click. This could obviously become problematic in Revit, since when you add this “\”, Revit doesn’t recognize the link anymore.

The clickable link in Solibri

The clickable link in Solibri

Tekla BIMSight, on the other hand, couldn’t recognized any of those links as a clickable item.

As you can see, they are many ways to link documents to a model and retrieve them in a viewer, and a few things could go wrong along the way. So, before starting anything, I would recommend to make sure you can link or embedded documents in your deliverables and structure these deliverables accordingly.

Align Tag Update

It is this time of the year again, and I have finally take the time to update Align on the App Store for the new version of Revit.

However, there is more in this than a simple version update, and this new release is packed with improvement, both small and large.

The main change reside in the alignment method. In the previous version of Align Tag, I was using the center point of a given tag as a reference to align tag (either left or right). To improve on the alignment of tags of various sizes, I now use the bounding box of the tag.

AlignSolution

Tags will now properly align themselves along their right or left side, regardless of their size or origin point.

Align

However, if you want something similar to the older version, you can use the new Align Center and Align Midlle commands, which will use the center of the tag as a reference.

This new alignment method is more in line with what can be found on solutions like PowerPoint, or Adobe Illustrator, and will allows you to neatly arrange your tag whatever their size or origin point.

Another important improvement is the long awaited support for Text. You can now align Text along with Tag, using the same command.

While I was at it, I also add support for Keynote tag, Room Tag and Space Tag, basically every tag. The Area Tag is still missing, but can be expected for the next version.

However, this support came at a cost, and I have to drop the support for Revit 2015 and prior. So, if you are still using this version, you will have to keep the old Align plugin.

There is also a handful of small UI improvement that I hope will help you.

Aligned tags are now kept selected after running the command so you can align them in another direction right away.

Your Align commands are also one click closer to you! The interface have been artfully arranged in a new tab to keep every icon directly accessible in the ribbon.

icons1

Under the hood, I have rewrote a large part of the code to support more types of annotation elements, and I hope to be able to use this new framework for more complex manipulations, including in the Arrange Tags function.

Of course, Align Tag is still open source, the entire code can be found on Bitbucket.

This plug-in is already available on the Autodesk App Store. If you like it, don’t hesitate to write a nice comment or add a few stars, it always means so much to me!

Wall Openings (again)

I am kind of obsessed with wall openings. The entire process of asking a structural engineer for holes in its beloved wall to let ducts and pipes goes through has always been a rather frustrating experience.

After my first article about a semi-automated way for placing an opening family, here is my latest attempt at creating the perfect opening family.

A good opening family must have the following features:

  • hosted on a wall, a slab or a beam
  • visible in a 3D view
  • fully parametric
  • schedulable
  • sharable in its own model
  • a nice 2D representation

Lets explore these features.

To host them, but still keep the ability to share them in their own model, I use the Generic Model Face Base family template to create my opening family. This template allows me place my opening on any wall, slab or beam, even if they are in a linked model.

In this Generic Model, I create the Opening subcategory, where I will place every element of my opening. This will allow me to fine tune the display of my openings in my model.

I create a bunch of reference planes, and drive them with three shared parameters, Width, Height and Depth. These reference planes help me constrain the Void Form that will cut the host. This void form will create an actual hole in the wall or slab, and will allow me to perform accurate clash detections after integrating these openings.

To be able to see my opening in a 3D view, I draw some Model Lines to outline the general shape of the opening, and place them in the “Opening” subcategory. These Model Lines are only visible in 3D.

3D View

The 2D representation is a pretty complex subject, and I have yet to find the perfect solution. After some experiences with Model lines, I have switched to annotations elements. These annotations elements are drawn in two nested families, one for the projection symbol, the other for the cut symbol.

These annotation families are drawn in a Generic Model, with the “Opening” subcategory, in order to follow the same graphical rules than the main family.

I also use Masked Regions to draw filled patterns, and use the Generic Model Override in a plan view to fill them with black. I am not entirely satisfied with this solution, but the workaround involve Detail Items, and I don’t want to deal with two different categories.

PlanSection 1

Section 2

To display the elevation of my opening family in a tag, or a schedule, I create two shared parameter, Top Elevation and Bottom Elevation.

As I was searching for a solution to calculate the elevation, I notice a feature I wasn’t aware of, the “Schedule Level”, present since at least Revit 2015, that allow us to define a reference level. Revit use it to automatically calculate the corresponding elevation. Since this elevation cannot be used directly in a schedule or a tag, I use a Dynamo definition to update elevation values in my shared parameters. This Dynamo definition perform some simple calculation to retrieve Top and Bottom elevations, and send these values in the corresponding shared parameter.

Dynamo

My work with wall openings is far from complete, and subjects like sharing these openings, and managing their modifications are still pending. You will find here the different families, models and Dynamo definition used in this article, feel free to use or improve on them.

Details Items, subcategories and filled regions

I am currently working with multiple detail items to create a set of views for architectural detailing. These Detail Items must comply with a precise standard for color and line weights, and of course, be consistent all over the model.

To implement these requirements, I define a set of subcategories for these detail items. Let see how it works with these two wood windows details.

01-WindowsDetailsComponents

These detail items already contain various subcategories, and I can control the color, weight and patterns of their lines in Visibility Overrides. Here Medium Lines are blue and Light Lines are red. Interesting, but not quite enough.

02-LineTypeOverrride

I open these two detail items, go to Object Styles, and create four new subcategories: Wood, Glass, Sealant and Steel. I also remove the previous subcategories. I can now select all lines in the detail item, and assign corresponding subcategories to these lines. Once these detail items are loaded back in the model, the four Detail Item subcategories are visible in the Graphic Overrides window.

I can now control line color, weight and pattern directly in my model, in the Graphic Overrides window for the current view, or in the Object Styles window to apply these colors to every details in the model.

03-OverideByMaterial

Sadly, there is no corresponding feature for managing filled region. As you can see in the picture above, the wood pattern is still in black.

In order to change pattern or color in a filled region, you have to edit the detail item and change the filled region style in the family. If you want to edit your wood pattern, you have to open every detail items containing wood, and change the pattern in the family.

To fix this, and be able to edit directly filled region style for every detail item, I create a small piece of code. This function matches model filled region types with those inside the detail item. So if I have a filled region in my Detail Item family with the same name than one in my Revit project, this filled region will take the properties of the one in the project.

matchProperties

After running this function, I end up with nicely matching wood pattern, all set up directly in my Revit project.

04-OverideFilledRegion

As usual, you will find the source code for this solution below, I hope it will help you solve your filled region issues.


public partial class ThisApplication
{
	public void MatchFilledRegion()
	{
		Document doc = this.ActiveUIDocument.Document;
		
		//Find all Filled Region Type, and create a dictonary with it
		Dictionary<string,FilledRegionType> modelFilledRegionTypes =
			new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType)).ToElements().Cast<FilledRegionType>().ToDictionary(e => e.Name);
		
		//Find all loaded families
		IList<Element> elements = new FilteredElementCollector(doc).OfClass(typeof(Family)).ToElements();
		
		//Get Detail Item category id.
		ElementId detailItemCategoryId = doc.Settings.Categories.get_Item(BuiltInCategory.OST_DetailComponents).Id;
		

		
		//Loop on all loaded families
		foreach (Element familyElement in elements) {
			
			Family family = familyElement as Family;
			
			//Exit the families loop if it isn't a Detail Item Familly
			if (family.FamilyCategory.Id != detailItemCategoryId) continue;

			//Open the family
			Document familyDoc = doc.EditFamily(family);
			string familyPath = Path.Combine(Path.GetTempPath(),family.Name+".rfa");
			
			bool familyEdited = false;
			
			//Find all Filled Region Type in the family
			IList<Element> filledRegionTypes = new FilteredElementCollector(familyDoc).OfClass(typeof(FilledRegionType)).ToElements();
			
			using (Transaction famTx = new Transaction(familyDoc))
			{
				famTx.Start("Edit Filled Region Type");
				
				//Loop on all Filled Region types in the family
				foreach (Element filledRegionTypeElement in filledRegionTypes)
				{
					FilledRegionType filledRegionType = filledRegionTypeElement as FilledRegionType;
					if (modelFilledRegionTypes.ContainsKey(filledRegionType.Name))
					{
						FilledRegionType refFilledRegion = modelFilledRegionTypes[filledRegionType.Name];
						//Change the color
						if (filledRegionType.Color.Red != refFilledRegion.Color.Red
						    || filledRegionType.Color.Blue != refFilledRegion.Color.Blue
						    || filledRegionType.Color.Green != refFilledRegion.Color.Green)
						{
							filledRegionType.Color = refFilledRegion.Color;
							familyEdited = true;
						}
						
						//Change the Background
						if (filledRegionType.Background != refFilledRegion.Background)
						{
							filledRegionType.Background = refFilledRegion.Background;
							familyEdited = true;
						}
						
						//Change line weight
						if (filledRegionType.LineWeight != refFilledRegion.LineWeight)
						{
							filledRegionType.LineWeight = refFilledRegion.LineWeight;
							familyEdited = true;
						}
						
					}
					
				}
				
				famTx.Commit();
			}
			
			if (familyEdited)
			{
				familyDoc.LoadFamily(doc, new FamilyOption());
				familyDoc.Close( false );
			}
			else
			{
				familyDoc.Close( false );
			}
		}
	}
}

public class FamilyOption : IFamilyLoadOptions
{
	public bool OnFamilyFound(bool familyInUse,out bool overwriteParameterValues)
	{
		overwriteParameterValues = true;
		return true;
	}
	
	public bool OnSharedFamilyFound(Family sharedFamily,bool familyInUse, out FamilySource source,out bool overwriteParameterValues )
	{
		source = FamilySource.Family;
		overwriteParameterValues = true;
		return true;
	}
}

Time Stamper, the Add-In

There is no easy way to override the color of an entire Revit link. Since most of my work involves linking Revit model from various subcontractors, this is something I miss badly.

Until recently, I was still using some workset hack to create filters on linked models. These filters were allowing me to display linked model with my color of choice.

But relying on workset leave much to be desired, and I have to find another solution.

I recently came up with a different solution, where each model element know where they came from.

The idea is to add file name, date and version in shared parameters on every model element. I created the corresponding Revit Add-In, and it is now available on the Autodesk App Exchange.

This application will:

  • Ask for identification information
  • Create four shared parameters on every category
  • Fill these shared parameters with identification information

The code itself is pretty easy, but there is a lot of applications.

First, it becomes easy to create filters on linked model. These filters allow us to display each linked model with a different color.

ColorsByModel

But it also enables us to tag the origin of every element, like we can see in the following screenshot.

IdentifyElements

You can create a linked models schedule, with date and version.

LinkedFilesSchedule

To help you create filters and tags with these parameters, you will find here the shared parameter text file. Please also note that the application uses a list of categories to create the four shared parameters. You will find this list here.

I hope this application will help you in your work, don’t hesitate to share your suggestions in the comments.

Automatic Modeling

Most questions I encounter these days turn around using building information modeling for producing construction drawings, schedules or clash detection reports. These features are important, of course, but they remain centered around using a more or less complete building model. But a largely overlooked use of building information model is the ability to automatically model building elements. In fact, object-oriented modeling should allow us to simply describe our solutions and let the computer implement them in our building model, and even warn us when something doesn’t fit.

Lead by this thought, and a problem raised by one of my colleague, I started looking again toward slab insulations. Before BIM, slab insulation was simply annotated on the drawing, and taken into account when creating a building section. Now, for coordination purpose, we have to spend large amount of time modeling everywhere a fairly simple element like insulation, without real added value.

There is nothing new with this problem, and I was already trying to find a solution for modeling insulation layers on the upper face of a series of spaces with my latest version of RoomFinishes, without finding a decent solution.

But while looking for something totally different, I came across this article in AUGI about room and spaces in Revit. So after five years working with Revit, I realized than by checking this small checkbox in the “Area and Volume Computations”, the room continues up until it fit a room bounding element, a ceiling or a floor.

VolumeComputation

Energized by this nice discovery, I created a small application for automatically modeling insulation. This application retrieves every faces of a given room, and uses the higher ones as references for modeling floors and walls as insulations.

Insulation

The only problem here is framing. They are not room bounding elements, and the upper face of the room does not fit the shape of the beam. I solved temporary this problem by creating a small floor under the beam.

beam

While doing this, I realized there is a lot of tricky cases, where insulation have to be modeled as wall or slab regarding of the configuration.

The entire code for this application can be found here. It is quite messy, but I hope it can help you anyway.

This small example illustrates one of the possibilities of working with building information models, where information can actually help us focus more on the actual design of the building and less on the representation of this design in the model.

Insulation Tag

I am not very fond of duct and pipe insulations in Revit. If the concept is very useful, I find difficult to add and edit them. Furthermore, seeing the insulation on every duct and pipe can quickly clutters the view. We want to know how much insulation we have, but we don’t want to see it everywhere.

In a technical drawing, we generally represent insulation only on small parts of the duct, with an annotation, and then infer that the duck is covered everywhere else.

To adapt this method on Revit, I create two detail components, representing the insulation on a round and on a rectangular duct.

Annotations

This components have a “Width” instance parameter for setting their width regarding the thickness of the insulation.

Width

I also create a small piece of code to instantiate these components on selected ducts and pipes.

The idea is to pick a series of duct and pipe, read their insulation thickness, and add a detail component with the corresponding thickness. Like this, we can control where we want to see an insulation, and improve the overall legibility of the drawing.

Animation

This solution allow me to create quickly some annotations to represent the insulation without having to display it everywhere. However, this is more a workaround than a real solution. Nothing here is adaptive, and you have to restart the tool each time you edit or even move your duct.

public void InsulationTag()
		{
			UIDocument uidoc = this.ActiveUIDocument;
			Document doc = uidoc.Document;
			
			Reference r = null;
			
			//Retrive the two symbols
			FamilySymbol rectangularSymbol = null;
			FamilySymbol roundSymbol = null;
			ICollection<Element> collection = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).OfCategory(BuiltInCategory.OST_DetailComponents).ToElements();
			foreach (Element element in collection)
			{
				FamilySymbol current = element as FamilySymbol;
				// This NewFamilyInstance overload requires a curve based family
				if (current.Family.Name == "DuctInsulationAnnotationRectangular")
				{
					rectangularSymbol = current;
				}
				else if (current.Family.Name == "DuctInsulationAnnotationRound")
				{
					roundSymbol = current;
				}
			}
			

			
			try
			{
				while (true) {
					
					using( Transaction t = new Transaction( doc ) )
					{
						t.Start( "Annotate Insulations" );

						r = uidoc.Selection.PickObject(ObjectType.Element, new SelectionFilter(),"Pick a duct");
						
						if (r != null)
						{
							MEPCurve mepCurve = doc.GetElement(r.ElementId) as MEPCurve;
							//doc.ActiveView.GetElementOverrides
							//Get the middle of the duct
							LocationCurve locCurve = mepCurve.Location as LocationCurve;
							XYZ insertionPoint = locCurve.Curve.Evaluate(0.5,true);
							//Get the angle
							XYZ vector = locCurve.Curve.GetEndPoint(1) - locCurve.Curve.GetEndPoint(0);
							double angle = new XYZ(1,0,0).AngleTo(vector);
							
							//Get the insulation
							ICollection<ElementId> insulationIds = InsulationLiningBase.GetInsulationIds(doc,r.ElementId);
							
							if (insulationIds.Count !=0)
							{
								InsulationLiningBase insulation = doc.GetElement(insulationIds.First()) as InsulationLiningBase;
								
								if (insulation != null)
								{
									FamilySymbol symbol = null;
									double widht;
									try {
										widht = insulation.Width;
										//Select the detail familly
										symbol = rectangularSymbol;
									} catch (Autodesk.Revit.Exceptions.InvalidOperationException) {
										Parameter outerDiameter = mepCurve.get_Parameter(BuiltInParameter.RBS_PIPE_OUTER_DIAMETER);
										if (outerDiameter != null)
										{
											widht = insulation.Thickness*2 + outerDiameter.AsDouble();
										}
										else
										{
											widht = insulation.Diameter;
										}
										
										//Select the detail familly
										symbol = roundSymbol;
									}
									
									//Create the annotation
									FamilyInstance annotation = doc.Create.NewFamilyInstance(insertionPoint,symbol,doc.ActiveView);
									
									//Change the witdh
									annotation.GetParameters("Width").First().Set(widht);
									
									//rotate the component
									annotation.Location.Rotate(Line.CreateUnbound(insertionPoint,new XYZ(0,0,1)),-angle);
								}
							}
						}

						t.Commit();
					}
				}
				
			}
			catch( Autodesk.Revit.Exceptions.OperationCanceledException )
			{
			}
		}

public class SelectionFilter : ISelectionFilter
	{
		#region ISelectionFilter Members

		public bool AllowElement(Element elem)
		{

			if (elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_DuctCurves) return true;
			if (elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves) return true;

			return false;
		}

		public bool AllowReference(Reference refer, XYZ pos)
		{
			if (refer.ElementReferenceType == ElementReferenceType.REFERENCE_TYPE_NONE) return false;

			if (refer.ElementReferenceType == ElementReferenceType.REFERENCE_TYPE_SURFACE) return true;
			if (refer.ElementReferenceType == ElementReferenceType.REFERENCE_TYPE_LINEAR) return true;

			return false;
		}

		#endregion
	}

BFC Reader

I was talking on my previous post about creating a report from a Open BIM Collaboration Format. This format can be exported from Tekla BIMSight.

I am using the Open BIM Collaboration Format on a daily basis for taking notes during coordination meetings. I am using Tekla BIMSight to create these notes, but any model review solution could do the trick, as long as you can export BCF files from it.

These notes are quite useful for addressing coordination problems, but cannot be seen outside a model.

After the proof of concept I presented to you on my last post, I finally took the time to build a packaged application in order to create a Microsoft Word document from a BCF report.

BCF Reader

Aside from minor technical problems, I was most concerned by the possibilities to edit the style of the report before creating it, and avoid the tedious task to clean it up in Word after.

I finally selected a solution mixing Word template and styles. All you have to do after selecting you BCF report is to load a Word template. The application will automatically retrieve all styles in it, and you will be able to select them for each part of your report.
These parts are described in the picture below, where every information embedded in the BCF note is written down on the report.

Report

You can then save your report in a new word document.

The application can be downloaded here, under the MIT licence.

The entire source code is also available on Bitbucket, feel free to use it for your own project.