Sunday, November 18, 2012

Overloading methods in TypeScript

At yesterday's presentation at Desert Code Camp I felt that I gave an inadequate explanation on how you would implement an overloaded method in TypeScript. Hopefully this code snippet will address that:

interface Thing {
    a: number;
    b: string;
    foo(x: string): string;
    foo(n: number): number;
}

function myfunction(myParam: Thing) {
    var stringResult: string = myParam.foo(myParam.b);
    var numberResult: number = myParam.foo(myParam.a);

    console.log(stringResult);
    console.log(numberResult);
}


var myObj = {
    a: 16,
    b: "My String",
    foo: (x: any) => {
        if (x && typeof x === 'string') {
            return x.length.toString();
        } else if (x && typeof x === 'number') {
            return x * x;
        } else {
            if (x) {
                throw { message: "null parameter is unsupported" };
            } else {
                throw { message: "unsupported type: " + typeof x };
            }
        }
    }
}

myfunction(myObj);

Note that in myfunction() you would not be able to call myParam.foo() with any other type of parameter than string or number because the compiler will complain about that. So even though the implementation checks for another type in the final else you cannot pass in another type (e.g. object) because TypeScript won't let you.

Friday, November 16, 2012

Toastmasters Timer in TypeScript

I recently wrote a Toastmasters Timer in TypeScript for two reasons:
  1. The other timers that I found out on the web didn't quite do what I wanted them to do and
  2. I needed a small project to learn TypeScript
All of the timers I found followed the same approximate format as this one created by Stan Birdwell (Central Toastmasters 2277-31) and Michael K. Heney (Goddard Toastmasters 3496-36):




I was looking for something that would should the time in a large font on the page and change the color of a large portion of the page at each stage. I needed this to be able to constantly monitor the time and color from a distance while I am pacing around the room practicing a speech. I didn't want to have to lean forward to see the time. This is the final result: Toastmasters Timer






Here is the TypeScript source code for that timer (the compiled JS, HTML and CSS can be pulled from the page):
/// <reference path="jquery.d.ts" />

class SpeechType {
    constructor (public name: string, public greenTime: string, public yellowTime: string, public redTime: string, public id: string) {
    }
}

class TSTimer {
    timerToken: number;
    speeches: SpeechType[];
    started: bool;
    startTime: Date;
    stopTime: Date;
    green: number;
    yellow: number;
    red: number;

    constructor (speeches: SpeechType[]) {
        this.started = false;
        this.speeches = speeches;

        $.each(this.speeches, (indexInArray: number, valueOfElement: SpeechType) => {
            var newButton = $('<span>')
                .attr('id', valueOfElement.id)
                .addClass('speech-type')
                .html(valueOfElement.name);
            newButton.click( (event) => {
                this.activateSpeech($(event.target).attr('id'));
            });
            newButton.appendTo('#buttons');
        });
       
        $(window).resize( () => {
            this.resizeTime();
        });
        // call on initialization in case the browser starts off narrow
        this.resizeTime();

        $('#btnReset').click( () => {
            this.resetButton();
        });

        $('#btnStart').click(() => {
            this.startButton();
        });

    }

    resetButton() {
        this.stop();
        $('#trafficlight').text('0:00');
        $('#body').css('background-color', '#EFEEEF');
        this.startTime = null;
    }

    startButton() {
        if (this.started) {
            this.stop();
        } else {
            this.start();
        }
    };

    resizeTime() {
        var width = $(window).width();
        var x: number = Math.floor((width < 900) ? (width / 900) * 28 : 28);
        $('#trafficlight').css('font-size', x + 'em');
    }

    setElementText(elapsedSeconds: number) {
        $('#trafficlight').text(this.formatTime(elapsedSeconds));
        if (elapsedSeconds >= this.red) {
            $('#body').css('background-color', '#FF4040');
        } else if (elapsedSeconds >= this.yellow) {
            $('#body').css('background-color', '#FCDC3B');
        } else if (elapsedSeconds >= this.green) {
            $('#body').css('background-color', '#A7DA7E');
        }
    }

