A Dutch software developer living in Chile

Monday, June 15, 2009
Sewer troubles
Our sewer is at it again. One big mess, and the exit pipe completely broken. Before you say: “Yuck”, we noticed the problem before the toilets stopped working. (Luckily!)
A few months ago, we had a problem that our sewer was clogged up, and it was clogged up pretty badly. They used (like usual) high pressure to remove the obstruction, but since then, the ground on the outside of our sewer pit started to sink slowly…
We didn’t notice this until a few weeks ago, when the Esso came here to fill up our Diesel tank for the heater. (We heat our house and the water on Diesel.) Since the Diesel tanker uses a hose of more than 30 meters which goes all the way to the back of our house from the street, we need to walk over that same spot that the sewer pit is at… and guess what? That is when I noticed the ground started to cave in. I took a step and I was standing up to my knees in the ground. (They joked about that, because they said I was simply too heavy) but I thought to myself, this can’t be good.
Last Saturday I was taking my usual shower and I noticed that the toilet was making a funny bubbling sound. Now I knew that the air coming from the toilet was coming straight out of the sewer, making place for the water I was putting in. So I asked Tatiana (my wife) to check with the water company (Aguadecima) to let them do the usual unclogging.
Today we called them, and they came. My suspicion was right. The sewer pit was almost filled up to the top, the pipe to the street is broken and they will replace it this week. That’s going to be some digging, but at least we have some space in the pit that can be filled now, because they were able to once-again remove some obstruction that was causing this mess.
And the nicest part? All of this is done for free! They react quick, and don’t charge a dime. If the problem lies between the pit and the house, it’s our problem. From the pit to the street, including the pit itself, is the problem of the county. This is needless to say, they respond quickly. Once they start digging, I’ll shoot some pictures :)
Monday, June 15, 2009 5:26:50 PM (Pacific SA Standard Time, UTC-04:00)
Chilean Adventures
Opera and the anti-trust case
First of all, this is my blog where I vent my own opinion. I’m not impartial, nor am I a judge, jury, or anything else on that kind. Having said that, if you don’t agree with me, that’s fine. If you do, that also fine. :)
The anti-trust case was started by Opera simply because they lack the market share and are now trying to get a competitive edge by letting their browser be included in the world’s most popular operating system. The question that this will raise: “Is this fair?”
Microsoft worked hard on Windows 7, Internet Explorer 8, and all other software that goes with it. (Media player, Media center, etc.) They invested millions into these products. Anyone who’s willing to buy this will have a secure, reliable, piece of software and once a bug is discovered which compromises security even the slightest, everything is done to plug the hole as soon as possible.
If I install any well-known Linux distribution on my PC, does it come with a browser? Sure it does. Does it come with Internet Explorer? Of course not. Embedding closed-source apps into a open-source OS would cause a small revolution here and there, but besides that, Microsoft does not allow it. Their licensing agreement does not allow you to simply install their browser on any other platform than the ones they say it may be installed on. Even several Windows versions do not meet this criteria. For example: Windows 200, Windows 9x/Me and Windows NT can only be used with IE6 and lower. IE7 and higher are not working on those operating systems.
So there’s no competition for Internet Explorer between Windows and Linux. Since there is an Opera version for Mac OS X, Linux, FreeBSD, Solaris, QNX, OS/2 and what-have-you even BeOS, they should have plenty of market share to go on, right?
But this still doesn’t answer the question: “Is this fair?”
Microsoft is willing to strip-out it’s browser of Windows for the European market, the so-called “E” edition. That means: deliver Windows without any browser. How you’re going to get a browser if you don’t have a browser? The consumers will be hard-hit with this, and OEMs will be eventually making the choice to install the browser for the customer, which is (you guessed it) probably Internet Explorer anyway. This will lead to higher costs and even frustration on the end-user’s behalf. Not a good thing. It’s even worst, because the “E” Edition will be the only edition that will be available in the European market.
Does this help Opera? Or will it help other browsers, like Chrome, FireFox, etc? Guess 3 times. The average home user doesn’t give a damn which browser they use, as long as it works. Businesses care about 3 things though: “Can it be managed?”, “Does it work with the solutions I use?” and “Is it safe?”
All browsers claim to be “the safest”, “the fastest”, and so on, and Opera is no exception in this case. Clearly this is where Apple has a lot to learn, since Safari seems to be the easiest browser to hack yet. But this is besides the point of this article. Fact of the matter is, most business applications were historically built for Internet Explorer. I can remember the phrase “IE Only” like it was told yesterday. These days web standards become better implemented and the differences between browsers gets less and less, but still, there are differences.
Most businesses will not change easily from IE6 to IE7, or from IE7 even to IE8. But they certainly won’t change that easy from IE to FireFox or … Opera? I can hear the manager saying: “But isn’t that that lady on TV?” Businesses will simply say: “I have better use for my time” and will not give it any more thought.
Home users? They will stay with what they find best working for their daily activities. If that means Internet Explorer, they might as well stick with it.
But this still doesn’t answer the question: “Is this fair?”
OK. Now back to the real heart of the issue. IS THIS FAIR? To force Microsoft to include Opera into Windows 7. No it is NOT. Several reasons:
Windows is Microsoft’s property, they decide what they want to do with it. If they want to include someone else’s products, fine, if not, then not. It should be their decision, not anyone else’s.
Including other company’s software in your own products can have huge implications. If a security leak is detected in Opera, who must fix it? Opera? Microsoft? You would say “Opera of course”, but wasn’t Microsoft who delivered that browser in the first place? This leads to confusion, problems and ultimately a bad reputation.
Internet Explorer is also Microsoft’s property. Why may they not include it in Windows for free? Ah, but the EU says, you’re charging for this in the Windows license fee. So even if they do, make it worst. Pay the same price and get less for your money. I can bet that Windows will not be any cheaper.
My conclusion is that Opera kind of ruined it for everyone in Europe. They started out to gain market share, and they probably made the end-user experience a lot more problematic and will probably not gain much in the end. That together with people now paying more for the same machine for the extra work that’s involved.
Way to go Opera!
Monday, June 15, 2009 2:51:27 PM (Pacific SA Standard Time, UTC-04:00)
Opinions

