Tuesday, September 15, 2015

Disable F1 Windows Help and Support on Windows 8.1

One of the most useless things built into windows is the F1 help, unfortunately Microsoft doesn't make it easy to disable. I think I can say that I may have found the F1 help useful once, and that is probably pretty generous.

Below is a Powershell script which will disable the F1 help in windows. Basically, it takes control over helppane.exe and then renames it. Thankfully, if windows can't find the file, it will not through an error. If you want to restore the F1 help, just rename the executable back.
takeown /f c:\windows\helppane.exe
$acl = Get-Acl "C:\Windows\HelpPane.exe"
$rule = New-Object  System.Security.AccessControl.FileSystemAccessRule("$([Environment]::UserDomainName)\$([Environment]::UserName)","FullControl","Allow")
$acl.SetAccessRule($rule)
Set-Acl "C:\Windows\HelpPane.exe" $acl
Rename-Item "C:\Windows\HelpPane.exe" "C:\Windows\HelpPane1.exe"
This may work on other versions of windows, but I have only tested this on Windows 8.1.

Thursday, September 3, 2015

Powershell Open A Windows Explorer Window And Select A File

Just a quick useful function that I have used a couple times and always forget about. If you have a script that persists a file to disk, you can open a Windows Explorer window and select the file with this function. This can be useful in desktop applications as well. I'll leave it to the reader to translate it to C# (it leverages straight-up .Net functions already).
function Show-InExplorer($file) {
 $explorerArgs = "/select, $file";
 [System.Diagnostics.Process]::Start("explorer.exe", $explorerArgs) | Out-Null;
}
NOTE: Dispite what people have said on several StackOverflow posts, I found that I had to have the comma after the /select.

Thursday, August 27, 2015

GNU Screen Awesomeness

Introduction

I have been using GNU Screen for a LONG time; it usually comes by default with every *nix distribution that I have used. It is one of my favorite tools in my *nix toolbox. Basically it allows you to multiplex your SSH session allowing the ability to switch between full screen shell windows. I recently worked on a project which used Linux and utilized the tool pretty heavily. I thought everyone knew about Screen, except my fellow developer had never heard of it, so I figured this topic would be great to share.

Basically, I can have screens for GNU Midnight Commander, MySQL REPL (sometimes I create a tunnel and use Workbench, but I don't always have access to it), my source directory, and a configuration directory. This allows me to quickly switch between different tasks/locations without having to do a lot of heavy lifting or have multiple SSH connections or change directories a lot.

This is all well and great, but it comes with another great benefit. If you are disconnected for some reason, screen will keep everything waiting for your return. You can also suspend your screen session via a keyboard shortcut and resume it just the same.

Let's get started.

Getting Started With Screen

It is really easy to start screen:
$ screen
You are in!
NOTE: The keyboard shortcuts all require the Control key, it is usually abbreviated with Ctrl, but the below will use "C-" because that is how Screen's help specifies.
Now you have a LOT of shortcuts, but below are the most basic and useful:

Create new window
C-a, c
View Windows
C-a, w
Switch to Window
C-a, # (index of the window)
Disconnecting/Detatching
C-a, d

Now, A Bit More Advanced

Name Your Session
C-a :sessionname bars
Let's test this out, create a named session.
screen -S sessionname
Enter some commands at the new prompt. And then press
C-a, d
Now you should be back where you were before you started Screen. Even if you were you were running Midnight Commander (or anything else). Now let's jump back into the session.
screen -r sessionname
That is it. So easy. Use it!

Friday, August 21, 2015

Azure Resource Manager Templates, The Missing Parts

Azure Resource Manager (ARM) is a fantastic addition to the Azure ecosystem. The fact that you can create a template for your environment is all the better. Basically, it allows you to describe all of the resources you need in an environment and have an amazing amount of configuration.

ARM templates are merely JSON files that use JSONSchema. Visual Studio gives you validation and lets you know if you reference something that is not known. The support is nice, but there are several things that do not validate, but work against Azure regardless.

A good place to start looking for template examples is the Azure GitHub repo azure-quickstart-templates. There are many examples, but from a development standpoint, good examples putting them all together are difficult to come by.

All is not rainbows and butterflies, there are limitations. To list a few:
  • If you require a GUI, you will be greatly dismayed by the offering in Visual Studio. It is extremely simplistic and you will quickly out grow it. There is, however, a very nice JSON Outline pane which will help you navigate the JSON file.
  • Database servers cannot be shared across Resource Groups.
  • Does not handle Cloud Services (Web/Worker Roles)
  • Does not handle Service Bus namespaces
  • There are a number of other services that are not supported on the new portal and not in the Resource Manager.
I am sure that in the coming months the unhandled services will be supported. It is possible to get around the these limitations via Powershell, but you don't don't get the template deployment goodness.

Build your connection strings

Assuming you are describing an Azure Web App, you can configure the configuration connectionstrings. You can build them based on other resources described in the template.
Here are examples of the ones I have been able to find:
"DefaultConnection": {
    "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', parameters('databaseName'), ';User Id=', parameters('administratorLogin'), '@', parameters('serverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
    "type": "SQLAzure"
},
"variables": {
    "storageAccountId": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/','Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]",
...
"AzureWebJobsDashboard": {
    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]",
    "type": "custom"
},
So this next one is a bit cheating, but it is presently the only way to make it happen (for now). I will dive more into this later.
"AzureWebJobsServiceBus": {
    "value": "[parameters('serviceBusConnectionString')]",
    "type": "custom"
},
"WebDocDb": {
    "value": "[concat('AccountEndpoint=', reference(concat('Microsoft.DocumentDb/databaseAccounts/', parameters('databaseName'))).documentEndpoint, ';AccountKey=', listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('databaseName')), '2015-04-08').primaryMasterKey, ';')]",
    "type": "custom"
},
"RedisCache": {
    "value": "[listKeys(resourceId('Microsoft.Cache/Redis', parameters('redisName')), '2014-04-01').primaryKey]",
    "type": "custom"
}

Web App With Staging Slot

