Archive

Author Archive

Building a Custom Defect Submitter for qTrace

May 10th, 2012 Buu Nguyen No comments

Code for my new blog post in QASymphony’s Blog.

namespace FtpSubmitter
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    using Iris.Trackers.Contracts;

[Export(typeof(IBugTracker))]
    public class Ftp : IBugTracker
    {
        public string DisplayName
        {
            get { return "FTP Submitter"; }
        }

        public string IconUri
        {
            get { return "/FtpSubmitter;component/ftp.png"; }
        }

        public string Verify(BugTrackerAccount bugTrackerAccount,
                             int timeoutInMillis,
                             IDictionary<string, string> settings)
        {
            var ftpRequest = (FtpWebRequest)WebRequest.Create(bugTrackerAccount.Url);
            ftpRequest.Credentials = new NetworkCredential(bugTrackerAccount.UserName,
                                                           bugTrackerAccount.Password);
            ftpRequest.Timeout = timeoutInMillis;
            ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
            using (ftpRequest.GetResponse())
            {
                return "Connected to FTP server successfully!";
            }
        }

        public SubmittedDefect Submit(Window owner,
                                      BugTrackerAccount bugTrackerAccount,
                                      int timeoutInMillis,
                                      Defect defect,
                                      Func<IDictionary<string, byte[]>> attachmentsFunc,
                                      IDictionary<string, string> settings)
        {
            Mouse.OverrideCursor = Cursors.Wait;
            try
            {
                var tasks = from attachment in attachmentsFunc()
                            select Task.Factory.StartNew(
                                () => Upload(bugTrackerAccount, timeoutInMillis,
                                             attachment.Key, attachment.Value));
                Task.WaitAll(tasks.ToArray());
                return null;
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }

        private void Upload(BugTrackerAccount bugTrackerAccount,
                            int timeoutInMillis,
                            string filePath,
                            byte[] fileContent)
        {
            var uri = bugTrackerAccount.Url +
                      (bugTrackerAccount.Url.EndsWith("/") ? string.Empty : "/") +
                      Path.GetFileName(filePath);
            var ftpRequest = (FtpWebRequest)WebRequest.Create(uri);
            ftpRequest.Credentials = new NetworkCredential(bugTrackerAccount.UserName,
                                                           bugTrackerAccount.Password);
            ftpRequest.Timeout = timeoutInMillis;
            ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
            using (Stream writer = ftpRequest.GetRequestStream())
            {
                writer.Write(fileContent, 0, fileContent.Length);
            }
        }
    }
}
Categories: Uncategorized Tags: ,

Bike has a homepage!

May 3rd, 2012 Buu Nguyen No comments

Had some fun with Python

May 1st, 2012 Buu Nguyen No comments

By now, you should have already known I love programming languages, to the extent that I even created one myself. One of the languages I want to learn this year is Python. My first Python program is a port for the Semicolon language. The code is also available in github with examples.

# coding: utf-8

def tokenize(code):
	import re
	ops = {
	  ';;;':  { 'code': 'push', 'arg': 'signed'},
	  ';;⁏':  { 'code': 'dup' },
	  ';⁏;':  { 'code': 'swap' },
	  ';⁏⁏':  { 'code': 'discard' },
	  '⁏;;':  { 'code': 'add' },
	  '⁏;⁏':  { 'code': 'sub' },
	  '⁏⁏;':  { 'code': 'mul' },
	  '⁏⁏⁏':  { 'code': 'div' },
	  '⁏  ':  { 'code': 'mod' },
	  '; ;':  { 'code': 'store' },
	  '; ⁏':  { 'code': 'retrieve' },
	  ' ;;':  { 'code': 'label', 'arg': 'unsigned' },
	  ' ;⁏':  { 'code': 'call', 'arg': 'unsigned' },
	  ' ; ':  { 'code': 'ret' },
	  ' ⁏ ':  { 'code': 'jump', 'arg': 'unsigned' },
	  ' ⁏;':  { 'code': 'jz', 'arg': 'unsigned' },
	  ' ⁏⁏':  { 'code': 'jn', 'arg': 'unsigned' },
	  '  ;':  { 'code': 'exit' },
	  '⁏ ;;': { 'code': 'outchar' },
	  '⁏ ;⁏': { 'code': 'outnum' },
	  '⁏ ⁏;': { 'code': 'readchar' },
	  '⁏ ⁏⁏': { 'code': 'readnum' },
	}

	make_int = lambda str:int(''.join('0' if c == ';' else '1' for c in str), 2)
	while code and code != '\n':
		has_match = False
		for key in ops:
			pattern = (key + (r'([;⁏]*)\n' if 'arg' in ops[key] else '()') + r'(.*)$').decode('utf8')
			match = re.match(pattern, code, re.S)
			if match:
				has_match = True
				code = match.group(2)
				if 'arg' in ops[key]:
					if ops[key]['arg'] == 'unsigned':
						tokens.append([ops[key]['code'], make_int(match.group(1))])
					elif ops[key]['arg'] == 'signed':
						tokens.append([ops[key]['code'],
									   (1 if match.group(1)[0] == ';' else -1) * make_int(match.group(1)[1:])])
				else: tokens.append([ops[key]['code']])
		if not has_match:
			raise Exception('Unknown command')