Sunday, June 14, 2009
Oh dear…
Does that mean I need to Twitter more often? ;)
Sunday, June 14, 2009 6:52:33 PM (Pacific SA Standard Time, UTC-04:00)

Friday, June 12, 2009
Silverlight 3 in the making
I haven’t blinked… yet, and there’s a new Silverlight version. After listening to Hanselminutes I notice that Microsoft is trying to start with out-of-the browser cross-platform applications, which is Silverlight 3. The beta you can download here: http://silverlight.net/getstarted/silverlight3/default.aspx Silverlight 3 will be integrated into Blend 3, which is also a free beta download.
I guess this will be the answer to Adobe AIR (or Adobe Integrated Runtime). Air uses Flex and Flash, HTML, JScript and AJAX, Silverlight 3 uses a mini CLR, JScript and XAML.
I’m by no means a Silverlight expert, nor AIR for that matter, so I guess this means that I’ll have something more to study. First WPF though…
Friday, June 12, 2009 11:04:06 AM (Pacific SA Standard Time, UTC-04:00)

Thursday, June 11, 2009
Mail wasn’t working…
I had just solved a nasty error, which was a interesting chain of events. My mail wasn’t delivered to the Netherlands, and the mail wasn’t coming in. Upon checking what was going wrong, I got a DNS error.
Checking the DNS server, it said: “Can’t bind to IP address X on interface Y”. Taking out netstat to see who was listening on port 53 (the default DNS port), I found that this was only the DNS server… strange… restarted the server, same problem.
Time to check the IP configuration, guess what? The static IP address assigned to this machine was a duplicate. After some server hunting, I found the offender, which has a different IP address now. Restarted the DNS server for a second time, and the mail started coming in.
Thursday, June 11, 2009 10:22:44 AM (Pacific SA Standard Time, UTC-04:00)

Wednesday, June 10, 2009
Visual Studio 2010 Beta 1 – First thoughts
I’ve been using Visual Studio 2010 for a few days now and I must say, I’m impressed. The version I’ve been using is the Team Suite version, Beta 1. I really like the multi monitor support as well as the possibility to zoom in on text and the fact that Visual Studio is now built using WPF makes Visual Studio 2010 a complete new experience. It is notably slower than the 2008 version though, it doesn’t feel as snappy as what 2008 did. With 2010 you get a new .Net Framework, but I’m not going into new features of .Net 4.0 in this post. In stead I’ll concentrate on the IDE. Some random thoughts:
- The code editor has improved a lot, as has Intellisense. Documents can be dragged out of the main window and be put anywhere, even full-screen on a different monitor. You can zoom in- and out of text, park the cursor onto a variable/member and see where it is referenced, refactoring is improved and you can toggle Intellisense between standard mode and consume-first mode.
- ClickOnce has changed a bit, and a some UI options have been taken away, especially in the partial trust area. There are still ways around this though, but it means a bit more hand-work. For the rest, not much noticeable in this part, if I forgot something, please let me know.
- The icons used in the UI are still the same as the last version, I guess they had their hands full rewriting the IDE. (And there are a LOT of icons in Visual Studio!) This doesn’t bother me though, functionality I think is way more important.
- No project templates for Office 2003… Options have been taken out as well… I guess that was to be expected since Office 2003 is out of mainstream support, but I’m a bit sad about it since some of my projects still use Office 2003 integration. Maybe there’s a way around this, I have no clue.
- F# Made it into Visual Studio. IronPyton and IronRuby haven’t? Probably an add-on
- New UML Modelling project, no idea how to use it though :)
Except all of this, extensibility and the new Team Foundation Server is there. Team build uses Workflow Foundation, and gated check-ins, so on that part we’ll probably see more improvement as well.
All in all, a fine release.
Wednesday, June 10, 2009 5:40:03 PM (Pacific SA Standard Time, UTC-04:00)