    timerEvent() {
        if (!this.startTime) {
            this.startTime = new Date();
        }
        var timeNow = new Date();
        var elapsedSeconds: number = this.timeDiffInSeconds(this.startTime, timeNow);
        this.setElementText(elapsedSeconds);
    }

    // Returns the difference in seconds between
    timeDiffInSeconds(earlyTime: Date, lateTime: Date): number {
        var diff: number = lateTime.getTime() - earlyTime.getTime();
        return Math.floor(diff / 1000);
    }

    formatTime(elapsedSeconds: number) {
        var minutes: number = Math.floor(elapsedSeconds / 60);
        var seconds: number = elapsedSeconds % 60;
        return minutes + ":" + ((seconds < 10) ? "0" + seconds.toString() : seconds.toString());
    }

    start() {
        $('#btnStart').val('Stop');
        this.started = true;
        if (this.startTime) {
            // i.e. no reset since the last time it was started so adjust the start time
            // to reflect the time that's elapsed since it was stopped.
            var newStartTime = new Date().getTime() - (this.stopTime.getTime() - this.startTime.getTime());
            this.startTime.setTime(newStartTime);
        }
        this.green = this.getSecondsFromTextBox('#green-light');
        this.yellow = this.getSecondsFromTextBox('#yellow-light');
        this.red = this.getSecondsFromTextBox('#red-light');
        this.timerToken = setInterval(() => this.timerEvent(), 1000);
    }

    stop() {
        $('#btnStart').val('Start');
        this.started = false;
        this.stopTime = new Date();
        clearTimeout(this.timerToken);
    }
   

    getSecondsFromTextBox(id: string): number {
        var greenLight: string = $(id).val();
        return parseInt(greenLight.split(':')[0]) * 60 + parseInt(greenLight.split(':')[1]);
    }

    setDefault() {
        this.activateSpeech('st-standard');
    }

    activateSpeech(speechId: string) {
        $.each(this.speeches, function (indexInArray: number, valueOfElement: SpeechType) {
            if (valueOfElement.id === speechId) {
                $('#green-light').val(valueOfElement.greenTime);
                $('#yellow-light').val(valueOfElement.yellowTime);
                $('#red-light').val(valueOfElement.redTime);
            }
        });
        $('.active-speech').removeClass('active-speech');
        $('#' + speechId).addClass('active-speech');
    }
}


$(document).ready(function () {
    var speeches = [];
    speeches.push(new SpeechType("Table&nbsp;Topics", "1:00", "1:30", "2:00", "st-table-topics"));
    speeches.push(new SpeechType("Evaluation", "2:00", "2:30", "3:00", "st-evaluation"));
    speeches.push(new SpeechType("Icebreaker", "4:00", "5:00", "6:00", "st-icebreaker"));
    speeches.push(new SpeechType("Standard", "5:00", "6:00", "7:00", "st-standard"));
    speeches.push(new SpeechType("Advanced", "8:00", "9:00", "10:00", "st-advanced"));
    speeches.push(new SpeechType("Test", "0:02", "0:04", "0:06", "st-test"));
    var timer = new TSTimer(speeches);

    timer.setDefault();
});



Saturday, November 10, 2012

TypeScript template doesn't work in FireFox

If you're using Visual Studio 2012 and you've added the TypeScript for Microsoft Visual Studio 2012 extension then you will be able to jump start a TypeScript project using the template. If you click File > New > Project and look under the Visual C# templates you'll see a template called HTML Application with TypeScript. Selecting this template will generate a new project with a TypeScript file with the following contents:

class Greeter {
    element: HTMLElement;
    span: HTMLElement;
    timerToken: number;
   
    constructor (element: HTMLElement) {
        this.element = element;
        this.element.innerText += "The time is: ";
        this.span = document.createElement('span');
        this.element.appendChild(this.span);
        this.span.innerText = new Date().toUTCString();
    }

    start() {
        this.timerToken = setInterval(() =>
          this.span.innerText = new Date().toUTCString(), 500);
    }

    stop() {
        clearTimeout(this.timerToken);
    }
}