def step():
	global pc
	op = tokens[pc][0]
	arg = None if len(tokens[pc]) == 1 else tokens[pc][1]
	pc += 1
	if op == 'push':
		stack.append(arg)
		step()
	elif op == 'dup':
		stack.append(stack[-1])
		step()
	elif op == 'swap':
		stack[-1], stack[-2] = stack[-2], stack[-1]
		step()
	elif op == 'discard':
		stack.pop()
		step()
	elif op == 'add' or op == 'sub' or op == 'mul' or op == 'div' or op == 'mod':
		bin_ops = { 'add': '+', 'sub': '-', 'mul': '*', 'div': '/', 'mod': '%' }
		stack.append(eval(str(stack.pop()) + bin_ops[op] + str(stack.pop())))
		step()
	elif op == 'store':
		heap[stack[-2]] = stack[-1]
		stack.pop(); stack.pop()
		step()
	elif op == 'retrieve':
		stack.append(heap[stack.pop()])
		step()
	elif op == 'label':
		step()
	elif op == 'call':
		call_stack.append(pc)
		jump(arg)
	elif op == 'ret':
		pc = call_stack.pop()
		step()
	elif op == 'jump':
		jump(arg)
	elif op == 'jz':
		if stack.pop() == 0: jump(arg)
	elif op == 'jn':
		if stack.pop() < 0: jump(arg)
	elif op == 'exit':
		sys.exit()
	elif op == 'outchar':
		print chr(stack.pop())
		step()
	elif op == 'outnum':
		print str(stack.pop())
		step()
	elif op == 'readchar':
		stack.append(ord(sys.stdin.read(1)))
		step()
	elif op == 'readnum':
		stack.append(int(sys.stdin.readline()))
		step()
	else: raise Exception('Unknown opcode')

def jump(label):
	global pc
	for index, token in enumerate(tokens):
		if token[0] == 'label' and token[1] == label:
			pc = index
			break
	step()

import sys
if len(sys.argv) == 2:
	tokens = []; pc = 0; heap = {}; stack = []; call_stack = []
	tokenize(open(sys.argv[1], 'r').read().decode('utf8'))
	step()
else: print 'Usage: python semicolon.py [file.sc]'

Posts on software testing

March 3rd, 2012 Buu Nguyen 1 comment

I’ve written a series of blog posts in my company’s blog.  Links here for references:

Any plugin to automatically synchronize posts between 2 blogs by same author?

The Bike Programming Language

February 19th, 2012 Buu Nguyen 7 comments

Bike is a programming language that I develop.  I worked on this interesting toy project a while ago.  I was hoping to have had time to improve it further (plenty of things I want in a language) before announcing it in my blog.  However, work at my new startup has been so hectic (surprise, surprise…) that I can hardly find time to continue, so I guess I just put it out to the public and get everyone’s opinions.