Tuesday, June 09, 2009
.Net 4.0 – No longer the layer-cake model, no longer the CAS policy
.Net 4.0 comes with a set of changes, that makes development and management of software a lot easier. There have been changes in the security model of .Net 4.0, the CLR itself and the layer-cake model is more or less gone because this is a new side-by-side release. Let’s take things step by step and let me tell you the changes I have seen so far…
Changes in security
The CAS policy is … gone. Say what? Everything runs as full trust now? Er… no, but there are a lot of changes. To sum them up, this is what it’s going to be:
- By default, unhosted applications are not subject to managed security policy when you run under 4.0. Effectively, this means any managed application that you launch from the command prompt or by double clicking the .exe in Windows Explorer will run fully trusted, as will all of the assemblies that it loads (including assemblies that it loads from a location other than the the directory where the executable lives).
- Applications that host .Net applications (like Internet Explorer for example) still can sandbox code. Also AppDomains can be used to sandbox code in. The difference is: the host decides now which permissions the application gets, not the CAS policy.
- When using Assembly.LoadFrom in a manner that .Net 3.5 and before would cause to sandbox the assembly, but .Net 4.0 won’t, a FileLoadException is thrown. (Inner exception will read “NotSupportedException”)
All this makes management of applications a lot easier and .Net applications will work more predictable.
Source: Shawn Farkas
The layer-cake model is gone
The layer-cake model was that a new version of .Net was built “on top” of a previous version and this way adding functionality. This is not the case with .Net 4.0. .Net 4.0 can co-exist with .Net 2.0, 3.0 and 3.5 and applications that host .Net solutions can host both 2.0-3.5 and 4.0 side by side in the same process. This last part wasn’t possible with .Net 1.0, 1.1 or 2.0. .Net 3.0 was essentially built “on top” of 2.0, the CLR didn’t change in that time. .Net 3.5 was built on top of .Net 3.0, adding functionality but not changing the CLR significantly. (Both did service pack the lower releases though ;))
A new language – F#
F# is a language which already existed for a long time, but wasn’t delivered with Visual Studio. Now, F# will make it into the Visual Studio package, bringing the total of the Microsoft .Net Languages up to 7 (C#, VB.Net, J#, C++.Net, JScript.Net, IronPyton and IronRuby) (If I forgot one, please let me know.)
A new version of C#
C# get a bunch of new language features (also VB.Net will see these things, but I’m more a C# guy) which will include:
- The dynamic keyword (finally!)
- Optional parameters (again, finally!)
- The no-PIA feature
- Co- and contra variance (also great)
This makes C# again a lot easier to work with.
Client Profile versions of .Net
Not really new to .Net 4.0 (.Net 3.5 included this already) is a client profile version, which is essentially a stripped-down version of .Net for client applications. Things like Windows Services, code compiler routines, web services, remoting and so on are not included in the client profile, because they are typically not needed. Also .Net 4.0 will have a client profile version of .Net which allows to distribute .Net with a smaller footprint.
Server core version of .Net
When Windows Server 2008 R2 is release, a server core version of .Net will be available. This will be both for .Net 2.0 and higher. Probably .Net 4.0 will also be available for server core, although there’s no news on this yet. .Net on core does have it’s advantages, because you can use IIS7 with ASP.Net or run application services on server core.
Threading improvements
Now, when .Net software wants to use multiple cores, it can do this only by starting separate threads. Thread management is cumbersome to implement and simply costs development time. With .Net 4.0 the Task Parallel Library will be included which contains out-of-the-box functions to make for-loops parallel, using parallel linq, and so on. This means that CPU heavy programs and routines that use heavy CPU calculations can now be optimized for using multiple cores and executing tasks in parallel.
Concluding
Although at first sight, it might look as if the new features are a bit slim, certainly not the volume we had with the introduction of .Net 3.0 (which introduced WCF, WF and WPF all at once), but the new features do provide a lot of usefulness and will shorten development times for a number of projects. Soon, more about the new features of Visual Studio 2010.
Tuesday, June 09, 2009 1:57:02 AM (Pacific SA Standard Time, UTC-04:00)