window.onload = () => {
    var el = document.getElementById('content');
    var greeter = new Greeter(el);
    greeter.start();
};

The problem with this code is the use of the .innerText property which is called .textContent in FireFox.

Here is a replacement to the above template that will work in FireFox and other browsers to get you moving forward again.

Tested on:
FireFox 16.0.2
Safari for Windows 5.1.7
IE9
Chrome 23.0.1271.64 m
Opera 12.10

class Greeter {
    element: HTMLElement;
    span: HTMLElement;
    timerToken: number;
    hasInnerText: bool;
   
    constructor (element: HTMLElement) {
        this.element = element;
        // Firefox uses textContent
        this.hasInnerText = !this.element.textContent;
        this.appendElementText(this.element, "The time is: ");
        this.span = document.createElement('span');
        this.element.appendChild(this.span);
        this.setElementText(this.span, new Date().toUTCString());
    }

    setElementText(elem: HTMLElement, value: string) {
        if (this.hasInnerText) {
            elem.innerText = value;
        } else {
            elem.textContent = value;
        }
    }

    appendElementText(elem: HTMLElement, value: string) {
        if (this.hasInnerText) {
            elem.innerText += value;
        } else {
            elem.textContent += value;
        }
    }

    start() {
        this.timerToken = setInterval(() =>
          this.setElementText(this.span, new Date().toUTCString()), 500);
    }

    stop() {
        clearTimeout(this.timerToken);
    }   
}

window.onload = () => {
    var el = document.getElementById('content');
    var greeter = new Greeter(el);
    greeter.start();
};


 

 

Friday, November 2, 2012

TypeScript

I'm going to be giving a presentation called TypeScript, what's all the fuss? at the Fall 2012 Desert Code Camp on November 17, 2012. I'll be adding a list of resources and my slides to this blog post.

TypeScript Resources:

Here's an example of method overloading in TypeScript which I didn't cover adequately in this presentation.

Thursday, July 19, 2012

Amazon SES and Easy DKIM

I've been using Amazon's Simple Email Service (SES) for at about a year now and it's been great. Failures are very rare and the API and libraries provided are excellent. With SES you build up trust which increases your volume quota (per 24 hour period) and your send rate (per second). My only complaint is that my send rate is not as high as I want it to be.

Today I received an email saying the I can easily DKIM-Sign my emails with Easy DKIM in the SES control panel (aka AWS Management Console). This was exciting because I'd never heard of DKIM before and it sounded so easy to do.

It turned out to be pathetically easy. In the AWS Management Console you simply select your email address and under the DKIM tab you click the "Generate DKIM Settings" button.

This generates 3 CNAME records that you have to update your DNS records with. I use Go Daddy so I launched the DNS Manager for that domain and under the CNAME section I clicked the Quick Add button and copy/pasted the 3 keys and values from Amazon. Both Go Daddy and Amazon warned that it could take up to 48 to 72 hours to complete, however, less than 2 hours later I received an email from Amazon stating that it was complete and I tested it and it worked.

The emails sent through SES on behalf of that domain (to my gmail account) now have 2 new headers:

DomainKey-Status: good

I'm guessing that GMail added this header to signal that it validated the DomainKey that Amazon had created.

DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; t=12345;
    s=fa; d=fake.com;
    h=From:Reply-To:To:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Date:Message-ID;
    bh=fake
    b=fake

This is what the actual signature looks like. I've replaced the values to protect the innocent. The one and two letter keys stand for:

v = version
a = algorithm (signing algorithm)
q = query (default query method)
c = canonicalization algorithm for header and body
t = timestamp
s = selector
d = domain (signing domain)
h = header (a list of the signed header fields)
bh = body hash
b = body (the actual digital signature of the contents, both header and body)

If you're already using SES then this is a no-brainer. Total time is around 15 minutes at the most. The first 10 minutes is initial setup in Amazon and then with your registrar. Once you get the confirmation back from Amazon (about 2 hours later) that it's been setup then take the other 5 minutes to go back into your Amazon account and enable DKIM by clicking a link. The first 2 times I clicked the link it didn't work so keep clicking it until it does.

