Antoine Aubry

Reinventing the wheel since 1990

8. March 2013 18:00
by aaubry
0 Comments

Configuring log4net ColoredConsoleAppender in code

8. March 2013 18:00 by aaubry | 0 Comments

var appender = new ColoredConsoleAppender
{
	Threshold = Level.All,
	Layout = new PatternLayout("%level [%thread] %d{HH:mm:ss} - %message%newline"),
};
appender.AddMapping(new ColoredConsoleAppender.LevelColors { Level = Level.Debug, ForeColor = ColoredConsoleAppender.Colors.Cyan | ColoredConsoleAppender.Colors.HighIntensity });
appender.AddMapping(new ColoredConsoleAppender.LevelColors { Level = Level.Info, ForeColor = ColoredConsoleAppender.Colors.Green | ColoredConsoleAppender.Colors.HighIntensity });
appender.AddMapping(new ColoredConsoleAppender.LevelColors { Level = Level.Warn, ForeColor = ColoredConsoleAppender.Colors.Purple | ColoredConsoleAppender.Colors.HighIntensity });
appender.AddMapping(new ColoredConsoleAppender.LevelColors { Level = Level.Error, ForeColor = ColoredConsoleAppender.Colors.Red | ColoredConsoleAppender.Colors.HighIntensity });
appender.AddMapping(new ColoredConsoleAppender.LevelColors { Level = Level.Fatal, ForeColor = ColoredConsoleAppender.Colors.White | ColoredConsoleAppender.Colors.HighIntensity, BackColor = ColoredConsoleAppender.Colors.Red });
appender.ActivateOptions();
BasicConfigurator.Configure(appender);

4. December 2012 14:57
by aaubry
0 Comments

Pingo Doce ajuda-nos a poupar

4. December 2012 14:57 by aaubry | 0 Comments

Há uns tempos falava-se que o Pingo Doce ia deixar de aceitar pagamentos por multibanco para valores inferiores a 20€. Como não sou cliente habitual dessa loja, nunca mais me lembrei desta questão. Hoje, passei à frente de uma loja Pingo Doce e lembrei de comprar umas cápsulas de café lá para o escritório. Depois de gastar algum tempo a escolher o tipo de cápsulas, ainda levei uma caixa de chocolates para partilhar com a malta e aguardei pela minha vez na fila. Quando sou finalmente atendido, ao tentar pagar, sou informado que não aceitam multibanco para pagamentos abaixo de 20€ e que o que podia fazer era sair da loja e ir apanhar chuva à procura de um multibanco. Não estava para isso pelo que me fui embora sem as minhas compras.

O bom disto tudo é que graças a esta política poupei dinheiro que, caso contrário, teria gasto em artigos supérfluos. Obrigado Pingo Doce!

14. November 2012 17:38
by aaubry
0 Comments

Interesting read: "Bring back the 40-hour work week"

14. November 2012 17:38 by aaubry | 0 Comments

I know a lot of people that should read this.

[...] knowledge workers actually have fewer good hours in a day than manual laborers do — on average, about six hours, as opposed to eight. It sounds strange, but if you’re a knowledge worker, the truth of this may become clear if you think about your own typical work day. Odds are good that you probably turn out five or six good, productive hours of hard mental work; and then spend the other two or three hours on the job in meetings, answering e-mail, making phone calls and so on. You can stay longer if your boss asks; but after six hours, all he’s really got left is a butt in a chair. Your brain has already clocked out and gone home.

20. September 2011 12:42
by aaubry
0 Comments

MBNet for Android

20. September 2011 12:42 by aaubry | 0 Comments

Notice: Due to a redesign of the MBNet site, this application no longer works. I hope to update it someday. In the meantime, don't bother downloading it.

The MBNet service

Those living in Portugal will be familiar with the MBNet service. It is a service that allows to use a Portuguese debit card to make payments in sites that accept credit cards only. In practice, you login with a user name and password, enter a maximum amount, and it generates a virtual credit card number that can be used for a single payment for up to the amount you specified. This service is very useful and I use it for most of the payments I make on the Internet.

Sometimes I need to make payments by credit card and the only trustworthy Internet access available is my Android phone. That is a problem because the MBNet site is not designed for small touch screens. It has a virtual keyboard that is a mess to use on a touch device. Not satisfied with this situation, I decided to create an Android application that could be used as a front-end for the Web site. The result can be seen in the following pictures.
MBNet1 MBNet2

Downloading the application

Warning: When you download applications from unknown sources, you are exposing yourself to a risk. Before using this application, think about the following risks:

  • Maybe this application sends your user name and password to some random hacker?
  • Even if you trust me, maybe the application has a bug that could expose your password?
  • This site might have been compromised and the application has been replaced with spyware?

In general, instead of downloading the application, you should download the source code, review it and then compile it yourself. In any case, I will not be held responsible if something happens to you after installing it.

If you are still interested, you can download the MBNet application here.

Implementation details