Monday, June 08, 2009
Remoting or WCF?
.Net Remoting sounds old, and it is essentially old. Though this is a technique not commonly used and not so popular, it is still valid and it still works today. (Even in .Net 4.0) WCF has gained more popularity since .Net 3.0. Now WCF is popular and .Net Remoting is nearly forgotten. Still, I have to use .Net Remoting because some of my customers are still using – glump – Windows 2000. Guess what Windows 2000 supports? Only .Net 2.0.
.Net Remoting supports almost any host, including IIS. Just like WCF, you can create your own Windows Service to host your Remoting objects or host them in IIS. There are some considerations that you should take when using .Net Remoting, but once you’ve gotten used to it, you’ll see that it’s quite a easy way to establish inter-process communication.
So time for some examples… For this example we’ll use 3 assemblies. One class library and 2 console applications.
First, let’s create a remotable object in a class library:
using System;
using System.Collections.Generic;
using System.Text;
namespace MyRemoteObjects
{
public class RemotableObject : MarshalByRefObject
{
public RemotableObject()
{
startTime = DateTime.Now;
}
private DateTime startTime;
public DateTime GetDateTime()
{
Console.WriteLine("Someone wants to know the time");
return DateTime.Now;
}
~RemotableObject()
{
Console.WriteLine("I'm shut down after {0}", DateTime.Now - startTime);
}
}
}
Next, here’s the source code for the server application:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Collections.Generic;
using System.Text;
using MyRemoteObjects;
namespace MyRemoteService
{
class Program
{
static void Main(string[] args)
{
HttpChannel channel = new HttpChannel(8080);
ChannelServices.RegisterChannel(channel, false);
RemotableObject object1 = new RemotableObject();
Console.WriteLine("I'm the server");
ObjRef ref1 = RemotingServices.Marshal(object1, "object1uri");
Console.WriteLine("ObjRef.URI: {0}", ref1.URI);
Console.WriteLine("Press enter to quit the app");
Console.ReadLine();
// tear down
RemotingServices.Disconnect(object1);
ChannelServices.UnregisterChannel(channel);
// The ServiceClass object's Finalize method writes a message to
// the console. A single object will almost always succeed in
// running its Finalize method before the Console is finalized;
// in a larger application, you could ensure that all objects
// finalize before the application ends by calling the garbage
// collector and waiting.
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
Last, here’s the source for the client application:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Collections.Generic;
using System.Text;
using MyRemoteObjects;
namespace RemotingExample
{
class Program
{
static void Main(string[] args)
{
HttpChannel channel = new HttpChannel(0);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownClientType(typeof(RemotableObject), "http://localhost:8080/object1uri");
RemotableObject remObject = new RemotableObject();
Console.WriteLine("I'm the client");
try
{
Console.WriteLine("The time on the server is: {0}", remObject.GetDateTime());
}
catch (Exception ex)
{
Console.WriteLine("Oops: {0}", ex);
}
Console.ReadLine();
}
}
}
After building and running this, you’ll get something like this:
If you would put this into a service, you can actually talk with your Windows service without much of a hassle. Hope this helps! Objects that are passed from the server to the client need to be either serializable or inherited from MarshalByRefObject.
Monday, June 08, 2009 1:16:06 PM (Pacific SA Standard Time, UTC-04:00)
Working on a new theme for this blog
I’m not happy with the current blue theme… The navigation is overlapped by code segments,
the text gets too wide on big wide-screen monitors
and last but not least, the text is simply too tiny. (Even on a 87 DPI screen it’s hard to read.) So I’ll be changing the theme any day now, to something somewhat more appealing and more usable. If you’ve got some suggestions, feel free to share them! You can comment on this post, or mail me.
Monday, June 08, 2009 11:48:03 AM (Pacific SA Standard Time, UTC-04:00)
Which search engine is best for you?
Take a look at http://blindsearch.fejus.com/. Here you can test your favorite searches and see which engine is best for you. Just search about 10 times and see which engine had the best results 
Monday, June 08, 2009 11:42:14 AM (Pacific SA Standard Time, UTC-04:00)

Sunday, June 07, 2009
Scripting in .Net
So you want to script C#? It’s very easy! For these examples in this article, we’ll use a script file called: “MyScript.cs” which is not compiled in the solution but simple marked as a content file. The contents of that file should look like this:
using System;
static class Program
{
[STAThread]
public static void Main()
{
System.Console.WriteLine("Hello world");
}
}
Next, let’s create a simple compiler to compile this script:
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.IO;
using System.Reflection;
namespace ScriptRunner
{
class Program
{
static void Main(string[] args)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.IncludeDebugInformation = true;
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
string source = File.ReadAllText("MyScript.cs");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParameters, new string[] { source });
if (results.Errors.Count > 0)
{
foreach (var item in results.Errors)
{
Console.WriteLine(item);
}
}
else
{
if (results.CompiledAssembly != null)
{
BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public;
Assembly asm = results.CompiledAssembly;
Type progType = asm.GetType("Program");
MethodInfo info = progType.GetMethod("Main", flags);
if (info != null)
{
info.Invoke(null, BindingFlags.NonPublic, null, null, null);
//asm.EntryPoint.Invoke(null, new object[0]);
}
else
{
Console.WriteLine("Entrypoint not found!");
foreach (var item in asm.GetTypes())
{
Console.WriteLine(item.FullName);
foreach (var method in item.GetMethods(flags))
{
Console.WriteLine(item.FullName + "." + method.Name);
}
}
}
}
}
Console.ReadLine();
}
}
}
No magic here, the result will be as expected:
Now what can we do with this? We can add scripting to our app… but wait, couldn’t that break my app? Yup, if someone decides to create a piece of script that generates an exception, loads huge files, etc, it will sooner or later break your app right with it… These are the kind of things you want to put inside an AppDomain, maybe even sandboxed with partial trust…
The idea is that a piece of code should be able to access certain items from your app. Interfaces and attributes are the preferred approach for these situations. Let’s create a plugin interface, and a marker attribute so we’ll be able to find it once the plugin gets compiled. For this, we’ll create a separate assembly which is called “PluginSDK” and this will contain a few interfaces.
The host interface:
namespace ScriptRunnerSDK
{
public interface IHost
{
string Name { get; }
}
}
The plugin interface:
namespace ScriptRunnerSDK
{
public interface IPlugin
{
string Execute();
IHost Host { get; set; }
}
}
And finally, the plugin attribute:
using System;
namespace ScriptRunnerSDK
{
[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class PluginAttribute : Attribute
{
readonly string name;
// This is a positional argument
public PluginAttribute(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
}
Now it’s time to change our sample script to something that actually uses this info.
using System;
using ScriptRunnerSDK;
[Plugin("MyPlugin")]
class Program : IPlugin
{
public Program()
{
}
public string Execute()
{
Console.WriteLine("I am running in domain: {0}", AppDomain.CurrentDomain.FriendlyName);
return String.Format("Hello {0}", Host.Name);
}
private IHost _host;
public IHost Host
{
get
{
return _host;
}
set
{
_host = value;
}
}
}
And finally, let’s create our compiler that loads the script, compiles it, runs it in a separate AppDomain providing a host and will terminate the script once it is done.
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;
using ScriptRunnerSDK;
namespace ScriptRunner
{
class Program
{
static void Main(string[] args)
{
string source = File.ReadAllText("MyScript.cs");
DummyHost host = new DummyHost();
AppDomain scriptDomain = null;
try
{
scriptDomain = AppDomain.CreateDomain("Script domain");
Type workerType = typeof(ScriptWorker);
ScriptWorker worker = (ScriptWorker)scriptDomain.CreateInstanceAndUnwrap(workerType.Assembly.FullName, workerType.FullName);
string result = worker.RunScript("MyPlugin", source, host);
Console.WriteLine(result);
}
finally
{
if (scriptDomain != null)
AppDomain.Unload(scriptDomain);
}
Console.ReadLine();
}
}
public class DummyHost : MarshalByRefObject, IHost
{
public DummyHost()
{
}
#region IHost Members
public string Name
{
get { return "DummyHost"; }
}
#endregion
}
public class ScriptWorker : MarshalByRefObject
{
public string RunScript(string pluginName, string script, IHost host)
{
string result = String.Empty;
CompilerResults results = Compile(script);
if (results.Errors.Count > 0)
{
foreach (var item in results.Errors)
{
Console.WriteLine(item);
}
}
else
{
result = RunCompiledScript(results.CompiledAssembly, pluginName, host);
}
return result;
}
private string RunCompiledScript(Assembly assembly, string pluginName, IHost host)
{
Type pluginType = null;
// Find the plugin attribute in the assembly's types, see if it matches the plugin name and if so, construct the type, pass the host and execute the plugin.
foreach (var type in assembly.GetTypes())
{
PluginAttribute[] attr = type.GetCustomAttributes(typeof(PluginAttribute), false) as PluginAttribute[];
if (attr != null && attr.Length > 0 && String.Equals(attr[0].Name, pluginName, StringComparison.OrdinalIgnoreCase))
{
pluginType = type;
break;
}
}
// Did we find the type?
if (pluginType != null)
{
IPlugin plugin = pluginType.GetConstructor(new Type[0]).Invoke(new object[0]) as IPlugin;
plugin.Host = host;
return plugin.Execute();
}
// No, we didn't...
throw new InvalidOperationException("The plugin specified could not be found");
}
CompilerResults Compile(string source)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.IncludeDebugInformation = true;
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
// Add a reference assembly
compilerParameters.ReferencedAssemblies.Add("ScriptRunnerSDK.dll");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParameters, new string[] { source });
return results;
}
}
}
This is all there’s to it
The result looks like this:
You can read in my previous post how to do error handling on remote AppDomains to provide additional stability to your application.
Sunday, June 07, 2009 3:03:50 PM (Pacific SA Standard Time, UTC-04:00)
Running code in a different AppDomain
Let’s say you would like to be able to extend your application with C# scripting abilities. You can do this by simply compiling the script and running it. The problem is that these kind of scripts take up memory that isn’t going to be released any time soon. Another problem is that the script can do anything your program can… or when an exception is thrown, your program crashes… is that really the idea?
Enter the use of application domains. Application domains are just for doing these kind of things. Loading temporary assemblies, executing partially trusted code and do memory-intensive work so you don’t need to GC.Collect at the end of the day. (Normally we wouldn’t want to interfere with .Net memory management, because there wouldn’t be much reason to. .Net does a very good job all by itself!)
Let’s start with a very simple example:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace MyAppDomain
{
class Program
{
static void Main(string[] args)
{
Worker localWorker = new Worker();
Console.WriteLine("localWorker is running in: {0}", localWorker.DomainName);
AppDomain myDomain = null;
try
{
myDomain = AppDomain.CreateDomain("Remote Domain");
Worker remoteWorker = (Worker)myDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "MyAppDomain.Worker");
Console.WriteLine("remoteWorker is running in: {0}", remoteWorker.DomainName);
}
finally
{
if (myDomain != null)
AppDomain.Unload(myDomain);
}
}
}
public class Worker : MarshalByRefObject
{
public Worker()
{
}
public string DomainName
{
get
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
}
}
What you see here is:
- An application domain is created
- A value is sent from the new application domain back to the local domain.
- We have a strongly-typed reference to the remote object
In this example, the remote domain is running with the same privileges as the local domain.
Let’s crash…
Unhandled exceptions can cause code to crash or leave your application in an unstable state. AppDomains are isolated and can help you to catch unhandled exceptions and unload the application domain when needed. So when we expand our example to include this, we get something like this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace MyAppDomain
{
class Program
{
static void Main(string[] args)
{
AppDomain myDomain = null;
try
{
myDomain = AppDomain.CreateDomain("Remote Domain");
myDomain.UnhandledException += new UnhandledExceptionEventHandler(myDomain_UnhandledException);
Worker remoteWorker = (Worker)myDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Worker).FullName);
remoteWorker.VeryBadMethod();
}
catch(Exception ex)
{
myDomain_UnhandledException(myDomain, new UnhandledExceptionEventArgs(ex, false));
}
finally
{
if (myDomain != null)
AppDomain.Unload(myDomain);
}
Console.ReadLine();
}
static void myDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex != null)
Console.WriteLine(ex.Message);
else
Console.WriteLine("A unknown exception was thrown");
}
}
public class Worker : MarshalByRefObject
{
public Worker()
{
}
public string DomainName
{
get
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
public void VeryBadMethod()
{
// Autch!
throw new InvalidOperationException();
}
}
}
Loading assemblies in the remote application domain
When loading an assembly in the remote domain, the assembly gets unloaded once the application domain gets unloaded. So if Worker would load an assembly, this would not be a problem as long as worker is in a separate domain. Here’s another example.
First, we create a simply plugin assembly:
using System;
using System.Collections.Generic;
using System.Text;
namespace MyPluginAssembly
{
public class MyPlugin
{
public MyPlugin()
{
}
public string Hello()
{
return "Hello";
}
}
}
This assembly needs to be compiled and for the sake of simplicity we’ll call it “MyPluginAssembly.dll”. Copy this dll to the same directory as the MyAppDomain output folder. Next, we’ll change the example a bit and load the assembly, do some reflection, run the Hello method and print the result.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace MyAppDomain
{
class Program
{
static void Main(string[] args)
{
AppDomain myDomain = null;
try
{
myDomain = AppDomain.CreateDomain("Remote Domain");
myDomain.UnhandledException += new UnhandledExceptionEventHandler(myDomain_UnhandledException);
Worker remoteWorker = (Worker)myDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Worker).FullName);
Console.WriteLine(remoteWorker.RunPlugin());
PrintAssemblies(myDomain);
PrintAssemblies(AppDomain.CurrentDomain);
}
catch(Exception ex)
{
myDomain_UnhandledException(myDomain, new UnhandledExceptionEventArgs(ex, false));
}
finally
{
if (myDomain != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Unloading {0}", myDomain.FriendlyName);
Console.ForegroundColor = ConsoleColor.Gray;
AppDomain.Unload(myDomain);
}
}
PrintAssemblies(AppDomain.CurrentDomain);
Console.ReadLine();
}
static void myDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex != null)
Console.WriteLine(ex.Message);
else
Console.WriteLine("A unknown exception was thrown");
}
static void PrintAssemblies(AppDomain domain)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Assemblies loaded in domain {0} are:", domain.FriendlyName);
Console.ForegroundColor = ConsoleColor.Gray;
foreach (var item in domain.GetAssemblies())
{
Console.WriteLine(item.FullName);
}
}
}
public class Worker : MarshalByRefObject
{
public Worker()
{
}
public string DomainName
{
get
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
public string RunPlugin()
{
Assembly asm = Assembly.LoadFrom("MyPluginAssembly.dll");
Type pluginType = asm.GetType("MyPluginAssembly.MyPlugin");
object plugin = pluginType.GetConstructor(new Type[0]).Invoke(new object[0]);
return (string)pluginType.GetMethod("Hello").Invoke(plugin, new object[0]);
}
}
}
What you’ll notice is that the first list will show that the remote’s plugin assembly is also loaded in the local appdomain. But once the AppDomain is unloaded, the plugin assembly is gone.
Sunday, June 07, 2009 12:43:50 PM (Pacific SA Standard Time, UTC-04:00)
Programming
Windows Storage Server 2008
This one completely went below my radar. Last month, Microsoft released Windows Storage Server 2008, together with it’s iSCSI target. I’m downloading it now and will post my findings within a few days.
Sunday, June 07, 2009 11:44:28 AM (Pacific SA Standard Time, UTC-04:00)
Storage