If you want to test it then send yourself an email through SES before you enable DKIM and then another afterwards and compare the headers.

 

Wednesday, June 27, 2012

Ad Management services versus doing it yourself

Should you use an advertising management solution such as DFP Small Business or do it yourself?

(DFP stands for DoubleClick For Publishers. DoubleClick was bought by Google in March 2008 for $3.1 billion.)

If someone approaches me and wants to advertise on one of my sites my usual response is to tell them to use Google's AdWords program and target my site or pages on my site with their adverts. In my opinion, Google does a great job and they only take 32%. I don't have to get involved at all.

Sometimes it is worth my while to split that 32% with an advertiser and I'll add their advert to a site for a given time period.

The advantages of doing it yourself are advantages for the the advertiser, not for you the publisher:

  • If you host the advert's image and text on your site then it is almost impossible for Ad Blockers to block the ads because they are integrated images.
  • Your advertiser gets a one-way follow link to their site from your page.

The disadvantage is that you have to create an embedded solution to allow advertisers to upload their adverts to your site (the sophisticated solution) or you have to do it manually. Doing this yourself requires work on your part either way and you will have to measure the Return On Investment and if that extra revenue over AdSense is worth it.

Wednesday, June 20, 2012

Should the team upgrade to the latest version?

I manage a couple of teams of .NET developers. Like everyone else we are under pressure and deadlines to push out the next feature and keep our products moving forward, feature rich and profitable. Nothing new here.




The usual arguments put forward to justify an upgrade to the latest version of a framework or tool are one or more of the following:
  • It has new features.
  • It fixes bugs
  • It runs faster
They are acceptable and reasonable reasons but in my opinion not the most important.
The most important reasons for me to keep us on the latest releases are for developer engagement, retention and recruitment.
As a developer I hate to hear about features that are available but I cannot use because I'm not on the latest release and I know that most other developers feel the same way. The latest feature or paradigm in the current RTM version of your framework might not be the best solution for your project but we don't want it to be excluded because we don't have access to it. We want to be able to actively exclude it because it's not right for us.
When recruiting new members onto your team it makes it easier to be able to say "we use .NET [latest version] with ASP.NET MVC [latest version] and jQuery [latest version]." There are obviously other factors involved but this (1) eliminates the fear that the tools might not be current and (2) keeps you open to almost all developers out there. i.e. those that don't want to regress to earlier versions of a framework. We might not be using any features that have been introduced in the latest versions (we are) but at least that option is open to us.
For engagement and retention it's important for the same reasons. Everyone's happy because we all have access to the latest.
I believe that early upgrade is important to reduce the pain and is ultimately more efficient. If the team is used to upgrading the frameworks and/or tools frequently then it will be familiar, less painful and easier to plan for. For example, we try and upgrade to the latest version of jQuery once a quarter. We do this because our QA team likes to do a full multi-browser regression once a quarter and an upgrade to a new version of jQuery requires this type of regression.
I rarely attempt an immediate upgrade when a new version is released. I like to let it bake for 4 to 12 weeks and read some of the upgrade comments and let the owners address any of the issues the early adopters have encountered. By then there are a few good instructional blogs out there on how to deal with unusual errors and edge case upgrades.
I usually isolate the upgrade to be done by one developer, have him or her extensively document the experience and put a hard time limit on the upgrade attempt. If possible we push the upgrade out as its own release and don't combine it with features and bug fixes.

Wednesday, May 9, 2012

SQL Injection Attack from 82.45.20.100

While perusing the application logs this morning I noticed a number of SQL Injection attempts. The site that was being attacked uses MVC with automatic Form values to object binding so the exceptions were being thrown early on in the controller when the framework was trying to bind the attack string to, for example, a boolean.

Here are some of the attack strings the system logged:

 