Since MBNet does not provide a publicly accessible API, which is understandable due to the nature of the service, I had to resort to Web scraping to implement the application. Web scraping consists of having a program interact with a Web site as if a real user was accessing it. This technique has some drawbacks. One of them is that even minor changes to the site can cause the application to break. Since there's no other way to do it, we will have to live with these potential problems.

A web scraper can be implemented in various ways. Some of them include:

  • performing HTTP requests to the site;
  • embedding a Web browser in the application.

After trying both techniques, I found that the Web browser solution was simpler because a Web browser already provides cookie management and javascript evaluation. Cookie handling is handy because we don't have to care about them while sending requests. Javascript was necessary because this Web site relies on client-side script to protect the user name and password of the user.

The Android platform provides the WebView control to display HTML pages. Opening a Web page is as simple as invoking loadUrl on the WebView:

webview.loadUrl("https://www.mbnet.pt/mbnetAut.html");

By default, javascript is disabled. We need to enable it using the following code:

webview.getSettings().setJavaScriptEnabled(true);

Interacting with the Web page

In order to do something useful, we need to be able to interact programmatically with the page. We will want to fill fields, submit forms and retrieve text. Usually, Web browser controls provide some way to manipulate the DOM and to invoke Javascript code on the page. WebView provides none of these. It allows to register objects that can be invoked from Javascript, but not the other way around. That is a problem because the pages that we are loading know nothing about our objects, therefore they won't invoke their methods.

Fortunately, it is possible to use a trick to work around the limitations of the WebView. If we tell the WebView to navigate to a javascript: url, the browser will execute the code after the semicolon in the context of the current page. This is how bookmarklets are implemented. This allows to do the following:

webview.loadUrl("javascript:eval('document.write(\"hello world\")')");

However, if we want to execute non-trivial code, this approach becomes hard to manage. To fix that I registered a javascript interface with a method that returns the actual script to execute, and the navigate code simply invokes that method and evaluates the resulting script. The following snippet illustrates that method.

webview.addJavascriptInterface(new Object() {
	public String getScript() {
       		// The code can be obtained from a resource or whatever
       		return "document.write('hello world');";
       	}
}, "itf");

webviewloadUrl("javascript:eval('' + itf.getScript())");

Conclusion

After finding out how to communicate with the page inside the WebView, it proved a viable solution for implementing Web scraping. I encourage you to read the source code for more details.

License

This program, along with its source code, is free software. You can use it under the terms of the GNU GPL license. For more information please consult the license.txt file inside the source distribution.

17. August 2011 03:04
by aaubry
0 Comments

Controlling ViewState size

17. August 2011 03:04 by aaubry | 0 Comments

For those of you still using ASP.NET Web Forms, here is a handy utility. The ViewState is a handy mechanism of ASP.NET that allows a page to preserve state between postbacks. The default implementation stores the content of the ViewState in a hidden field that is included in the page. When a postback occurs, the value of that field is sent back to the server, allowing it to recover its previous state.

However useful the ViewState may be, it may cause some problems. If too much data is stored in it, it can grow out of control and significantly slow down the page loads. I have created a GreaseMonkey script that helps keeping the ViewState under control by displaying its size in the bottom of every page.

ViewStateSize

Download the script here

Download the script on userscripts.org

8. August 2011 14:42
by aaubry
0 Comments

ASP.NET Errors Linkifier

8. August 2011 14:42 by aaubry | 0 Comments

When developing ASP.NET applications, it is frequent to get errors that show a stack trace. The stack trace includes the files and line numbers of the functions that caused the error. This extension adds links that open your favorite editor when clicked. The default editor is Visual Studio 2010, but this can be changed in the extension options.

preview

28. December 2010 04:27
by aaubry
0 Comments

Fixing jumping content when scrollbars appear

28. December 2010 04:27 by aaubry | 0 Comments

In Web sites that use centered layouts, like mine, the page content seems to jump from left to right when navigating between some pages, or expanding content on a page. This happens because some pages are taller than other, causing the vertical scrollbar be present only in some cases. Because the vertical scrollbar takes some space on the page, the centered layout is shifted a few pixels. The screenshots below illustrate this issue. The top one is from a page with no scrollbar. The bottom one is from the same site but has a scrollbar. Notice that, although the content is centered on both pages, the bottom content is shifted to the left relative to the top content.

NoScroll

Scroll

I don't like this behavior and will show a method for fixing it.

After some research, I found that the usual fix is to ensure that the vertical scrollbar is always visible. This is done using the overflow-y css property. While this prevents the jumping content, the downside is that the vertical scrollbar is always visible, even when there is no content to scroll to. I think we can do better.

My approach is to use javascript to reposition the content of the page while taking into account the visibility of the scrollbar. For that, we need to know if the scrollbar is visible and its width. If it is visible, we can adjust the position of the content. Note: I am using jQuery, but it is easy to convert the code to pure javascript if needed.

There is no direct way of knowing the size of the scrollbar and whether it is visible. The trick is to disable the scrollbar using overflow:hidden, measure the width of the body element, re-enable the scrollbar using overflow:auto and measure the width of the body element again. The difference between the measured widths is the width of the scrollbar. If the difference is zero, then the scrollbar is not visible at that moment.