Saturday, June 06, 2009
Doing PKI the right way
I’ll be doing a series of articles about PKI, it’s uses and how to set things up in a secure and correct manner. Information in these articles is gathered from various online resources, books and study material. Disclaimer: Though I am confident this information can be used to securely deploy a PKI even in big enterprises, you can use this information at your own risk.
This is the first part of the series, which will talk about setting up a root CA and it’s subordinate CAs. In the next articles we will talk about using this infrastructure to secure mail, encrypt files, secure your web servers, using smart cards for Windows logon and electronically sign your documents. Also, signing macro’s, software, add-ins, and more will be part of all of this. This article is full with abbreviations, though each of them should have at least once mentioned their full meaning.
Setting up a Private Key Infrastructure (PKI)
A PKI needs the following ingredients:
- One root certificate authority
- One or more subordinate certificate authorities
- Active Directory to facilitate in distributing and installing certificates
- A web server
The root CA
The root CA must be installed on a stand-alone machine. This machine must not be connected to the network at any time. Start by installing Windows (Standard Edition recommended), activate Windows by phone, install the latest service pack from a CD or DVD. After that, we’ll need to make some preparations for installing the certificate authority. Make sure the computer name of the machine is unique within your network, even though it’s an offline machine.
Create a text file that is called: “CAPolicy.inf”, and put in the following lines:
[Version]
Signature= "$Windows NT$"
[Certsrv_Server]
RenewalKeyLength=4096
RenewalValidityPeriod=Years
RenewalValidityPeriodUnits=20
[CRLDistributionPoint]
[AuthorityInformationAccess]
This will ensure that in the root certificate, the AIA and CRL fields are suppressed. (More about these in a minute.) Place CAPolicy.inf in your Windows directory and install the CA. Enable the web enrollment option, since we’ll be using the website for creating certificates later.
During the installation of a CA, you’ll need to choose a Cryptographic Service Provider (CSP). Since the root CA (or any CA for that matter) only does signing, no encryption, the MS Strong CSP is sufficient for keys up to 16K, the enhanced CSP has essentially the same parameters. When you want to support CNG (Cryptography Next Generation) certificates, the selection of the CSP is an important one. But note that you might be breaking backwards compatibility if you’re using older clients (i.e. Windows XP SP2 or lower, or Windows Server 2003 and lower.) There is a hotfix though: http://support.microsoft.com/kb/938397
Once the CA is installed, you should have a root certificate that is valid for 20 years.
Configuring the Root CA
The Authority Information Access field in a certificate tells the end user where it can download a certificate which signed the certificate that you are using. For example, John sends you a certificate signed by an unknown certificate authority. You see a signature, but you have no idea who it is… Using a AIA extension you can see where you can obtain that certificate which placed the signature on John’s certificate. You download it and you see that it’s issued by a trusted root certificate authority. Since you trust the root CA, you can trust the signer of John’s certificate and therefore John’s certificate is valid. (There are more things to consider, but are outside of the scope of the AIA.) Without an AIA field you could never have verified John’s certificate.
The problem with an offline computer is that it has no network access. The default AIA field in certificates the root CA will issue will be the computer name of the root CA, which is… unreachable. The same story goes for the CRL Distribution point. The CRL (Certificate Revocation List) is used when certificates are revoked. An OCSP (Online Certificate Status Protocol) responder on the Root CA itself will also not work, because of the same reason: no network access. These fields are therefore important and need to be changed before any certificates are issued.
CA addresses (AIA and CRL) can contain multiple protocols, but I usually stick to http. The reason I do this, is because it’s easy to implement, manage, distribute and why should we make our lives more difficult? This is where the web server comes in. The CRL and the CA Certificate need to be hosted on a web server which anyone (internal in the network and outside of the network) has access to. An example:
On the left you see a picture of one of our intermediate CA’s. The CRL distribution point points to http://cert.thewheel.nl/rootca/The%20Wheel%20Enterprise%20Services%20Root%20CA.crl and if you click that link, you’ll get a CRL file. This is a CRL of our root CA, which is manually copied every month to a web server using an old-style method of either a floppy or a USB disk.
To change these extensions you can use the “Certificate Authority” console, right-click on the server, select properties and select the “Extensions” tab. Next, select the CRL extension and you’ll see a whole lot of items in the list box below, which can look quite intimidating, but don’t worry, it isn’t that geeky.
- The extension starting with: “C:\Windows\system32\…” must have “Publish CRLs to this location” and “Publish Delta CRLs to this location” selected
- Make sure that for the LDAP Extension all checkboxes are unchecked. This is an offline CA, so there’s no LDAP that we can use.
- The default HTTP extension: “http://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- The default FILE extension: “file://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- Add a new extension, and type in the following: “http://myserver.mydomain.com/mysubdirectory/<CaName><CRLNameSuffix><DeltaCRLAllowed>.crl” (Without quotes, replace “myserver.mydomain.com/mysubdirectory with the address of your own web server which is everywhere accessible)
- Apply your changes by clicking on the “Apply” button.
Now, we’re doing the same thing for the AIA. Select the AIA extension.
- The extension starting with: “C:\Windows\system32\…” does not have any options you can set
- Make sure that for the LDAP Extension all checkboxes are unchecked. This is an offline CA, so there’s no LDAP that we can use.
- The default HTTP extension: “http://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- The default FILE extension: “file://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- Add a new extension, and type in the following: “http://myserver.mydomain.com/mysubdirectory/<CaName><CertificateName>.crt” (Without quotes, replace “myserver.mydomain.com/mysubdirectory with the address of your own web server which is everywhere accessible)
Next, create an empty directory somewhere on the disk and backup your certificate authority to this location. Copy this to some removable media (Floppy, USB flashdrive, etc) and store it in a very secure location. If this data gets compromised, your PKI will be worthless and needs to be rebuilt from scratch. Lastly, we’re going to install the root certificate on all the machines in the network. (That’s the public certificate, not the private key of course!)
Copying the CA Certificate and the Root CA CRL to another computer
First, we need the root certificate, this you can obtain in multiple ways. The easiest way is to go to %windir%\system32\certsrv\certenroll and copy the files to removable media. Next, you can put these files (one CRL, one CRT and a ASP file for Netscape(!) compatibility) This CRT file is the public certificate of you root CA, not a private key so you don’t have to worry that this contains anything that is worth protecting. In fact, it’s quite the opposite, the more people/computers who trust that certificate, the better.
Installing the root certificate on all computers in the Active Directory domain
Now it’s time to get to either your domain controller or your own workstation if you have the group policy management console (GPMC) installed. Open the GPMC, and edit the default domain policy. Select the following path:
- Computer Configuration
- Policies
- Windows Settings
- Security Settings
- Public Key Policies
- Trusted Root Certification Authorities
- Add the root certificate by right-clicking the folder and click “Import”
- Next, open a command prompt and type: “GPUpdate /force” and wait for group policy to be applied.
Verify the root certificate is installed by doing the following steps:
- Open MMC
- Press Ctrl-M to open the “Add or remove snap-ins” dialog
- Add the “Certificates” snapin
- Choose “Computer account” –> “Local computer”
- Add another instance of the “Certificates” snapin
- Choose “My user account”
- Click on OK
- Expand each certificates node
- Check in the “Trusted root certification authorities” folder if your root certificate is there. (Both for the user account and for the computer account)
If they are both there, congratulations. You’ve done the most difficult step in setting up a PKI. The rest is easy :)
Installing a enterprise subordinate certificate authority
Subordinate CAs are CAs that issue certificates to end users. The Root CA doesn’t do this for several reasons, among which are:
- The CA Certificate of the Root CA can never be revoked
- The Root CA is offline, to issue end user certificates from a offline machine is impractical and a administrator’s nightmare.
Therefore, we create a subordinate CA to take away that burden. Subordinate CA’s are installed on domain controllers. Since we use AD, we can use a enterprise subordinate CA and use Certificate Templates to fine-tune our PKI. You’ll need Windows Enterprise Edition on the DC to do this. If you don’t want to use certificate templates (which is a huge benefit sometimes) you can use standard edition. Note that creating certificates for auto enrollment (which means kind-of zero administration) will require Windows Enterprise Edition. My recommendation? Stick with Enterprise Edition, it will save you a lot of time and effort. If you have a DC installed with Standard Edition, you can upgrade this DC to Enterprise Edition. (Both for Windows Server 2003 and 2008). Cross-platform upgrades (i.e. x86 to x64 or vice-versa) are not supported. Only Wipe & Load migrations or side-by-side migrations are possible. If you can, then this might be a good time to get to Windows Server 2008 x64, the 2008 R2 edition (and any future versions of Windows Server) coming in a few months will only support x64. (until 128 bit computing is invented and we’re reaching the 2 Exabyte of memory limitation on a machine
)
The subordinate CA will be a lot easier to install. Add the CA role and enable web enrollment option. I recommend using keys of 2048 bits in length for the intermediate CA. Also here, choose the CSP that best suites your purpose. During the installation you will be asked for the generation of a certificate request. Save the request to disk, we’ll be using the request file later for obtaining the certificate at the root CA.
Once installed, copy the request file to your USB flash drive or floppy, and bring it to the root CA. There you can start the web browser and browse to http://localhost/certsrv and you'll see the website which you can use to request a new certificate. Do the following steps to obtain a certificate for your new intermediate CA:
- Open the certificate authority management console
- Right-click on the CA
- Select All-Tasks –> Submit new request
- Open the request file
- Go to pending requests
- Issue the request
- Go to issued certificates
- Open the issued certificate
- Select the “Details” tab
- Export to a file
- Select the P7B format
- Check “Include all certificates in the certification path if possible”
- Save the file on your removable media
Now you have your certificate for your intermediate CA. Next, you need to install this on your intermediate CA. So you go back to your DC, open the certification authority snap-in and right-click on the CA. Select “Install CA Certificate” and select the certificate on your removable media. If everything went OK your new CA is up-and-running.
Now it’s time to change the extensions, and add some HTTP extensions so that the certificate and CRL can be downloaded via the web. Finally, make sure that the CA publishes the CRL at regular intervals to your web server.
Concluding
I recommend to have at least 2 intermediate certification authorities running, and in larger environments, to load-balance the web server for fault tolerance. (Note that the amount of web traffic is negligible, the goal is fault tolerance, not throughput.) Make sure that the root CA’s private key is well-guarded and treat this like the most important business secret.
If you would be able to factor this number:
30 82 01 0a 02 82 01 01 00 a9 02 bd c1 70 e6 3b f2 4e 1b 28
9f 97 78 5e 30 ea a2 a9 8d 25 5f f8 fe 95 4c a3 b7 fe 9d a2
20 3e 7c 51 a2 9b a2 8f 60 32 6b d1 42 64 79 ee ac 76 c9 54
da f2 eb 9c 86 1c 8f 9f 84 66 b3 c5 6b 7a 62 23 d6 1d 3c de
0f 01 92 e8 96 c4 bf 2d 66 9a 9a 68 26 99 d0 3a 2c bf 0c b5
58 26 c1 46 e7 0a 3e 38 96 2c a9 28 39 a8 ec 49 83 42 e3 84
0f bb 9a 6c 55 61 ac 82 7c a1 60 2d 77 4c e9 99 b4 64 3b 9a
50 1c 31 08 24 14 9f a9 e7 91 2b 18 e6 3d 98 63 14 60 58 05
65 9f 1d 37 52 87 f7 a7 ef 94 02 c6 1b d3 bf 55 45 b3 89 80
bf 3a ec 54 94 4e ae fd a7 7a 6d 74 4e af 18 cc 96 09 28 21
00 57 90 60 69 37 bb 4b 12 07 3c 56 ff 5b fb a4 66 0a 08 a6
d2 81 56 57 ef b6 3b 5e 16 81 77 04 da f6 be ae 80 95 fe b0
cd 7f d6 a7 1a 72 5c 3c ca bc f0 08 a3 22 30 b3 06 85 c9 b3
20 77 13 85 df 02 03 01 00 01
... then Microsoft would have a serious problem. But since they keep their private key secure, it will be long after the time that this key is valid that the secret will be revealed, if ever.
Saturday, June 06, 2009 4:00:49 PM (Pacific SA Standard Time, UTC-04:00)
Security and Cryptography