%20AND%201=1
%20AND%201=2
&amp;#39; AND &amp;#39;1&amp;#39;=&amp;#39;1
&amp;#39; AND &amp;#39;1&amp;#39;=&amp;#39;2
&amp;#39; AND 1=1/*
&amp;#39; AND 1=2/*
AND 1=1/*
AND 1=2/*

The source of the attack:

IP: 82.45.20.100
City: Bristol
State: England
Country: United Kingdom
ISP: Virgin Media Limited.

The attack bot wandered around the site and tried many different entry points as you'd expect. Some of the attack points on the site identified it as an attack through the pattern being requested and stopped processing .An initial inspection of the database shows no damage.

One of the tricky things about logging SQL Injection attacks is that if you're logging them to a database then your logging process might facilitate the attack when the initial attack failed. I have 2 suggestions for this this:

1. Ensure that any code you use to insert or update to the DB is appropriately parameterized and injection proof.

2. Become a SQL Injection expert and try and break your fortress with injection attempts.

I'm a little bit surprised that SQL Injection attempts are still going on. I would have thought that any site worth taking over would have dealt with this by now. It's been over a decade since this became a well known security problem.

 

 

Sunday, March 25, 2012

The Servant Leadership Training Course

I've just finished The Servant Leadership Training Course on CD.

The Servant Leadership Training Course

There isn't anything new in this book and if you've read and understood the other popular books in this area then this will just be a repeat.

However, having this information repeated to you on a regular basis is very useful. And having it repeated from a different point of view is even more useful. For that reason I enjoyed it. The first quarter of the book was a bit redundant but the rest was good.

I didn't care much for the author's condescending tone and attitude but if you look past that you'll see that the material he's presenting is of value.

 

 

 

Tuesday, March 13, 2012

Install an HttpModule in IIS 7.5 on Server 2008 R2

Mostly for my own notes for when I next need to do this again. Assumes that the HttpModule has already been compiled and that you have the DLL.

Copy the DLL to the server and put in any folder.

Install the module into the GAC

  1. Right click on a command window and select "Run as administrator"
  2. At the command prompt type "explorer c:\windows\assembly" without the quotes.
  3. Find the folder that you copied the DLL to and while holding down the control key right click this folder and select "Open in a new window".
  4. Drag the HttpModule DLL from the new window and drop it into the c:\windows\assembly window.
  5. The HttpModule is now installed in the GAC.

Add the module to IIS 7.5

(This assumes a .NET 2.0 module (there's a good reason why it's .NET 2.0 and not 4))

  1. Open IIS and navigate to root. This is usually the machine name and adding the module here will ensure that it operates on all websites.
  2. In the Features View find the IIS section and double click on Modules.
  3. Click "Add Managed Module"
  4. In the Name field put any name you want.
  5. In the Type dropdown you should find the module that you added to the GAC above. Select this.
  6. Leave the "Invoke only for requests to ASP.NET applications or managed handlers" unchecked.
  7. Click OK and you're done.

This HttpModule will now execute against every request on all web sites.

Thursday, January 19, 2012

Kintiskton LLC IP Ranges

There's a company called Kintiskton LLC who either own or are owned by Mark Manager and they provide a trademark protection service. They have a spider that crawls the web attempting to identify their customers' copyright material posted on sites other than their customers'. In principal I don't have a problem with this because I agree that copyright should be respected.

There's a good write-up about them here: http://endellion.me.uk/info/Kintiskton.html

The problem is that their spider aggressively spiders sites without respecting the robots.txt file. It hits the site hard and fast and ignores the crawl-delay directive and exclude directives. Ignoring the excludes directive is understandable (but not tolerable) as rouge web sites that are violating copyright could "hide" their content from respectful spiders by adding an exclude directive in the robots.txt file for that part of the site. This spider, however, also ignores the crawl-delay and is also not very well written as it generates a fair number of errors in the log files making it easy to see.

If you want to exclude this spider from your site you can exclude these IP ranges: 

65.208.151.112 - 65.208.151.119
63.110.158.48 - 63.110.158.55
65.200.47.0 - 65.200.47.7
65.208.189.24 - 65.208.189.31
65.208.185.96 - 65.208.185.103
65.211.195.16 - 65.211.195.23
5.208.151.112 - 5.208.151.119 (probably a mistake - see Zap's comment below)

If you discover another range that they are using please post as a reply to this blog post and I'll add it to the above list.