In a nutshell, Bike is an interpreted language running on Windows and Mac/Linux (via Mono).  I developed Bike with the intention of building a language feel most natural by me so that I can use for daily programming tasks.  And since the existing languages that already feel natural to me are Ruby, JavaScript and C#, no surprise that these languages influenced Bike a great deal.  From the language perspective these are the important characteristics of Bike:

  • Dynamic and strong typing
  • Everything is an object
  • Prototypal inheritance
  • First-class function
  • CLR interoperability

No further ado, here’s some Bike.  First, hello world.

print 'Hello, world!'

Everything is object (note that the print function is passed as argument)

10.times( print );
0.upto( 10, print );

Calculating Fibonacci (return keyword is optional, semicolon is optional in the last statement of a block)

func fib( n ) {
    n <= 2 ? n : fib( n - 1 ) + fib( n - 2 )
}
print( "n: " );
var n = readln();
println( fib( n.to_number() ) );

Self-executing function

( func() {
    println( 'executed' );
} )();

Closure

var f = ( func( a, b ) {
     var c = 1;
     return func() { a + b + c };
} )( 2, 5 );
println( f() );

Currying

Bike.Function.curry = func( *args ) {
	if ( args == null || args.size() == 0 ) return this;
	var me = this;
	return func( *more ) {
		if ( more != null )
			args.add_all( more );
		me.call( this, *args );
	};
};

func add( a, b ) { a + b }
var addTo2 = add.curry( 2 );
println( addTo2( 3 ) );

add = add.curry( 2, 3 );
println( add() );

Var-args and array expansion

func add_all( *numbers ) {
    numbers.reduce( 0, func( current, ele ) { current + ele; } );
}
println( add_all( 1, 2, 3 ) );
println( add_all( 1, 2, 3, 4 ) );

var arr = [ 1->10 ];
println( add_all( *arr ) );

Inheritance

var Person = {
    initialize: func( name ) {
        this.name = name;
    },
    to_string: func() {
        this.name;
    }
};

# clone person and invoke initialize on the new obj
var buu = Person.create( 'Buu' );
buu.fav_language = "Bike";
buu.to_string = func() {
    this.super( 'to_string' ) + "'s favorite language is " + this.fav_language;
};
println( buu );

.NET Interoperability

var list = System.Collections.ArrayList();
[ 0->9 ].each( func( i ) { list.Add( i ); } );

for ( var e in list ) print( e + ', ' );

0.upto( list.Count, func( i ){println( list[ i ] );} );

Dynamic code evaluation

var code = 'println( "This is cool!" );';
exec( code );
code = '2 * 3;';
println( exec code );
code = 'var person = {name: "John"};';
println( ( exec code ).name );
println( person.name );

There are more interesting features, but I guess that’s enough for you to get a feel of Bike. if/else/while/for/switch/rescue are all available but they are probably not needed much.  Bike also comes with a minimal base class library to work with file system, multithreading, HTTP, JSON, regex, unit test etc.  All these are written in Bike itself (mostly .NET wrapper since it’s fast to implement although pure native implementation would be interesting).

Go to https://github.com/buunguyen/Bike and check out the samples folder for more.  Interested?  Fork and contribute to the language and/or base class library.  Questions, ideas and feedback, please comment or email (see About).  Thanks and happy biking!

Paint War is released!!

December 22nd, 2011 Buu Nguyen 2 comments

This is the release month! After qTrace, another product I spent much mind and heart on for many months has just been released: Paint War, the super fun and addicted (shamelessly biased!) iPad game.  Visit Paint War’s website or iTunes App Store to learn more about Paint War.  And don’t forget to give it a try!

Paint War

PaintWar

PaintWar

PaintWar

PaintWar

qTrace is released!

December 5th, 2011 Buu Nguyen 2 comments

After quite some time working on it, we finally released qTrace 1.0, the defect reporting tool you want to have ;) .

To find out more and download the trial version, please visit http://www.qasymphony.com.

Pro iOS Apps Performance Optimization

December 3rd, 2011 Buu Nguyen No comments

My former student and colleague, Khang Vo, has just published a book on iOS performance optimization. Congratulations to him!

Categories: Mobile Tags: , ,

Fun with HTML5 canvas

November 14th, 2011 Buu Nguyen No comments

Demonstrating Canvas API…

var Point = function(x, y) {
	this.x = x;
	this.y = y;
}