Friday, June 05, 2009
Installed syntax highlighter
As you might have noticed in the previous post, I’ve installed syntax highlighter. This together with PreCode Snippet allows you to insert code snippets very easily using Live Writer. If you have a coding blog, I can recommend you these tools!
Friday, June 05, 2009 5:36:38 PM (Pacific SA Standard Time, UTC-04:00)
Adding some UI elements with jQuery to an MVC app
One of the requirements that I have on an application that I’m working on is that the user can select a date easily when a textbox has focus. I wanted this to do in such a manner that programmatically this can be done with minimum effort, and that a few extra things are taken into account:
- Nullable dates (i.e. end dates) should be allowed with an empty text box
- Not-nullable dates should default to the date of today
- Multiple date pickers should be possible within the same form
Ingredients
For this to work out, I’ve used the date picker control that’s available at http://jqueryui.com/ Besides that, I’m using ASP.Net MVC 1.0
Creating an extension method for System.Web.Mvc.ViewUserControl
For the view, I’m using an extension method that’s called “DateField”. This allows me to use the date field without having to use things like “RenderPartial” and creating custom models.
This class looks like this:
public static class ViewUserControlDateFieldExtension
{
public static string DateField(this IViewDataContainer control, string fieldName)
{
return DateField(control, fieldName, control.ViewData.Eval(fieldName) as DateTime?, false);
}
public static string DateField(this IViewDataContainer control, string fieldName, bool allowNulls)
{
return DateField(control, fieldName, control.ViewData.Eval(fieldName) as DateTime?, allowNulls);
}
public static string DateField(this IViewDataContainer control, string fieldName, DateTime? value)
{
return DateField(control, fieldName, value, false);
}
public static string DateField(this IViewDataContainer control, string fieldName, DateTime? value, bool allowNulls)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("<input type=\"text\" name=\"{0}\" value=\"{1}\" class=\"datepicker\" />", fieldName, GetFieldValue(control, value, allowNulls));
return sb.ToString();
}
private static string GetFieldValue(IViewDataContainer control, DateTime? value, bool allowNulls)
{
if (allowNulls)
{
if (value.HasValue)
return value.Value.ToString("dd-MM-yyyy");
else
return String.Empty;
}
else
{
if (value.HasValue)
{
if (value.Value == DateTime.MinValue)
return DateTime.Now.ToString("dd-MM-yyyy");
else
return value.Value.ToString("dd-MM-yyyy");
}
else
return DateTime.Now.ToString("dd-MM-yyyy");
}
}
}
Next, adding some jQuery script
Adding the script to the master page is easy. Just a few <script> tags and that’s it.
<link href="/themes/redmond/ui.all.css" type="text/css" rel="Stylesheet" />
<script src="/Scripts/jquery-1.3.2.js" type="text/javascript"></script>
<script src="/Scripts/ui/ui.core.js" type="text/javascript"></script>
<script src="/Scripts/ui/ui.datepicker.js" type="text/javascript"></script>
<script src="/Scripts/ui/i18n/ui.datepicker-nl.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
// Configure and add a date picker.
$(function() {
$(".datepicker").datepicker({
changeMonth: true,
changeYear: true
});
$(".datepicker").datepicker('option', { dateFormat: 'dd-mm-yy' });
$.datepicker.setDefaults($.extend({ showMonthAfterYear: false }, $.datepicker.regional['nl']))
});
</script>
Finally, use the class
Using the class is as easy as using this little line of code for a date field:
<% = this.DateField("EndDate", true) %>
The result looks like this:

