Author Archives: Adam Z

One Hand Typing

If you have to type with one hand, AutoHotkey is a free option to turn your regular keyboard into a half mirror keyboard, where each key on one side is mirrored to the other (activate it by pressing Space key first).

Here’s a script, copied from AutoHotkey forum with slight modifications:

#SingleInstance, force
; Half-QWERTY: One-handed Typing - version 3a
; HalfKeyboard invented by Matias Corporation between 1992 and 1996
; Originally coded in AutoHotkey by jonny in 2004
; Many thanks to Chris for helping him out with this script.
; Capslock hacks and `~ remap to '" by Watcher
; This implementation was done by mbirth in 2007
; version 3a script, mod by hugov:
; 2008-10-31:
; - mixed with "Capitalize letters after 1 second hold" at request of Calibran
; just tested very briefly so try at your own peril :-)

KeyIsDown = 0
UpperDelay = 300
UpperDelay *= -1

RegRead KLang, HKEY_CURRENT_USER, Keyboard Layout\Preload, 1
StringRight KLang, KLang, 4
If (!KLang)
KLang := A_Language

If (KLang = "0407") {
; 0407 DE_de QWERTZ mirror set
original := "^12345qwertasdfgyxcvb"
mirrored := "ß09876poiuzölkjh-.,mn"
} Else If (KLang = "040c" || KLang = "040C") {
; 040c FR_fr AZERTY mirror set
original := "²&é" . """" . "'(azertqsdfgwxcvb" ; split up string for better
mirrored := ")àç" . "_" . "è-poiuymlkjh!:;,n" ; human readability
} Else {
; 0409 US_us QWERTY mirror set
original := "``" . "12345qwertasdfgzxcvb" ; split up string for better
mirrored := "'" . "09876poiuy;lkjh/.,mn" ; human readability

; Now define all hotkeys
Loop % StrLen(original)
c1 := SubStr(original, A_Index, 1)
c2 := SubStr(mirrored, A_Index, 1)
Hotkey Space & %c1%, DoHotkey
Hotkey Space & %c2%, DoHotkey
Hotkey %c1%, KeyDown
Hotkey %c1% UP, KeyUP
Hotkey %c2%, KeyDown ;
Hotkey %c2% UP, KeyUP ;


; This key may help, as the space-on-up may get annoying, especially if you type fast.
Control & Space::Suspend

; Not exactly mirror but as close as we can get, Capslock enter, Tab backspace.
Space & CapsLock::Send {Enter}
Space & Tab::Send {Backspace}

; If spacebar didn't modify anything, send a real space keystroke upon release.
+Space::Send {Space}
Space::Send {Space}

; General purpose
StartTime := A_TickCount
StringRight ThisKey, A_ThisHotkey, 1
i1 := InStr(original, ThisKey)
i2 := InStr(mirrored, ThisKey)
If (i1+i2 = 0) {
MirrorKey := ThisKey
} Else If (i1 > 0) {
MirrorKey := SubStr(mirrored, i1, 1)
} Else {
MirrorKey := SubStr(original, i2, 1)

Modifiers := ""
If (GetKeyState("LWin") || GetKeyState("RWin")) {
Modifiers .= "#"
If (GetKeyState("Control")) {
Modifiers .= "^"
If (GetKeyState("Alt")) {
Modifiers .= "!"
If (GetKeyState("Shift") + GetKeyState("CapsLock", "T") = 1) {
; only add if Shift is held OR CapsLock is on (XOR) (both held down would result in value of 2)
Modifiers .= "+"

If (KeyIsDown < 1 or ThisKey <> LastKey)
KeyIsDown := True
LastKey := ThisKey
Send %Modifiers%{%MirrorKey%}
SetKeyDelay, 65535
SetTimer, ReplaceWithUpperMirror, %UpperDelay%


IfWinNotExist, HalfKeyboard - permanent keyboard layout
Gui, +Owner +Toolwindow +AlwaysOnTop
Gui, Add, picture, x0 y0 w310 h104, %A_ScriptDir%\halfkeyboard_help.png
Gui, Show, w310 h104 NA, HalfKeyboard - permanent keyboard layout
Menu, Tray, Check, &Show Keyboard layout
Gosub, GuiClose

Menu, Tray, UnCheck, &Show Keyboard layout
Gui, Destroy


If (KeyIsDown < 1 or Key <> LastKey)
KeyIsDown := True
LastKey := Key
Send %Key%
SetKeyDelay, 65535
SetTimer, ReplaceWithUpper, %UpperDelay%

SetTimer, ReplaceWithUpper, Off
SetTimer, ReplaceWithUpperMirror, Off
KeyIsDown := False

SetKeyDelay, -1
Send {Backspace}+%LastKey%

SetKeyDelay, -1
Send {Backspace}+%MirrorKey%

C# 6 Summary

Short and incomplete notes on Rob Conery Pluralsight course “Exploring C# 6 with Jon Skeet”

  • Auto-properties
    Old way (still can set anywhere within the class)

    public string Name {get; private set;}

    New way (can be set only in a constructor or initializer)

    public string Name{get;}


    public string Name{get;} = "J";

  • Expression-bodied members
    For Properties
    Old way

    public Timespan Age{ get {return DateTime.UtcNow - DateOfBirth;}

    New way

    public Timespan Age => return DateTime.UtcNow - DateOfBirth;

    For Methods
    Old way

    public int GetName() {return "Joe";}

    New way

    public int GetName() => "Joe";

  • nameof
    Old way
    Use string literal; expression tree, or [CallerMemberName] attribute
    New way

  • Using Static
    Old way


    New way

    using static System.Math;
    using static SomeEnum

  • String Interpolation
    $”{SomePropertyOrExpression} …”

  • Nullability
    Null Conditional Operator
    Old way

    return a!=null && a.b!=null && a.b.c=="abc";

    New way

    return a!.b!.c=="abc";

    Event Handlers
    Old way

    var handler = eventHandler;
    if (handler !=null) {handler...}

    New way


  • Exception Filters
    catch(WebException e) when(e.Status == ...)

Custom MVC Model Binder

When you expect data in non-standard way and you want it to magically bind to your model, custom model binders could be a way to go.

Let’s say we want to post xml data to our controller method and we have a model for it.

public class XmlModel
            public int Number { get; set; }

Which we want to accept in our controller method:

public ActionResult Xml(XmlModel xmlModel)
            return Content(xmlModel.Number.ToString());

Now, let’s add our xml binder:

public class XmlModelBinder : IModelBinder
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            var modelType = bindingContext.ModelType;
            return new XmlSerializer(modelType).Deserialize(controllerContext.HttpContext.Request.InputStream);

And XMLModelBinderProvider:

public class XMLModelBinderProvider : IModelBinderProvider
        public IModelBinder GetBinder(Type modelType)
            var contentType = HttpContext.Current.Request.ContentType;
            if (string.Compare(contentType, @"text/xml", StringComparison.OrdinalIgnoreCase) != 0)
                return null;

            return new XmlModelBinder();

Add the provider to our Application_Start method in the Global.asax:

ModelBinderProviders.BinderProviders.Insert(0, new XMLModelBinderProvider()); 

To test this we can use Composer from Fiddler:
User-Agent: Fiddler
Content-Type: text/xml

Request Body:


If we add breakpoint in our controller, we should see 42 coming through in our model.

Exceptionless Self-Hosting Tips

Exceptionless is an awesome open source real-time error, feature, and log reporting solution that can be self-hosted for free (they provide a very reasonable pricing plans as well). Here’re some tips on self-hosting in the Windows environment.

Use these detailed instructions to set it up. Instructions are quite good. However, there are some details not mentioned in the guide which you could find helpful for self-hosting.

Elastic Search

When setting up Elastic Search, it’s a good idea to change the default location of the data folder. It can help avoid an accidental loss of your data when updating to the next version of Elastic Search. The data path can be set in the elasticsearch.yml – “” property.

Rename your cluster name – “” property. This can help prevent someone from accidentally joining your cluster.

To directly query Elastic Search, you can install Sense chrome plugin and run queries inside Chrome.

Another useful ES GUI plugin: elasticsearch-gui
To install, run cmd from ES installation bin folder: [~/elasticsearch] $ bin/plugin –install jettro/elasticsearch-gui
To access it, go to http://yourServer:9200/_plugin/gui/index.html#/dashboard (assuming default ES port 9200)

If you want to set up backups for ES, first set the repo location in elasticsearch.yml
path.repo: [“backupLocation”]

From Chrome, Sense plugin, run the following query to create a repo for your backups:

PUT /_snapshot/exceptionless_backup
  "type": "fs",
   "settings": {
        "compress" : true,
        "location": "backupLocation"

When you want to create a snapshot, run:

PUT /_snapshot/exceptionless_backup/yourShapshotName?wait_for_completion=true

To delete an old snapshot:

DELETE _snapshot/exceptionless_backup/yourShapshotName

Removing Old Data
Exceptionless provides a job which will automatically remove data over a given retention period. But if you self-host, the retention period is indefinite. If you prefer to have Exceptionless remove the old automatically, you can modify the retention period directly in the Elastic Search. Run the following ES query to set retention period to 45 days:

POST /organizations-v1/organization/YourOrganizationId/_update '{ "doc" : 
    "doc" : {        
 "_source": {
     "retention_days": 45

You can use Elasticsearch-gui plugin to figure out your organization Id.

Weirdness with IE 11.
For some reason IE 11 did not want to auto refresh itself. So, you could add these headers at IIS level:
Cache-Control:no-cache, no-store
This comes at the price of more hits to your server. But I couldn’t figure out the IE issue.

If you use Redis (recommended), this is how you specify the connection string:

<add name="RedisConnectionString" connectionString="serverName:6379" />

The important part is that there is no http in the server name

Using Git with Tfs

If you’ve been curious about Git but have to use TFS, there is a way to try Git locally while still using TFS on the server. This can give you a chance to learn about Git while still working with Tfs.

Install git ( and git-tfs ( Ensure both are working properly on the command line by trying out the commands.
Setup username and email address in .gitconfig. On a Windows system, it should be in your C:\Users\{username}. See a sample .gitconfig below.

quick-clone allows you to clone a TFS repository at a specific changeset (c12345 in the example below):
git tfs quick-clone http://tfs:8080/tfs/DefaultCollection “$/yourTfsBranch” -c12345 –workspace=C:/ws

Now, you can pull all of the history starting from c12345 above:
git tfs pull

Run the clean up command:
git gc
git tfs cleanup

You’re ready to use Git as your local source control.

When you have a new task, create a new branch:
git checkout -b yourNewBranchName
After you made your changes, add it to your local branch:
git add –patch

Before moving your code, you need to get the latest from TFS and merge it into your branch:
git checkout master
git tfs pull
git checkout yourNewBranchName
git rebase master

Or, you can replace all of the 4 commands above with:
git tfs pull -r

If you need to shelve your changes:
git tfs shelve ShelfsetName

To checkin your code to tfs:
git tfs checkintool

When you need to merge changes from TFS, run
git mergetool

After you are done merging, continue with git rebase
git rebase –continue

Visual Studio also provides options to manage your branches and checkin your code to your local branches without the need to use a command line. You would still use command line to move your code to TFS.

SourceTree is another excellent tool to manage your local Git.

Sample .gitconfig (using Visual Studio as a merge tool):

name = FirstName LastName
email = [email protected]
autocrlf = true
excludesfile = C:\\.gitignore
editor = ‘C:\\Program Files\\Sublime Text 3\\sublime_text.exe’ -w
fscache = true
preloadindex = true

tool = vs
prompt = false
[difftool “vs”]
cmd = \”C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE\\vsdiffmerge.exe\” \”$LOCAL\” \”$REMOTE\” //t
keepbackup = false
trustexitcode = true
tool = vs
prompt = false
[mergetool “vs”]
#cmd = ‘C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE\\vsdiffmerge.exe’ “$REMOTE” “$LOCAL” “$BASE” “$MERGED” //m
cmd = \”C:\\Program Files (x86)//Microsoft Visual Studio 12.0\\Common7\\IDE\\vsdiffmerge.exe\” \”$REMOTE\” \”$LOCAL\” \”$BASE\” \”$MERGED\” //m
keepbackup = true
trustexitcode = true


Sample .gitIgnore:
#ignore thumbnails created by windows
#Ignore files build by Visual Studio

Securing Windows RDP with two-factor Authentication.

Opening RDP access for you home computer can be quite convenient. However, this means you have to carefully secure access to your machine. One of the things you can do is to enable two-factor authentication.
Duosecurity provides such an option for free (has paid versions for business).

Steps to enable two-factor authentication with Duo:

  • Create a free account on
  • Log int to your account. Go to Application – create a new application – Microsoft RDP.
  • Install Duo RDP Installer Package (from duosecurity) and install on your machine. It’ll ask for Integration key, Secret key, and API hostname from the application that you created. If you don’t want to use duo for local logins, make sure to check “Only prompt for Duo authentication when logging in via RDP”.
  • Go to your duosecurity dashboard and add a new user. This may be a little tricky if you use a Microsoft Live account (the same account across multiple machines). It doesn’t seem to work with duosecurity. Instead you need to enter your Windows username (Computer Management – Local Users and Groups – Find your account. Use this name in your RDP connection as well as in Duo Security.). Add Phone to your user account and activate it (will text you a link to activate).

You are all set. The next time you try to RDP to your machine, it’ll send you a push notification to your phone before you can login.

Custom Dynamic Error Messages with JQuery Unobtrusive Validation

This could be helpful for the circumstances when you need to dynamically determine the error message for one of you custom validators:

$.validator.addMethod('customvalidatorname', function(value, element, parameters) {
	return validationFunction();
}, function(params, element) {
	return errorMessageFunction();

The third parameter to addMethod can be a function which dynamically determines your error message.

Chrome Developer Tools Productivity Tips

Most Useful Shortcuts
Ctrl Shift I – Open developer tools.
Ctrl Shift P – Search within file. Displays all functions within a file.
Ctrl P – show js files. Type to search.
Ctrl Shift C – inspect element
Esc – toggle console
Ctrl F – find inside a file
Ctrl Shift F – find across all sources

To enable text editing directly in a browser:
document.body.contentEditable = true;

To time something: console.time(“my action”); … console.timeEnd(“my action”)

Snippets – run custom JavaScript code and run it anwhere you want.

To disable cache – Network tab – disable cache (while DevTools is open).

Add timestamp to events displayed in console – Settings – General – Console – Show timestamps.

Enabling awesome dark theme:
Go to chrome://flags – Enable Developer Tools Experiments.
Open Chrome Dev Tools. – Settings – Experiments – allow custom UIthemes
Install a DevTools Theme. Here’s one.

A cool video about the above and much more – Chrome Developer Tools Deep Dive by Shay Friedman

Free Options to Protect a WordPress Site

  • Do not use username “admin” – when someone tries to brute-force into your site, this will likely be the first username they try.
    Keep your WordPress and plugins up to date.
  • Use a password manager to store your passwords. This will allow you to use strong passwords for your site (and anything else) without committing your memory to remembering all of the combinations special characters, letters and numbers.
  • Akismet – a very effective option to detect and block spam comments from your blog.
  • Wordfence (free/paid) – a free version allows to scan your source code, themes and plugins; set up limits on login attempts; sent email notifications when somebody logs in to your site or enters invalid credentials. If the number of users who can login to you site is relatively small, I recommend immediately locking out the users who try to log in with an invalid name, which is an excellent option to defend against brute-force attacks.
    A paid version allows to set up two-factor authentication, country-blocking, advanced spam scan options.
  • IQ Block Country (free) – you can combine it with the Wordfence to get additional protection for country blocking if you don’t want to pay Premium for Wordfence. IQ Block Country allows to block certain countries (determined by IP) from logging to either your frontend or backend pages.

There is a potential that Wordfence and IQ Block country may conflict with each other; I have used both plugins without experiencing any conflicts.
When considering country blocking, you may want to check your Spam folder to see where most of your spam comes from; or if you already use Wordfence – it can tell from which countries most of the invalid logins orginate. Use this information to lock your back-end or front-end. I found country blocking surprisingly effective against spam.
Continue reading