var Circle = function(pos, dir, color, radius) {
	this.pos = pos;
	this.dir = dir;
	this.color = color;
	this.radius = radius;
};

Circle.prototype.move = function(speed, w, h) {
	this.pos.x += this.dir.x * speed;
	if (this.pos.x < 0) {
		this.pos.x = 0;
		this.dir.x = -this.dir.x;
	} else if ((this.pos.x + this.radius*2) > w) {
		this.pos.x = w - this.radius*2;
		this.dir.x = -this.dir.x;
	}

	this.pos.y += this.dir.y * speed;
	if (this.pos.y < 0) {
		this.pos.y = 0;
		this.dir.y = -this.dir.y;
	} else if ((this.pos.y + this.radius*2) > h) {
		this.pos.y = h - this.radius*2;
		this.dir.y = -this.dir.y;
	}
};

Circle.prototype.draw = function(context) {
	context.beginPath();
	context.arc(this.pos.x + this.radius, this.pos.y + this.radius, this.radius, 0, Utils.degreesToRadians(360), true);
	context.fillStyle = this.color;
	context.fill();
};

var Frame = function(canvasId, numberOfCircles) {
	this.canvas = document.getElementById(canvasId);
	this.speed = 1;
	this.numberOfCircles ||= 5;
	this.circles = [];
};

Frame.prototype.start = function() {
	for (var i = 0; i < this.numberOfCircles; i++) {
		this.addBall();
	}
	var self = this;
	setInterval(function() { self.update(); }, 25);
};

Frame.prototype.speedUp = function() {
	this.speed++;
};

Frame.prototype.addBall = function() {
	var circle = new Circle(Utils.randPos(this.canvas.width, this.canvas.height), Utils.randDir(), Utils.randColor(), Utils.randRadius());
	this.circles.push(circle);
};

Frame.prototype.update = function() {
	var canvas = this.canvas;
	var context = canvas.getContext("2d");

	context.clearRect(0, 0, canvas.width, canvas.height);
	context.strokeStyle = '#000000';
	context.strokeRect(0, 0, canvas.width, canvas.height);

	for (var i = 0; this.circles[i]; i++) {
		var circle = this.circles[i];
		circle.move(this.speed, canvas.width, canvas.height);
		circle.draw(context);
	}
};

var Utils = {
	degreesToRadians: function(degrees) {
		return (degrees * Math.PI) / 180;
	},

	randDir: function() {
		return new Point((Math.random() > 0.5 ? 1 : -1) * Math.random(),
						 (Math.random() > 0.5 ? 1 : -1) * Math.random());
	},

	randPos: function(w, h) {
		return new Point(Utils.rand(w), Utils.rand(h));
	},

	randColor: function() {
		var letters = '0123456789ABCDEF'.split('');
	    var color = '#';
	    for (var i = 0; i < 6; i++ ) {
	        color += letters[Utils.rand(15)];
	    }
	    return color;
	},

	randRadius: function() {
		return Utils.rand(5) + 5;
	},

	rand: function(max) {
		return Math.round(Math.random() * max);
	}
};

Array.prototype.each = function(f) {
	for (var i = 0; this[i]; i++) f(this[i]);
};

window.onload = function() {
	var frames = [new Frame("canvas1"), new Frame("canvas2")];
	frames.each(function(f) { f.start(); });

	document.getElementById("btnAddSpeed").onclick = function() {
		frames.each(function(f) { f.speedUp(); });
	};

	document.getElementById("btnAddBall").onclick = function() {
		frames.each(function(f) { f.addBall(); });
	};
};

Place that script in a page with these elements

<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
<br/>
<input type="button" id="btnAddSpeed" value="Add Speed">
<input type="button" id="btnAddBall" value="Add Balls">
Categories: Uncategorized Tags: , ,

Training screen casts (in Vietnamese) about C#, ASP.NET MVC, LINQ and Combres

August 15th, 2011 Buu Nguyen 7 comments

The series of MVC/C#/LINQ/Combres screen-casts (in Vietnamese) I produced for Microsoft Vietnam a while a go. Microsoft Vietnam recently allowed CiOne to distribute on their website so that everyone can access for free.