The most nice part? It works in IE7, IE8, Opera, Chrome, FireFox and Safari.
UPDATE: Why use IViewDataContainer
I had a question from someone who wanted to know why I choose to extend IViewDataContainer in stead of WebControl/WebPage. The reason is simple. Both the System.Web.Mvc.ViewPage en System.Web.Mvc.ViewControl implement IViewDataContainer. This makes the interface the easiest target to implement.
Friday, June 05, 2009 5:03:17 PM (Pacific SA Standard Time, UTC-04:00)
MVC | Programming
Giving BitLocker a try
BitLocker can work with an external USB flash drive, so I thought, let’s give this a try. In short, it works fine, I didn’t see any noticeable performance degradation, but it simply does not work for me. There are a few reasons to this, all which I’ll explain below.
The BIOS and the flash drive
My MoBo’s BIOS has a tendency to put the flash drive on top of the list when it considers which device it should use to boot up. This is a pain in the neck, since once I removed the USB drive and I insert it again, my BIOS tends to forget the changes. So the workaround would be pressing F12 during the POST or maybe updating the BIOS… This is the most nasty part of using BitLocker with a USB drive. And putting the RAID array as a secondary doesn’t work either. This is for me the showstopper.
Making duplicates of the USB flash key
This is a good thing of BitLocker, you can easily make a new flash drive using either a new key or simply copy a key from your current one. Also, the password you can put into your vault is a good thing to have. So no comments on this.
You can only encrypt drives on which Windows is installed
You can not encrypt other hard drives in the system. This means that I have 33% of my data protected, while the other is easy to get. This means for me that EFS (Encrypting File System) is a better alternative.
My conclusion
BitLocker has it’s limitations, and with a TPM chip on board things will certainly be a lot better. For notebooks I’d say: Go and use this. For a workstation? Unless you got one hard disk to protect and a TPM chip onboard, use EFS. It’s easier to manage and deploy once you’ve set it up. So I’ll be doing this for the coming hours:

Friday, June 05, 2009 4:25:33 PM (Pacific SA Standard Time, UTC-04:00)