Often times, our sales team will approach a client and talk up our integration with blue-tooth peripherals, on device bar-code scanners, network printers, etc., usually displaying the capabilities of the latest brand-name mobile device. I have been in rooms when these sales discussions are taking place, and it is really a joy to see the excitement our potential customers have as the wheels start turning; each person thinking of how our integration with X will solve some Y set of problems their company is facing.
The product my company develops is designed to be cross-platform. Built on web technologies, we are able to support Android, iOS, PC, Mac, or nearly any other system that runs a proper web browser.
A couple weeks go by, the sale is finalized, the contract ink is dry, and the project kicks off. Now our integration and development teams start to encounter hurdles.
“We don’t support Android”
“Our entire enterprise is required to use Internet Explorer”
“We already have a support contract with Dell”
“We plan to use Windows Mobile handhelds we purchased 5 years ago”
“Our users are allowed and encouraged to use their own mobile devices”
Luckily, these types of problems are where web technologies really shine. “OK, no problem. We ensure you that our application with all desired integrations work well on whatever platform you choose.” Making that promise a reality is where I find a lot of enjoyment in my job.
Out of all of our active projects, Windows is probably the least requested platform. However, we still do our best to make sure all of the features our sales team advertised on Android and iOS devices are available on Windows.
To make it happen, it’s really hard to avoid .NET
The hurdle that spawned the creation of this article is related to GPS and location services on Windows. Modern browsers already include a location service, and they work pretty well. But, the location API built into desktop browsers turned out to be very poor for a few of our customers.
Most location services work by looking up the registered location of your IP address or by calculating your location based off of nearby wireless access points (yes, the location of your home wifi is part of a giant database). To do these lookups, your pc is required to have an active internet connection.
Our product is designed to work just as well with and without an internet connection, so for these customers we had to find a way to make device location available to browsers without requiring an internet connection. To the surprise of no-one, browsers do not readily fetch information from hardware GPS chips/dongles. We had to create our own solution to bridge the gap between GPS hardware and the browser.
Luckily for us, Microsoft had already done a lot of the work. Windows includes an OS level location API that many GPS devices happily register themselves with. All we had to was access it and make it available to the browser.
We decided early that creating browser plug-ins and extensions was an unacceptable solution. None of us felt like, or have the time, to maintain extensions for each of the major browsers. Nor was there any common API to directly access arbitrary system information from Windows (any technology like that would pose a huge security risk).
The solution we created out of necessity ended up being a solution we could repeat across many use cases.
We use .NET to fetch any information from Windows that we desire (Device Location in this case). We then use use .NET to create a Windows Web Service to expose that information over HTTP. Browsers can make xhr requests to this web service on localhost and receive the location data as a JSON string.
Pretty clever. We had now made nearly any Windows information available to the browser and we gladly offered the software we created to the public. https://github.com/DataSplice/locatinator
The “locatinator” worked for us for a number of years until recently Google Chrome threw us a curve-ball.
Google Chrome is really doing the world a favor by enforcing security, but this particular security feature caused us some temporary headache.
First, Chrome started enforcing HTTPS security if your website/app wanted access to the device camera/fileupload api. Then they added the same enforcement for access to device location. In response, we started encouraging our customers to switch to HTTPS, either in the form of self-signed certificates within our server software, or by using secure reverse-proxies with SSL certificates provided by trusted Certificate Authorities.
Secondly, Chrome started enforcing that any site served with HTTPS can only access other sites served by HTTPS. This became a problem for our locatinator.
Our web service had always been hosted without HTTPS and we didn’t have a mechanism for securing it. From then on, HTTPS secured customer sites could no longer make requests to our GPS web service.
I took it upon myself to re-vamp our Locatinator.
Our lead developer recommended that I look into a technology called EdgeJS. http://tjanczuk.github.io/edge/
Every person in our development team loves to stay up-to-date with the latest technology and programming concepts. EdgeJS was something our lead developer had read about but didn’t have the time to research. Having set aside the time to do so, I was able to read up on it and run through a couple of example programs. Turns out that it’s pretty slick.
Or, you can integrate with existing .NET dll libraries by calling their methods directly.
As the example above states, the .NET method must be a Function that takes any object as input and outputs a Task that provides a resulting object. This lets Node.JS execute .NET methods asynchronously.
I quickly realized that using EdgeJS is going to take care of two of our problems. EdgeJS will allow us to integrate our .NET with NW.JS without a web service, which makes our NW.JS client an attractive option for customers. To support browsers, EdgeJS will also allow us to implement our web service with Node.JS instead of C# (Setting up HTTPS on Node.JS web servers is incredibly easy).
Before starting to integrate with NW.JS, I wanted to focus on the locatinator web service first.
All of the code for this project is temporarily located at https://github.com/WebeWizard/ds-webservice
lib folder you will find the .NET code that compiles to a dll.
Most of the .NET class is just standard code, but for convenience I created a wrapper to make the class EdgeJS friendly.
EdgeGeoProvider takes the normal locatinator class and creates a new instance of it. Without this “provider”, we wouldn’t be able to maintain state within an instance of the locatinator object.
I won’t post the coffeescript code here, but if you look at the Github project, you can find the code primarily in
locatinator.coffee contains the integration with EdgeJS that gets ahold of the .NET provider and allows us to make calls to the provider’s methods.
providers.coffee is responsible for initializing providers and adding their sub-routes to the server route map.
server.coffee provides the Node.JS web server and serves data requested by routes.
Routes like ‘\gps\location’ are added to a route map by
providers.coffee. In this case, ‘gps’ refers to the locatinator provider, and ‘location’ refers to a sub-route within that provider that serves location data.
I decided not to use Gulp to manage builds on this project. It’s all for Windows, so there is no need to support cross-platform building and distribution. Instead I am using windows .bat files to compile the C# code, CoffeeScript code, and make a release folder.
No real hurdles here except file size. I can’t expect our customers to have a Node.JS runtime installed on their devices so I have to include one. The executable for Node.JS is about 13MB. The dependency on EdgeJS was massive, around 40MB. Digging in the EdgeJS folders I saw that a lot of the size due to edgejs including all of the different cross-platform binaries by default. Since I am only targeting Win32 and a specific version of Node, I was able to remove most of the cross-platform files from my release folder. All together the release is about 26MB and zips down to 19MB. That still seems large for just the locatinator, but as we add more types of providers to the web service, it won’t seem so bad.
I also distribute a self-signed certificate so Node.JS can provide an HTTPS secured server, which solves our Chrome problems.
I’m pretty proud of myself for this one. The EdgeJS friendly .NET dlls that provide Windows data to the web service are now also available to our NW.JS client, where integration should be easy.
There is still a bit of work to be done, but mostly it’s on the node.js server side. EdgeJS took all of the hard work out of integrating with Windows.
Thanks for reading!
Note that a “Combination” is a group of values where order of the values does not matter. Ex: ‘123’
We are NOT computing a set of “Permutations”. Ex: ‘123’ and ‘213’ and ‘321’ etc.
So, for example, we want to compute the set of combinations for the values 1,2,3 we can easily list them out by hand.
1, 12, 13, 14, 123, 124, 134, 1234, 2, 23, 24, 234, 3, 34, 4
There are 2^(n)-1 or 15 total combinations. Easy enough right?
What about values 1 to 5? That’s 31 combinations.
what about values 1 to 999? I’d spend the rest of my lifetime writing out that list.
We know we need a loop for the most significant digit… and going deeper, we assume we need another loop for the second most significant digit… deeper still means more loops… MOOAARR LOOPS.
Writing 999 loops is definitely easier than writing out each combination by hand, but I still don’t want to write out 999 loops.
If we were only computing a single value result, we might think about solving this problem mathematically and avoid loops altogether. But instead, we need to record a combination at each step of the process.
The technique for solving these types of “loops on loops on loops” problems is called “Recursion”.
What recursion in programming looks like is a function, that during its execution, calls itself.
We can use a recursive function to perform our loops within loops within loops and record a combination at each step.
Let’s start our program by defining our
end values from the first example above.
We’ll also create a Vec that will hold our result.
For the meat and potatoes of our program, we need a loop that serves the purpose of “given a number, calculate all combinations of values >= this number”. Ex: Given 1, calculate 1, 12, 123, 1234, 13, etc.
Inside of the loop, we’ll put our recursive function… the recursive function… the recursive…
Since each call to the recursive function needs to know the part of the problem it’s supposed to work on, we need to give it the current position of the overall problem. We’ll call it
pos for position. Ex.
pos of ‘2’ will work on 2,23,234,24
We also need to keep track of the history of numbers that came before our recursive function call. We’ll call that history
pos is ‘3’, then
prefix could be ‘1’ or ‘12’ or ‘2’.
We need to know how many times we need to repeat the inner loops ( current position to the end), so we’ll keep passing the
end variable we created earlier.
Finally, we need a place to record our results from each step. We’ll pass a reference to our mutable
collections vector along as well.
The code for the recursive function ends up looking like this:
The result comes out just as we wanted. By printing the Collection we see it contains all combinations for the values 1 to 4.
Recursive functions are great for solving these types of problems.
Because we retain and build data at each step of the recursion, we quickly consume a large amount of memory as the value of
Create a shell script to execute the Hexo server.
The contents can be as simple as the following:
Make the script executable.
Edit your user’s crontab file to start Hexo on boot.
Add the following line to the bottom of your crontab file.
Remember that time I tried to run a wordpress site and GoDaddy locked me out of my own database over and over? Good times… Such fun…
This time we’re doing it ourselves. DigitalOcean hosted server, nodejs, Hexo blogging engine, and git. No databases, no bloated webserver. Just my thoughts, written in markdown, and a command line.
And because googling for “hexo startup at boot” apparently returns bollocks… I suppose that will be my first post. Thank you Hexo. You’re welcome Hexo community.