// This script fixes the shift that occurs in a centered layout when the page grows and forces scrollbars to appear.
$(function () {
	var body = $("body");

	var previousWidth = null;

	// Function that applies padding to the body to adjust its position.
	var resizeBody = function () {
		var currentWidth = body.width();
		if (currentWidth != previousWidth) {
			previousWidth = currentWidth;

			// Measure the scrollbar size
			body.css("overflow", "hidden");
			var scrollBarWidth = body.width() - currentWidth;
			body.css("overflow", "auto");

			body.css("margin-left", scrollBarWidth + "px");
		}
	};

	// setInterval is required because the resize event is not fired when a scrollbar appears or disappears.
	setInterval(resizeBody, 100);
	resizeBody();
});

1. September 2010 06:50
by aaubry
0 Comments

Undo checkout on unchanged files (TFS)

1. September 2010 06:50 by aaubry | 0 Comments

One thing that drives me crazy with TFS is the fact that if you have a file checked out, but you made no changes to it, it still shows as a change, distracting you from real changes that you made. This is especially annoying when you use tools such as T4 to generate code, because most of the time the tool will generate the same code, but will leave the file checked out.

For some reason that I can't understand, Visual Studio insists in showing those as changes, and will even claim that there are conflicts if another person happened to check-in the same "changes".

Fortunately, the TFS Power Tools include a command that compares checked-out files with the server version and undoes the unchanged files. I will explain how to integrate it into Visual Studio using a custom tool.

Integration into Visual Studio

First we need to install TFS Power Tools. Simply go to the download page and install it from there. Once it is done, we need to create a custom tool to run it.

In Visual Studio, go to the Tools/External Tools menu. In the dialog that appears, click on Add, then enter the following values:

FieldValue
Title &Undo fake changes
Command %windir%\System32\cmd.exe
Arguments /C echo y | "%ProgramFiles(x86)%\Microsoft Team Foundation Server 2010 Power Tools\TFPT.EXE" uu /recursive /noget
Initial directory $(SolutionDir)

Then check the "Use Output Window" option and click on OK.

UPDATE: Do not check "Use Output Window" because that prevents TFS Power Tools from prompting you for your credentials.

In order to run the command, go to Tools/Undo fake changes.

31. May 2010 15:55
by aaubry
0 Comments

RightKeyboard

31. May 2010 15:55 by aaubry | 0 Comments

Introduction

My laptop has a Portuguese keyboard which I use when I am at home, but at work, I use an external keyboard with a Belgian layout. This is annoying because every time I switch keyboards, I need to go to every open program and manually change its input language with the language bar. Worse, when I start a new program, it starts with the default language, which means that sometimes I have to switch input language also.

One way to work around this problem could be to buy a new keyboard, but I like the IBM model M keyboard and I have yet to find a better keyboard.

Instead of doing that, I wrote a program that switches to the correct input language when I start using a keyboard.

Background

Although more than one keyboard may be connected to the same computer, the Win32 API treats them as if there was only one keyboard. A program receives key strokes from every keyboard, but has no way of knowing which keyboard sent a particular stroke.

Usually, this is exactly what the program wants. It is the role of the Operating System to shield the program from the complexity of dealing with multiple input devices. But in this case, we need to know which device has been used in order to switch the input language. Luckily, the raw input API exposes which device is sending the messages, which solves our problem.

How it works

Describing the raw input API is outside of the scope of this article. The MSDN documentation already provides plenty of information about it. We will stick to the essential. The API allows a program to register to receive notifications each time a keyboard sends an event. When the notification is received, the program checks if it comes from a different device than the previous one. In that case, the program selects the appropriate input language and broadcasts the WM_INPUTLANGCHANGEREQUEST message so that open programs change their input language. Additionally, the default input language is updated using the SystemParametersInfo function, which causes new programs to start with the correct input language.

When a keyboard is used for the first time, the program asks the user which language is to be used. When the program is closed, a file is saved in %USERPROFILE%\Local Settings\Application Data\RightKeyboard that contains the associations between the device identifiers and the input languages. When the program starts, that information is loaded so that the program already knows the correct language for any previously used keyboard.

Using the program

The program is easy to use. Simply run it and an icon will appear in the notification area. The icon allows to close the program when right-clicked. The first time a keyboard is used, a popup will appear with a list of the available input languages. Select the correct language, then click OK. From now on, each time that keyboard is used, every application will switch to that language. More input languages can be added in the Regional and Language Options on the Control Panel.

You can download the program from the CodeProject page where I originally published this article.

Known Limitations

There are some limitations that more work could probably overcome:

  • Console windows do not switch language when they receive the WM_INPUTLANGCHANGEREQUEST message. Any such window that is already open when the program switches the input language will keep the current language.
  • When the program switches the input language, the currently focused window receives the key before the change. Because of that, the first key that is pressed on another keyboard is always incorrect, unless that particular key is the same on the previous language.
  • After hibernating, the device handles become invalid, which makes the program ask the language for a previously known keyboard.