Here is a good example of how to create a web application with a staging slot both containing the correct connection strings.
"variables": {
    "siteNameStage": "[concat(parameters('siteName'),'stage')]",
    "databaseNameStage": "[concat(parameters('databaseName'),'stage')]",

    "storageAccountId": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/','Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]",
    "storageAccountIdStage": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountNameStage'))]",

    "storageAccountNameStage": "[concat(parameters('storageAccountName'),'stage')]"
},
"resources": [

...

    /*** Web App ***/
    {
      "apiVersion": "2015-06-01",
      "name": "[parameters('siteName')]",
      "type": "Microsoft.Web/Sites",
      "location": "[parameters('siteLocation')]",
      "dependsOn": [ "[concat('Microsoft.Web/serverFarms/', parameters('hostingPlanName'))]" ],
      "tags": {
        "[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "empty"
      },
      "properties": {
        "name": "[parameters('siteName')]",
        "serverFarmId": "[parameters('hostingPlanName')]"
      },
      "resources": [
        {
          "apiVersion": "2014-11-01",
          "type": "config",
          "name": "connectionstrings",
          "dependsOn": [
            "[concat('Microsoft.Web/Sites/', parameters('siteName'))]",
            "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]",
            "[resourceId('Microsoft.Cache/Redis', parameters('redisName'))]"
          ],
          "properties": {
            "DefaultConnection": {
              "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', parameters('databaseName'), ';User Id=', parameters('administratorLogin'), '@', parameters('serverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
              "type": "SQLAzure"
            },
            "AzureWebJobsDashboard": {
              "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]",
              "type": "custom"
            },
            "AzureWebJobsStorage": {
              "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]",
              "type": "custom"
            },
            "AzureWebJobsServiceBus": {
              "value": "[parameters('serviceBusConnectionString')]",
              "type": "custom"
            },
            "WebDocDb": {
              "value": "[concat('AccountEndpoint=', reference(concat('Microsoft.DocumentDb/databaseAccounts/', parameters('databaseName'))).documentEndpoint, ';AccountKey=', listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('databaseName')), '2015-04-08').primaryMasterKey, ';')]",
              "type": "custom"
            },
            "RedisCache": {
              "value": "[listKeys(resourceId('Microsoft.Cache/Redis', parameters('redisName')), '2014-04-01').primaryKey]",
              "type": "custom"
            }
          }
        },
        {
          "apiVersion": "2015-04-01",
          "name": "appsettings",
          "type": "config",
          "dependsOn": [
            "[concat('Microsoft.Web/Sites/', parameters('siteName'))]"
          ],
          "properties": {
            "Demo:Environment": "PROD",
            "Test:Environment": ""
          }
        },
        {
          "apiVersion": "2014-11-01",
          "name": "slotconfignames",
          "type": "config",
          "dependsOn": [
            "[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
          ],
          "properties": {
            "connectionStringNames": [ "DefaultConnection", "AzureWebJobsDashboard", "AzureWebJobsStorage", "AzureWebJobsServiceBus", "WebDocDb", "RedisCache" ],
            "appSettingNames": [ "Demo:Environment", "Test:Environment" ]
          }
        },
    
        /*** Web App STAGING SLOT ***/
        {
          "apiVersion": "2015-04-01",
          "name": "Staging",
          "type": "slots",
          "location": "[parameters('siteLocation')]",
          "dependsOn": [
            "[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
          ],
          "properties": {
          },
          "resources": [
            {
              "apiVersion": "2014-11-01",
              "type": "config",
              "name": "connectionstrings",
              "dependsOn": [
                "[resourceId('Microsoft.Web/Sites/slots', parameters('siteName'), 'Staging')]",
                "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]",
                "[resourceId('Microsoft.Cache/Redis', parameters('redisName'))]"
              ],
              "properties": {
                "DefaultConnection": {
                  "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('databaseNameStage'), ';User Id=', parameters('administratorLogin'), '@', parameters('serverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
                  "type": "SQLAzure"
                },
                "AzureWebJobsDashboard": {
                  "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountNameStage'), ';AccountKey=', listKeys(variables('storageAccountIdStage'),'2015-05-01-preview').key1)]",
                  "type": "custom"
                },
                "AzureWebJobsStorage": {
                  "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountNameStage'), ';AccountKey=', listKeys(variables('storageAccountIdStage'),'2015-05-01-preview').key1)]",
                  "type": "custom"
                },
                "AzureWebJobsServiceBus": {
                  "value": "[parameters('serviceBusConnectionStringStage')]",
                  "type": "custom"
                },
                "WebDocDb": {
                  "value": "[concat('AccountEndpoint=', reference(concat('Microsoft.DocumentDb/databaseAccounts/', variables('databaseNameStage'))).documentEndpoint, ';AccountKey=', listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', variables('databaseNameStage')), '2015-04-08').primaryMasterKey, ';')]",
                  "type": "custom"
                },
                "RedisCache": {
                  "value": "[listKeys(resourceId('Microsoft.Cache/Redis', parameters('redisName')), '2014-04-01').primaryKey]",
                  "type": "custom"
                }
              }
            },
            {
              "apiVersion": "2015-04-01",
              "name": "appsettings",
              "type": "config",
              "dependsOn": [
                "[resourceId('Microsoft.Web/Sites/slots', parameters('siteName'), 'Staging')]"
              ],
              "properties": {
                "Demo:Environment": "TEST",
                "Test:Environment": "TEST"
              }
            }
          ]
        }
      ]
    },

...

That is a lot of JSON, but very useful.

Service Buses

Services buses don't seem to be receiving the love that other Azure resources have received, but it doesn't make them any less useful.

The trick to using/maintaining Service Buses is to not use the Resource Manager template. Basically, you can use a Powershell script to create the Service Bus(es), grab the connection string(s), and then pass the connection string into the ARM template deployment as a parameter.
function Create-AzureServiceBusQueue($Namespace, $Location) {
 # Query to see if the namespace currently exists
 $CurrentNamespace = Get-AzureSBNamespace -Name $Namespace;

 # Check if the namespace already exists or needs to be created
 if ($CurrentNamespace)
 {
  Write-Host "The namespace [$Namespace] already exists in the [$($CurrentNamespace.Region)] region.";
 }
 else
 {
  Write-Host "The [$Namespace] namespace does not exist.";
  Write-Host "Creating the [$Namespace] namespace in the [$Location] region...";
  New-AzureSBNamespace -Name $Namespace -Location $Location -CreateACSNamespace $false -NamespaceType Messaging;
  $CurrentNamespace = Get-AzureSBNamespace -Name $Namespace;
  Write-Host "The [$Namespace] namespace in the [$Location] region has been successfully created.";
 }
 return $CurrentNamespace.ConnectionString;
}
You may want to dig a little deeper and this page MSDN page, Use PowerShell to manage Service Bus and Event Hubs resources, is pretty useful.

Putting It Together

With the web application resource section in a template and the Service Bus(es) created via Powershell, how do we deploy the template to put it together?
# Create the Services Buses
$serviceBusConnectionStrings = @{"Prod"=$(Create-AzureServiceBusQueue $ServiceBusName $ResourceGroupLocation);
     "Stage"=$(Create-AzureServiceBusQueue "$($ServiceBusName)stage" $ResourceGroupLocation);
     "Dev"=$(Create-AzureServiceBusQueue "$($ServiceBusName)dev" $ResourceGroupLocation);}

...

$rg = Get-AzureResourceGroup | ? { $_.ResourceGroupName -eq $ResourceGroupName };
if ($rg -eq $null) {
 # Create the Resource Group
 New-AzureResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation;
}
# Start a Resource Group deployment
$results = New-AzureResourceGroupDeployment `
  -Name WebAppDeployment `
  -ResourceGroupName $ResourceGroupName `
  -TemplateFile $TemplateFile `
  -TemplateParameterFile $TemplateParameterFile `
  -storageAccountNameFromTemplate $DefaultStorage `
  -serviceBusConnectionString $($serviceBusConnectionStrings.Prod) `
  -serviceBusConnectionStringStage $($serviceBusConnectionStrings.Stage);
Write-Output $results;
Write-Output "ServiceBus Prod: $($serviceBusConnectionStrings.Prod)";
Write-Output "ServiceBus Stage: $($serviceBusConnectionStrings.Stage)";
Write-Output "ServiceBus Dev: $($serviceBusConnectionStrings.Dev)";
This will configure the web app and populate the correct connection strings on the correct slot. Hopefully, Microsoft will add the capability to maintain Cloud Services and Service Buses soon, but until then, this will be helpful.

Monday, August 17, 2015

A Couple AutoHotKey Windows 10 Helpers

With Windows 10 comes a bunch of new features and shortcuts. I have long been a fan of VirtuaWin, it's context menu driven virtual desktop paradigm is a bit of a hurdle, but it is easy to get used to. Windows 10 brings the concept of virtual desktops to the masses. It is pretty simplistic and has much room for improvement, but probably a good starting point.

Here are a couple tweaks that make navigating multiple desktop with your mouse.
; Show Task View, Wheel/Middle click on desktop
#IfWinActive ahk_class Progman
MButton::sendevent {LWin down}{Tab down}{Tab up}{Lwin up}
Return
#IfWinActive

; Move to the desktop left of the current desktop
$WheelLeft::send ^#{Left}

; Move to the desktop right of the current desktop
$WheelRight::send ^#{Right}

Friday, August 7, 2015

R Create Data.Frame Like Read.Csv

In exploring using R.NET and RserveLink inside of C#, I ran into a couple performance issues with my scenario. In load balanced environments which will need to pull the random forests and the cached CSV data saving the files to a network share makes sense, but there is a cost. My initial process was:
  1. In C#, load and prep the data.
  2. Serialize the data into CSV format and save to a network share.
  3. Use R.NET or RServeLink, send the below commands to pull the Random Forest and the CSV data and run the data through the Random Forest.
Below is the proof of concept R code.
library("randomForest")
library("caret")

mydata = read.csv(file="IntPonAllTheData.csv",head=TRUE,row.names="IntPonID")

test.predict <- predict(readRDS('//intponsrv/Data/RandomForest/CLASS123.rf'), mydata)
write.table(test.predict)
I was able to combine several of the lines, but it didn't improve the performance very much. However, if I could remove 2 of the network and file I/O trips, that would greatly improve the performance. The only question was, how do I create a data.frame in R that would produce the same object as read.csv. I inquired to the #R freenode channel (they are awesome, check them out and stay a while) and they suggested that I look into the save function or dputs function. I was able to use dputs and serialize the data.frame. The format of the serialization wasn't an exact match, but it was close enough that I could figure out how the data.frame is structured relative to the CSV data. The following is my converted code which generates a data.frame directly.
library("randomForest")
library("caret")

df <- data.frame(Q1 = c(0.301775147928994,0.301775147928994,0.301775147928994,0.301775147928994),Q2 = c(0.301775147928994,0.301775147928994,0.301775147928994,0.301775147928994),Q2 = c(0.094674556213018,0.094674556213018,0.094674556213018,0.094674556213018),Q3 = c(0.301775147928994,0.301775147928994,0.301775147928994,0.301775147928994),Q4 = c(0.082840236686391,0.082840236686391,0.082840236686391,0.082840236686391),row.names = c("baseline","TEST1","TEST2","TEST3"))
write.table(df)

test.predict <- predict(readRDS('//intponsrv/Data/RandomForest/CLASS123.rf'), df)
write.table(test.predict)
Instead of generating the CSV, I can generate the data.frame statement with the same result. After integrating it with my C# code, this produced a 60-80% improvement in processing time per prediction, when repeatedly processing large data sets.

Friday, July 24, 2015

RserveLink Eval Failed Even When Successful

I have been playing with RserveLink and Rserve recently and found that it worked very well, except in one case (which is not really a fringe case) where it reliably returns an "Eval Failed" exception when the command actually succeeded. I was able to run the command in RStudio (Awesome R IDE) and RGUI successfully.

I am not going to include the R statement that generated the issue because it is large, but suffice it to say that it reliably works with much larger statements.

The response we get for the 4th index is 0 and the library jumps over the if statement. However, dragging the debug arrow onto the DataLength line and run the code, it continues without error.
if (response[4] != 0)
{
    Int32 DataLength = BitConverter.ToInt32(response, 4);
I changed the section of code converting the code to the following. Essentially, just getting the response data length and assume that a data length greater than 0 is successful.
Int32 DataLength = BitConverter.ToInt32(response, 4);
if (DataLength != 0)
{
The original code was posted in a zip file on SourceForge and posted back in 2007. I have emailed the author (awaiting reply) and posted my change on my RserveLink GitHub repository. The binary library targeting 4.0 Client and 4.5.1 can be found in the releases section.

I have also published an RserveLink Nuget package for ease of adding to .Net projects.

Saturday, July 11, 2015

AngularJS UTC to Local Time Filter

In a previous post I detailed how to to implement the UTC time to local time conversion in Vanilla JS. Now let's take it a step further and utilize it in an AngularJS application. The best path forward will be to create a filter which will format the string being rendered. The end result will allow us to do something like the following:
<div class="row" ng-repeat="time in viewModel.times">
  <div class="col-md-6">
    <time datetime="{{time}}">{{ time | utctolocal }}</time>
  </div>
</div>
Basic usage is thus: create the filter, add the script tag to load the filter, add the module to be a dependency on the app.
angular.module('intPonfilters', [])
 .filter('utctolocal', function () {

 var LeadingZero = function (val) {
  return (val < 10) ? "0" + val : val;
 },
 ToDateString = function (dateObj, dateFormat) {
  var curr_year = dateObj.getFullYear(),
   curr_month = LeadingZero(dateObj.getMonth() + 1),
   curr_date = LeadingZero(dateObj.getDate()),
   curr_hour = LeadingZero(dateObj.getHours()),
   curr_min = LeadingZero(dateObj.getMinutes()),
   curr_sec = LeadingZero(dateObj.getSeconds()),
   curr_ampm = "AM";
  if (curr_hour > 11) {
   curr_ampm = "PM";
   curr_hour = (curr_hour == 12) ? 12 : curr_hour - 12;
  }
    var timestamp = curr_year + "-" + curr_month + "-" + curr_date + " " + curr_hour + ":" + curr_min + ":" + curr_sec + " " + curr_ampm + " " + LocalTimeZone();
  return timestamp;
 },
  LocalTimeZone = function() {
    // From http://stackoverflow.com/questions/2897478/get-client-timezone-not-gmt-offset-amount-in-js
    var now = new Date().toString(),
        timezone = now.indexOf('(') > -1 ?
          //now.match(/\([^\)]+\)/)[0] :  // Uncomment this line to return the full time zone text
          now.match(/\([^\)]+\)/)[0].match(/[A-Z]/g).join('') :  // Uncomment this line to return the full time zone abbreviation
          now.match(/[A-Z]{3,4}/)[0];
    if (timezone == "GMT" && /(GMT\W*\d{4})/.test(now))
      timezone = RegExp.$1;
    return timezone;
  };

 return function (input) {
  var inputDate = new Date(input);
  var dateString = ToDateString(inputDate);
  return dateString;
 };
});


An example can be found in my UTCtoLocalAngularJS GitHub repository.

Saturday, July 4, 2015

Javascript UTC to Local Time for Display

If you are developing an application which will only be used by a people in one timezone, then DateTime.Now with the current time zone will work for you. This is a rather short sighted. As the userbase grows, users will have to translate the dates manually. Additionally, if you have migrate the application to servers in different locations which have a different time zone set or a time zone that you can't control, the date and times generated will be off. This is especially true when developing applications for the cloud (which by and large use UTC).

There are a couple options:
  1. Have a setting per users which indicates the users timezone and convert the times on every view/page render
  2. Have the user's browser handle the conversion

The former requires significantly more development, user interaction, and more processing time. The latter requires a bit of HTML5 and javascript. So let's see what it takes to do it in javascript. There are javascript libraries like Moment.js which do this with potentially more robustness, but it is more than 12KB minified and gzipped. If it can be done in 1-2KB's, why tote the rest around. When page load times are so important, every kilobyte saved is time spent loading your page. Lets say we want to render the following render the following HTML to the browser.
<time datetime="@Html.DisplayFor(modelItem => item.Created) UTC">
 @Html.DisplayFor(modelItem => item.Created) UTC
</time>
We can iterate over all of the time elements and convert the UTC times and leverage javascript to translate the times to local with the following code.
function UtcTimesToLocal() {
 $("time").each(function (index, element) {
  var el = $(element),
   time = el.attr("datetime"),
   converted = new Date(time);
  var dateString = ToDateString(converted);
  el.text(dateString);
 });
}

function ToDateString(dateObj, dateFormat) {
 var curr_year = dateObj.getFullYear(),
  curr_month = LeadingZero(dateObj.getMonth() + 1),
  curr_date = LeadingZero(dateObj.getDate()),
  curr_hour = LeadingZero(dateObj.getHours()),
  curr_min = LeadingZero(dateObj.getMinutes()),
  curr_sec = LeadingZero(dateObj.getSeconds()),
  curr_ampm = "AM";
 if (curr_hour > 11) {
  curr_ampm = "PM";
  curr_hour = (curr_hour == 12) ? 12 : curr_hour - 12;
 }
 var timestamp = curr_year + "-" + curr_month + "-" + curr_date + " " + curr_hour + ":" + curr_min + ":" + curr_sec + " " + curr_ampm + " " + LocalTimeZone();
 return timestamp;
}

function LeadingZero(val) {
 return (val < 10) ? "0" + val : val;
}

function LocalTimeZone () {
  // From http://stackoverflow.com/questions/2897478/get-client-timezone-not-gmt-offset-amount-in-js
  var now = new Date().toString(),
      timezone = now.indexOf('(') > -1 ?
        //now.match(/\([^\)]+\)/)[0] :  // Uncomment this line to return the full time zone text
        now.match(/\([^\)]+\)/)[0].match(/[A-Z]/g).join('') :  // Uncomment this line to return the full time zone abbreviation
        now.match(/[A-Z]{3,4}/)[0];
  if (timezone == "GMT" && /(GMT\W*\d{4})/.test(now))
    timezone = RegExp.$1;
  return timezone;
}
Then at the bottom of the page, run the UtcTimesToLocal function.
<script>
 $(function() { UtcTimesToLocal(); });
</script>
An example project can be found on my UTCtoLocalJS GitHub repository.

Tuesday, December 23, 2014

Javascript Client Side File Size Validation

When you attempt to upload a file that is larger than the web server will accept, it just stops processing. It might be OK, but you don't have a way to be notified. It would be nice to be able to do have something like the following code snippet.
$("#editDialog form").submit(function( event ) {
    return validateFileSize('profile_image', 1024*1024*2, 'Profile Image', event);
});
The solution is very simple with the HTML5 file reader functionality. We can add some JavaScript to run before we attempt to send the bad files. The following achieves the validation needed.
function validateFileSize(id, limit, label, event) {
    if (typeof FileReader !== "undefined" && document.getElementById(id).files.length > 0) {
        var size = document.getElementById(id).files[0].size;
        if (size > limit) {
            alert(label + ' is too large.  The file must be less than ' + formatSize(limit) + '.');
            event.preventDefault();
            return false;
        }
    }
    return true;
}
I am utilizing my JavaScript function from my previous post JavaScript Format File Size Truncate Decimals. This allows me to format the file size very nicely.
function formatSize(bytes, decimals) {
    if (!!!bytes) return 'n/a';
    var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'],
        i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))),
        decMult = Math.pow(10, decimals || 2);
    return (Math.round((bytes / Math.pow(1024, i)) * decMult)) / decMult + ' ' + sizes[i];
}

Friday, December 19, 2014

Checking For Network Reachabilty In Xamarin

Just ran into this little gem. Everything that I found on how to detect network reachability in says that the following code should be used.
await Network.IsReachable(url, new TimeSpan(NetworkTimeout))
This worked on every iOS device I could get, except the most important device - the client's. It works on iPhone 4s, 5, and 5s, also it worked on my iPad, but not the client's iPhone 5. After much research and frustration, I started diving into the Network.InternetConnectionStatus() function to see if that would be fruitful. I tried the following:
return !Network.InternetConnectionStatus().HasFlag(NetworkStatus.NotReachable);
which naturally (for Xamarin) it is not reliable. I ended up trying the following setup, which seemed to work for on my devices.
var networkstatus = Network.InternetConnectionStatus();
return 
    networkstatus.HasFlag(NetworkStatus.ReachableViaWiFiNetwork) || 
    networkstatus.HasFlag(NetworkStatus.ReachableViaCarrierDataNetwork);
After pushing the build out to the client, he was able to log in. This way has some downsides, as it doesn't check to see if you can actually reach the site you want, but at least you can detect if there is network connectivity.

I would love to submit a bug, but I am not sure how to reliably recreate the issue. It is little things like this that do not build my confidence in Xamarin.

Wednesday, December 17, 2014

Xamarin Forms Non-Native CheckBox

Having experience developing iOS applications, I know that there is no "check box" per say. When I searched for a Xamarin Forms built in check box and was left with only an native implementation, this would have been acceptable, except that they were causing some significant performance issues/lag when a view containing the controls would be added to the navigation stack.

In my last couple posts, I dove into creating non-native controls in Xamarin Forms. I can build on that knowledge to build a Xamarin Forms checkbox hopefully improve performance. This definitely renders a lot faster.
<localcontrol:CheckBoxView Checked="{Binding SomeBooleanProperty}" DefaultText="Check Box Text" ReadOnly="true" HorizontalOptions="FillAndExpand" TextColor="#000000" FontSize="12" />
The source code...
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       x:Class="IntPonApp.Controls.CheckBoxView">

 <StackLayout x:Name="CheckBoxStack" Orientation="Horizontal">
  <StackLayout.GestureRecognizers>
   <TapGestureRecognizer 
      Command="{Binding CheckCommand}"
      CommandParameter="#" />
  </StackLayout.GestureRecognizers>
  <Image x:Name="boxImage" 
      Source="{Binding BoxImageSource}" />
  <Label x:Name="textLabel" 
      Text="{Binding Text}" 
      LineBreakMode="WordWrap" 
      XAlign="Center" 
      HorizontalOptions="StartAndExpand" 
      VerticalOptions="Center" 
      TextColor="{Binding TextColor}" 
      Font="{Binding Font}" />
 </StackLayout>
 
</ContentView>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Labs;
using CustomControls;
using System.Diagnostics;
using System.Windows.Input;

namespace Check123Mobile.Controls
{
    public partial class CheckBoxView
    {
        #region Properties

        /// <summary>
        /// The width request in inches property.
        /// </summary>
        public static readonly BindableProperty CheckedProperty =
            BindableProperty.Create<CheckBoxView, bool>(
                p => p.Checked, false
                , propertyChanged: new BindableProperty.BindingPropertyChangedDelegate<bool>(
                    (BindableObject obj, bool oldPlaceHolderValue, bool newPlaceHolderValue) =>
                    {
                        var cbv = (CheckBoxView)obj;
                        cbv.BoxImageSource = cbv.GetCheckBoxImageSource();
                    })
                );

        protected static readonly BindableProperty BoxImageSourceProperty =
            BindableProperty.Create<CheckBoxView, ImageSource>(
                p => p.BoxImageSource, null);

        /// <summary>
        /// The read only property.
        /// </summary>
        public static readonly BindableProperty ReadOnlyProperty =
            BindableProperty.Create<CheckBoxView, bool>(
                p => p.ReadOnly, false);

        /// <summary>
        /// The checked text property.
        /// </summary>
        public static readonly BindableProperty CheckedTextProperty =
            BindableProperty.Create<CheckBoxView, string>(
                p => p.CheckedText, string.Empty);

        /// <summary>
        /// The unchecked text property.
        /// </summary>
        public static readonly BindableProperty UncheckedTextProperty =
            BindableProperty.Create<CheckBoxView, string>(
                p => p.UncheckedText, string.Empty);

        /// <summary>
        /// The checked image property.
        /// </summary>
        public static readonly BindableProperty CheckedImageProperty =
            BindableProperty.Create<CheckBoxView, string>(
                p => p.CheckedImage, string.Empty);

        /// <summary>
        /// The unchecked image property.
        /// </summary>
        public static readonly BindableProperty UncheckedImageProperty =
            BindableProperty.Create<CheckBoxView, string>(
                p => p.UncheckedImage, string.Empty);

        /// <summary>
        /// The default text property.
        /// </summary>
        public static readonly BindableProperty DefaultTextProperty =
            BindableProperty.Create<CheckBoxView, string>(
                p => p.Text, string.Empty);

        /// <summary>
        /// Identifies the TextColor bindable property.
        /// </summary>
        /// 
        /// <remarks/>
        public static readonly BindableProperty TextColorProperty =
            BindableProperty.Create<CheckBoxView, Color>(
                p => p.TextColor, Color.Black);

        /// <summary>
        /// The font size property
        /// </summary>
        public static readonly BindableProperty FontSizeProperty =
            BindableProperty.Create<CheckBoxView, double>(
                p => p.FontSize, -1);

        /// <summary>
        /// The font name property.
        /// </summary>
        public static readonly BindableProperty FontNameProperty =
            BindableProperty.Create<CheckBoxView, string>(
                p => p.FontName, string.Empty);

        public static ImageSource CheckedImageSource { get; protected set; }

        public static ImageSource UncheckedImageSource { get; protected set; }

        /// <summary>
        /// The checked changed event.
        /// </summary>
        public EventHandler<EventArgs<bool>> CheckedChanged;

        /// <summary>
        /// Gets or sets a value indicating whether the control is checked.
        /// </summary>
        /// <value>The checked state.</value>
        public bool Checked
        {
            get
            {
                return this.GetValue<bool>(CheckedProperty);
            }

            set
            {
                this.SetValue(CheckedProperty, value);
                var eventHandler = this.CheckedChanged;
                if (eventHandler != null)
                {
                    eventHandler.Invoke(this, value);
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the control is checked.
        /// </summary>
        /// <value>The checked state.</value>
        public bool ReadOnly
        {
            get
            {
                return this.GetValue<bool>(ReadOnlyProperty);
            }

            set
            {
                this.SetValue(ReadOnlyProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the checked text.
        /// </summary>
        /// <value>The checked state.</value>
        /// <remarks>
        /// Overwrites the default text property if set when checkbox is checked.
        /// </remarks>
        public string CheckedText
        {
            get
            {
                return this.GetValue<string>(CheckedTextProperty);
            }

            set
            {
                this.SetValue(CheckedTextProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the control is checked.
        /// </summary>
        /// <value>The checked state.</value>
        /// <remarks>
        /// Overwrites the default text property if set when checkbox is checked.
        /// </remarks>
        public string UncheckedText
        {
            get
            {
                return this.GetValue<string>(UncheckedTextProperty);
            }

            set
            {
                this.SetValue(UncheckedTextProperty, value);
            }
        }

        public ImageSource BoxImageSource
        {
            get
            {

                return this.GetValue<ImageSource>(BoxImageSourceProperty) ?? GetCheckBoxImageSource();
            }

            set
            {
                this.SetValue(BoxImageSourceProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the checked text.
        /// </summary>
        /// <value>The checked state.</value>
        /// <remarks>
        /// Overwrites the default text property if set when checkbox is checked.
        /// </remarks>
        public string CheckedImage
        {
            get
            {
                return this.GetValue<string>(CheckedImageProperty);
            }

            set
            {
                this.SetValue(CheckedImageProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the control is checked.
        /// </summary>
        /// <value>The checked state.</value>
        /// <remarks>
        /// Overwrites the default text property if set when checkbox is checked.
        /// </remarks>
        public string UncheckedImage
        {
            get
            {
                return this.GetValue<string>(UncheckedImageProperty);
            }

            set
            {
                this.SetValue(UncheckedImageProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        public string DefaultText
        {
            get
            {
                return this.GetValue<string>(DefaultTextProperty);
            }

            set
            {
                this.SetValue(DefaultTextProperty, value);
            }
        }

        public Color TextColor
        {
            get
            {
                return this.GetValue<Color>(TextColorProperty);
            }

            set
            {
                this.SetValue(TextColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the size of the font.
        /// </summary>
        /// <value>The size of the font.</value>
        public double FontSize
        {
            get
            {
                return (double)GetValue(FontSizeProperty);
            }
            set
            {
                SetValue(FontSizeProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the name of the font.
        /// </summary>
        /// <value>The name of the font.</value>
        public string FontName
        {
            get
            {
                return (string)GetValue(FontNameProperty);
            }
            set
            {
                SetValue(FontNameProperty, value);
            }
        }

        public Font Font
        {
            get
            {
                return Font.SystemFontOfSize(FontSize);
            }
        }

        public string Text
        {
            get
            {
                return this.Checked
                    ? (string.IsNullOrEmpty(this.CheckedText) ? this.DefaultText : this.CheckedText)
                        : (string.IsNullOrEmpty(this.UncheckedText) ? this.DefaultText : this.UncheckedText);
            }
        }

        public ICommand CheckCommand { get; protected set; }

        #endregion Properties

        #region Constructor

        public CheckBoxView()
        {
            CheckCommand = new Command((object s) =>
                {
                    if (!ReadOnly)
                    {
                        Checked = !Checked;
                    }
                });
            InitializeComponent();
            LoadImages();
            CheckBoxStack.BindingContext = this;
            boxImage.BindingContext = this;
            textLabel.BindingContext = this;
        }

        #endregion Constructor
         
        #region Image Functions

        protected void LoadImages()
        {
            if (CheckedImageSource == null)
            {
                CheckedImageSource = ImageSource.FromResource(GetCheckedImage());
            }
            if (UncheckedImageSource == null)
            {
                UncheckedImageSource = ImageSource.FromResource(GetUncheckedImage());
            }
        }

        private ImageSource GetCheckBoxImageSource()
        {
            return this.Checked ? CheckedImageSource : UncheckedImageSource;
        }

        private string GetCheckBoxImage()
        {
            return this.Checked
                        ? GetCheckedImage()
                        : GetUncheckedImage();
        }

        private string GetCheckedImage()
        {
            return (string.IsNullOrEmpty(this.CheckedImage) ?
                            "Check123Mobile.Resources.checked_checkbox.png" :
                            this.CheckedImage);
        }

        private string GetUncheckedImage()
        {
            return (string.IsNullOrEmpty(this.UncheckedImage) ?
                            "Check123Mobile.Resources.unchecked_checkbox.png" :
                            this.UncheckedImage);
        }

        #endregion Image Functions
    }
}

Friday, November 28, 2014

Windows 7 IKEv2 VPN "Verifying User and Password..."

I VPN quite often and recently something changed on my old laptop running Windows 7 which prevented me from connecting. I was able to connect using my laptop running Windows 8. After some hunting I came across this TechNet thread.

The fix ended up being very simple, but not intuitive.
  1. View your network adaptors by going to Control Panel > Network and Internet > Network Connection
  2. Right-click on the offending VPN adapter and click Properties
  3. Click on the Security tab
  4. Change the "Type of VPN" value from IKEv2 to Point to Point Tunneling Protocol (PPTP)
  5. Click OK
From the thread:
It seems that when this property is set to Automatic the WAN Miniport defaults to IKEv2 (and gets stuck if this is not the VPN type used).
Translated: it is a feature not a bug.

Now attempt to connect again. Short of other issues, it will connect successfully.

Thursday, November 20, 2014

Git Filter-Branch Saves The Day Again

Disclaimer

You can really mess things up, make sure you back up your files/repositories before you wield this axe.

Removing a large file from a Git repository

Recently I committed and pushed a commit to my remote repository. The push took an unusually long time. Looking at the commit, I discovered that I had committed/pushed a vagrant box into the repository. Doh! Now the repository was ~500MB. Here is what I did to clean up the repository and remove the large file.

I can't remember where I found this command (I may have assembled it from many locations). It is supposed to remove all references and the file from the repository.
git filter-branch --prune-empty -d /dev/shm/scratch --index-filter "git rm --cached -f --ignore-unmatch ubuntu-precise32-intpon.box" --tag-name-filter cat -- --all
This seemed to clean up the git tree, but didn't actually remove the file from the repository. So, on we go...

I ran across an Atlassian page which detailed several new steps to remove a large file. I skipped the first 3 steps because the above command seemed to do the same thing.

The next step was to prune all of the reflog references from now on back.
git reflog expire --expire=now --all

Then repack the repository by running the garbage collector and pruning old objects.
git gc --prune=now

Finally, push all your changes back to the remote repository.
git push origin master --force

Looking at my repository, it was back at ~45MB. I can pretend it never happened and life is good again. As long as I don't tell anyone about it.

Changing the author information

If you are committing to a public repository, you may not want your private email address exposed to the world. GitHub's change author info page has an excellent script that can fix that issue if you accidentally commit with the wrong email address. In case the page changes or disappears, here is the script:
#!/bin/sh
 
git filter-branch --env-filter '
 
OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"
 
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
Once it completes, you need to push the changes to the remote repository.
git push --force --tags origin 'refs/heads/*'
Your email is now changed.

Tuesday, October 21, 2014

A JUnit XSL Transform For PHPUnit Logging

I recently worked on a PHP application with a PHPUnit test suite. Not finding a good way to view the test run results, I settled on logging the output into JUnit format and then applied the style sheet to the XML file so that I can through the XML file into a browser.
time phpunit --testsuite "Application Test Suite" --log-junit public/testresults.xml & sed -i 's//\n/g' public/testresults.xml
Not sure why, but finding a decent transform for the JUnit output was more diffcult than expected. I decided to extended an XSL transform in this StackOverflow answer. It is a pretty good start, plain text, but I can work with it.

After applying Bootstrap styling, the end result is a pleasantly styled JUnit view in a browser. For some reason, FireFox was not applying the bootstrap CSS file, so I just brought in the styles that I needed, thus the style block.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/testsuites">
        <!-- <xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html></xsl:text> -->
        <html class="no-js" lang="en">
        <head>
            <meta charset="utf-8" />
            <meta http-equiv="X-UA-Compatible" content="IE=edge" />
            <title>PHPUnit Test Results</title>
            <meta name="description" content="" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <!-- <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" /> -->
            <style>
                html {
                  font-family: sans-serif;
                  -webkit-text-size-adjust: 100%;
                      -ms-text-size-adjust: 100%;
                  font-size: 10px;
                  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
                }
                body {
                  margin: 0;
                  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                  font-size: 14px;
                  line-height: 1.42857143;
                  color: #333;
                  background-color: #fff;
                }
                article,
                aside,
                details,
                figcaption,
                figure,
                footer,
                header,
                hgroup,
                main,
                nav,
                section,
                summary {
                  display: block;
                }
                hr {
                  height: 0;
                  -webkit-box-sizing: content-box;
                     -moz-box-sizing: content-box;
                          box-sizing: content-box;
                }
                pre {
                  overflow: auto;
                  font-family: monospace, monospace;
                  font-size: 1em;
                }

                .container {
                  padding-right: 15px;
                  padding-left: 15px;
                  margin-right: auto;
                  margin-left: auto;
                }
                .page-header {
                    padding-bottom: 9px;
                    margin: 40px 0 20px;
                    border-bottom: 1px solid #eee;
                }
                .failure, .error {
                    padding: 0px 20px;
                }
                .failure pre, .error pre {
                    border: 1px solid #DDD;
                    padding: 10px;
                }
            </style>
        </head>
        <body>
            <div class="container">
                <xsl:apply-templates select="testsuite" />
            </div>
        </body>
        </html>
    </xsl:template>

    <xsl:template match="testsuite">
        <header class="page-header">
        <h1>Testsuite: <xsl:value-of select="@name" /></h1>
        <div>
            <xsl:text>
            Tests run: </xsl:text>
            <xsl:value-of select="@tests" />
            <xsl:text>, Failures: </xsl:text>
            <xsl:value-of select="@failures" />
            <xsl:text>, Errors: </xsl:text>
            <xsl:value-of select="@errors" />
            <xsl:text>, Time elapsed: </xsl:text>
            <xsl:value-of select="@time" />
            <xsl:text> sec</xsl:text>
        </div>
        </header>
        <xsl:apply-templates select="system-out" />
        <xsl:apply-templates select="system-err" />
        <div>
            <xsl:apply-templates select="//testcase" />
        </div>
    </xsl:template>

    <xsl:template match="testcase">
        <p>
            <xsl:text>
            Testcase: </xsl:text>
            <xsl:value-of select="@name" />
            <xsl:text> took </xsl:text>
            <xsl:value-of select="@time" />
        </p>
        <xsl:apply-templates select="failure" />
        <xsl:apply-templates select="error" />
    </xsl:template>

    <xsl:template match="failure">
        <div class="failure">
            <span style="color: #ff4136;">
                <xsl:text>
                    Failure:
                </xsl:text>
                <xsl:value-of select="@type" />
            </span>
            <pre>
                <xsl:value-of select="." />
            </pre>
        </div>
    </xsl:template>

    <xsl:template match="error">
        <div class="error">
            <span style="color: #F00;">
                <xsl:text>
                    Error:
                </xsl:text>
                <xsl:value-of select="@type" />
            </span>
            <pre>
                <xsl:value-of select="." />
            </pre>
        </div>
    </xsl:template>

    <xsl:template match="system-out">
        <div>
            <xsl:text>
            ------ Standard output ------
            </xsl:text>
            <pre>
                <xsl:value-of select="." />
            </pre>
        </div>
    </xsl:template>

    <xsl:template match="system-err">
        <div>
            <xsl:text>
            ------ Error output ------
            </xsl:text>
            <pre>
                <xsl:value-of select="." />
            </pre>
        </div>
    </xsl:template>

</xsl:stylesheet>

Tuesday, October 7, 2014

Xamarin Forms Custom Controls Without Native Renderers

My last blog post discussed how to create reusable custom content views. It involved leveraging the ContentPage element's ViewModel. This is great when you want to easily pull common code out and make it reusable. This will be a great place to start building.

As with my last blog post, I was not able to find examples of people doing this pattern. It seems like such a common thing to want to do. I digress.

Let's say that there is a repeated layout structure which only differs by the ViewModel properties. What about making a custom control which do not depend on a ViewModel?

A custom control which doesn't depend on a ViewModel internally, will need to have properties which we can bind to a ContentPage ViewModel's property. We want to end up with something like:
<localcontrol:CountLabelView
    CountText="{Binding path=MessageCount}"
    Text="{Binding path=MessageText}" />
The first task is to add a new Forms Xaml Page to the project. I'll call it "CountLabelView".

Then, my experience with building native controls comes in handy. We can add BindableProperty fields to our custom control's code behind. One for each property we want to have available to our control.
public static readonly BindableProperty TextProperty =
    BindableProperty.Create<CountLabelView, string>(
        p => p.Text, 
        "", 
        BindingMode.TwoWay, 
        null,
        new BindableProperty.BindingPropertyChangedDelegate<string>(TextChanged), 
        null, 
        null);

public string Text
{
    get { return (string)GetValue(TextProperty); }
    set { SetValue(TextProperty, value); }
}

static void TextChanged(
    BindableObject obj, 
    string oldPlaceHolderValue, 
    string newPlaceHolderValue)
{
    
}
Now we have a way for a ContentPage to bind properties to custom ContentView controls.

Next we can move our layout into the ContentView.
<?xml version="1.0" encoding="utf-8" ?>
<ContentView 
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:IntPonApp;assembly=IntPonApp"
    xmlns:custom="clr-namespace:CustomControls.Controls;assembly=CustomControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    x:Class="IntPonApp.Controls.CountLabelView">
 
 <StackLayout 
        Orientation="Horizontal" 
        HorizontalOptions="FillAndExpand" 
        VerticalOptions="FillAndExpand" 
        Padding="0">
  <custom:RoundFrame 
            HorizontalOptions="CenterAndExpand" 
            VerticalOptions="CenterAndExpand" 
            Padding="7,1" 
            BorderRadius="40" 
            FillColor="#333333" 
            HasShadow="false">

   <Label    x:Name="CountTextLabel"
                Text="{Binding CountText}" 
                VerticalOptions="Center" 
                XAlign="Center" 
                TextColor="#FFFFFF" />

  </custom:RoundFrame>

  <StackLayout 
            Spacing="0" 
            HorizontalOptions="StartAndExpand" 
            VerticalOptions="CenterAndExpand" 
            Padding="0">

   <Label    x:Name="TextLabel"
                Text="{Binding Text}" 
                LineBreakMode="WordWrap" 
                XAlign="Center" 
                HorizontalOptions="StartAndExpand" 
                VerticalOptions="Center" 
                TextColor="#DEDEDE" />

  </StackLayout>
 </StackLayout>
 
</ContentView>
This is great except, if you run this, the application will fail (unless CountText and Text happen to exist in your ContentPage's ViewModel. This is problematic, but not an insurmountable obstacle. We may have a couple options:
  1. We can remove the binding from the elements, assign names to the elements which need binding, hook up onchange events (not useful in this case because we are using labels and not Entry elements) which would assign the value back to the BindableProperty, and then find the named elements and assign the value from the BindableProperty.
  2. We can assign names to the elements which need binding and then find the named elements and assign the BindingContext to the custom control object.
  3. We can assign the custom control's BindingContext to the custom control itself.
Option 1 would be a mess to implement and maintain. It has to be replicated for every control which needs binding and there is a good chance that the bindings won't work as one should expect.

Option 2: We are able to bind in a much more expected fashion and changes will cascade as we expect. However this will still result in extra 1 line of code per control needing to be bound.

Option 3: It gets rid of the inherited BindingContext and forces the control to be self sufficient and thus reusable regardless of the ViewModel. Plus, the bindings work as one expects and it is only ONE line of code.

In testing Option 3, I found that the BindingContext was not being inherited correctly to the child controls. I suspect this is a bug in Xamarin. So, at the moment Option 2 is the best option that works.

Below is the code behind for the custom control.
public partial class CountLabelView
{
    #region Properties

    public static readonly BindableProperty TextProperty =
        BindableProperty.Create<CountLabelView, string>(
            p => p.Text, 
            "", 
            BindingMode.TwoWay, 
            null,
            new BindableProperty.BindingPropertyChangedDelegate<string>(TextChanged), 
            null, 
            null);

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    static void TextChanged(
        BindableObject obj, 
        string oldPlaceHolderValue, 
        string newPlaceHolderValue)
    {
        
    }


    public static readonly BindableProperty CountTextProperty =
        BindableProperty.Create<CountLabelView, string>(
            p => p.CountText, 
            "", 
            BindingMode.TwoWay, 
            null,
            new BindableProperty.BindingPropertyChangedDelegate<string>(CountTextChanged), 
            null, 
            null);

    public string CountText
    {
        get { return (string)GetValue(CountTextProperty); }
        set { SetValue(CountTextProperty, value); }
    }

    static void CountTextChanged(
        BindableObject obj, 
        string oldPlaceHolderValue, 
        string newPlaceHolderValue)
    {

    }

    #endregion Properties

    #region Constructor

    public CountLabelView()
    {
        InitializeComponent();
        CountText = "1";
        //this.BindingContext = this;
        CountTextLabel.BindingContext = this;
        Text1Label.BindingContext = this;
        Text2Label.BindingContext = this;
    }

    #endregion Constructor
}
A point of note, the constructor contains this line CountText = "1";. This is required because there is a custom native control surrounding the label with a binding. For some reason the rendering process executes initially before the binding finishes and not having an initial value on the control will result in the custom native control's height to be ~1px. I suspect that this is another bug in Xamarin.

Then you add the XML namespace to the ContentPage declaration and add the custom control.
xmlns:localcontrol="clr-namespace:IntPonApp.Controls;assembly=IntPonApp"
<localcontrol:CountLabelView
    CountText="{Binding path=MessageCount}"
    Text="{Binding path=MessageText}" />

Wednesday, October 1, 2014

Xamarin Forms Reusable Custom Content Views

There is a lot (relatively) of information on how to make reusable native controls with renderers and native views. However there is next to nothing about how to make reusable controls which don't require renderers or native views.

[Edit 2014-12-05] The project I developed required the same header on each page, so I figured I would use that as a way to describe how to create resuable controls. Performance-wise, it shouldn't be any worse than loading the information on every page. I needed the NavigationPage functionality, but without the navigation bar. It is probably not ideal, but it is what the design imposed.

Let's assume that we have the following XAML which needs to be replicated on several pages.
<Grid x:Name="SharedHeaderBar" HorizontalOptions="FillAndExpand" Padding="5,10,5,-5" BackgroundColor="#3FB5C1" >
    <Grid.RowDefinitions>
      <RowDefinition Height="45" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Image x:Name="homeImageiOS" Source="{local:ImageResource IntPonApp.Resources.IntPon-Logo.png}" Grid.Row="0" Grid.Column="0" />
    <Button x:Name="logoffButtoniOS" Text="{Binding Path=FullName}" TextColor="#FFFFFF" Grid.Row="0" Grid.Column="2" />
  </Grid>
My first foray into this was unsuccessful because I tried using a View. I stumbled upon the ContentView. I couldn't find any examples of people using it. Having had a lot of experience with WPF and knowing what I wanted to achieve, this seemed to be the most promising path.

I created a new Forms Xaml Page and changed the ContentPage tags to ContentView. Then I moved the reused XAML into the ContentView.
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:IntPonApp;assembly=IntPonApp"
        x:Class="IntPonApp.Controls.SharedHeaderView">
  
  <Grid x:Name="SharedHeaderBar" HorizontalOptions="FillAndExpand" Padding="5,10,5,-5" BackgroundColor="#3FB5C1" >
    <Grid.RowDefinitions>
      <RowDefinition Height="45" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Image x:Name="homeImageiOS" Source="{local:ImageResource IntPonApp.Resources.IntPon-Logo.png}" Grid.Row="0" Grid.Column="0" />
    <Button x:Name="logoffButtoniOS" Text="{Binding Path=FullName}" TextColor="#FFFFFF" Grid.Row="0" Grid.Column="2" />
  </Grid>

</ContentView>
It is important to understand the state of the binding context. The binding context will be inherited from the parent control where it is used. This is very convenient because I wanted to pull a value from the ContentPage's ViewModel.

I pulled over the event bindings and the needed navigation functions. Part of the functionality that I wanted to move into the ContentView needed to raise a DisplayAlert which, as it turns out, isn't available on the ContentView element. So I flexed my recursive skills and created the following to get the ContentPage element.
public ContentPage FindParentPage(Element el = null)
{
    if (el == null)
        el = this;
    return 
          (el is ContentPage) ? (ContentPage)el
        : (el.Parent != null) ? FindParentPage(el.Parent) 
        : null;
}
Then I was able to display alert messages.

Below is the resulting code behind.
public partial class SharedHeaderView
{
    public SharedHeaderView()
    {
        InitializeComponent();

        string platformName = Device.OS.ToString();

        this.FindByName<Button>("logoffButton" + platformName)
            .Clicked += OnLogoffClicked;
        this.FindByName<Image>("homeImage" + platformName)
            .GestureRecognizers.Add(new TapGestureRecognizer((view, args) =>
        {
            this.Navigation.PopToRootAsync();
        }));
    }

    protected async void OnLogoffClicked(object sender, EventArgs e)
    {
        if (!string.IsNullOrEmpty(App.ApiKey))
        {
            string errorMessage = "";
            try
            {
                if (await FindParentPage()
                    .DisplayAlert("Sign Off", "Are you sure?", "Yes", "No"))
                {
                    App.Logout();
                }
            }
            catch (Exception ex)
            {
                errorMessage = ex.Message;
            }

            if (!string.IsNullOrEmpty(errorMessage))
            {
                await FindParentPage()
                    .DisplayAlert("Help", errorMessage, "OK");
            }
        }
    }

    public ContentPage FindParentPage(Element el = null)
    {
        if (el == null)
            el = this;
        return 
              (el is ContentPage) ? (ContentPage)el
            : (el.Parent != null) ? FindParentPage(el.Parent) 
            : null;
    }
}
Then you add the XML namespace to the ContentPage declaration and add the XML node.
xmlns:localcontrol="clr-namespace:IntPonApp.Controls;assembly=IntPonApp"
<localcontrol:SharedHeaderView />
Getting this to work has really saved me a lot of unneeded duplication.

Edit 2014-12-05: Edited to add comment/response/excuse to a question on StackOverflow: Is it possible to create a custom page layout with Xamarin.Forms?

Thursday, September 25, 2014

Synergy Desktop Path Error

I recently started working on a mobile project which afforded me the opportunity to flex my iOS development skills again. I installed the latest version of Synergy on my MacBook and my main laptop. I used the setup I had before which loaded correctly, but I started receiving this error which prevented me from connecting my Mac to my PC host.

ERROR: failed to get desktop path, no drop target available, error=2

Googling wasn't fruitful so I looked at the settings which looked as I expected. I finally tried unchecking the "Elevate" checkbox and clicked "Apply". The error went away and I was able to connect. "Elevate" should mean that the service will run in elevated/administrator mode. I found no events being raised in the event log and I believe I had the Synergy application successfully using the Elevate option in the past. Whatever the root cause was, not using the "Elevate" option fixed the issue.

For those that do not know about Synergy, it is an
application which allows you to share your keyboard and mouse with other computers over a network. I have been using Synergy for years and find is especially useful when I need to switch between multiple computers frequently.

Wednesday, September 3, 2014

IP Subnet Mask Expander The Web Client

In a previous post, I created a Node.Js project, IPSubnetMaskToIPRange, that takes a file with a list of IP subnet masks and then outputs 2 CSV files (one of the IP ranges and one of the expanded IP ranges).

Sometimes when I create a cool project, I end up having flashes of changes and improvements that I can make to it. This is one of those cases.

This project uses the same base functionality as the Node.Js project. This has the same functionality, except it is completely run from the browser leveraging AngularJS and Bootstrap 3. It outputs the ranges to the screen and provides buttons to download the IP ranges and the expanded IP ranges.

The working site can be found at IP Subnet Mask Expander and the source can be found on GitHub.

Monday, August 18, 2014

Angular.JS Service to Download Data Generated in Browser

I ran into a situation where I wanted to be able to download data that was generated in the browser. There are several libraries that handle this scenario, but I thought it should have been simpler than those large libraries.

Below is the result. It supports IE 10+ (potentially 9 haven't tested), FireFox, and Chrome.
angular.module('FileDownload')
.service('SaveFileService', [function () {
        this.Save = function(data, filename, mimeType) {
            var blob = new Blob([data.join('\n')], {type: mimeType});
            if (/\bMSIE\b|\bTrident\b|\bEdge\b/.test(navigator.userAgent)) {
                window.navigator.msSaveOrOpenBlob(blob, filename);
            } else {
                var url  = window.URL || window.webkitURL,
                    link = document.createElementNS("http://www.w3.org/1999/xhtml", "a"),
                    event = document.createEvent("MouseEvents");
                
                link.href = url.createObjectURL(blob);
                link.download = filename;

                event.initEvent("click", true, false);
                link.dispatchEvent(event);
            }
        };
    }]);
Basically, the Save function does a couple things. For IE browsers, it creates the blob and calls the msSaveOrOpenBlob (the msSaveBlob function would make IE only display a save dialog and not give the user the option to open it). For all other browsers, it creates the blob, generates a link element, creates a mouse click event, and has the link dispatch the created event.

To use the service, just inject the service into the controller and call the Save function w/ the needed parameters.

UPDATE 2015-09-28: Per Kevin's feedback, I have updated the regular expression to catch the Edge browser (so much for Microsoft making a standards evergreen browser). I have verified that the above change works as advertised.