Monday, July 18, 2011

Host your own Roborumble server

There are several reasons why you might want to run your own Roborumble server. Maybe you would like to run small local contest at your school or workplace. Or maybe you are testing your new shiny robot. Or may you want to collect some battle data, like myself.

The current Roborumble server is created and maintained by Darkcanuck. Luckily he shares the RumbleServer sources via subversion. It is implemented in PHP and MySQL.

Because I'm not PHP+MySQL expert, easiest solution for me was to download ready-made LAMP virtual machine and configure it.
I know you are busy ;-), so I published my virtual appliance, you could just start using it. You can download it and run it in VMWare Player. Password is robocode, you should change it as soon. Or you could follow the guide below.

Configure server

Once you have LAMP stack up and running you need few things:
Install subversion client
Get PHP sources
Configure RumbleServer
Turn on URL rewriting mod in Apache
Configure MySQL database and grant permissions

The appliance has could be configured from web admin. You can access it on https://192.168.1.12/ where 192.168.1.12 is the IP address assigned to the virtual machine by your DHCP server. I will use 192.168.1.12 which was assigned to me in rest of the article.


Webmin->Global configuration
  ->Configure Apache Modules->rewrite: switch ON

MyPhpAdmin
  Create database->roborumble   Import script schema/schema.sql
  Priviledges->add new user->
    name->rumbleuser
    pass->rumblepass
    Database for user->None
    Global privileges->Select+Update+Insert+Delete

On root shell do something like this
apt-get install subversion
cd /var/www/
mkdir rumble
cd rumble
svn co http://darkcanuck.net/svn/rumbleserver/trunk/ .
chmod g+w templates_c/
chown :www-data templates_c/
cat > participants.txt
[paste participants.txt file and press Ctrl-D]
cd config
cp config.php-sample config.php


Participants

Are defined as list of robots and their .jar files. Big competition is driven by this file. We could simplify our own list like this. We host the file on the appliance in folder /var/www/. So create you own shortlist and update it there. Note there are starting and ending tags.
----
<pre>
jk.mega.DrussGT 2.0.4,http://www.minifly.rchomepage.com/robocode/jk.mega.DrussGT_2.0.4.jar
voidious.Diamond 1.5.34b,http://www.dijitari.com/void/robocode/voidious.Diamond_1.5.34b.jar
</pre>
----


Configure client

Download and install Robocode 1.7.3
Edit c:\robocode\roborumble\roborumble.txt

  PARTICIPANTSURL=http://192.168.1.12/participants.txt
  UPDATEBOTSURL=http://192.168.1.12/rumble/RemoveOldParticipant
  RESULTSURL=http://192.168.1.12/rumble/UploadedResults
  RATINGS.URL=http://192.168.1.12/rumble/RatingsFile
  ITERATE=YES

start c:\robocode\roborumble.bat

Purge data

If you need to purge the data from the roborumble database and start from scratch just delete rows using MyPhpAdmin.
delete from battle_results;
delete from game_pairings;
delete from bot_data;
delete from participants;
delete from upload_stats;
delete from upload_users;


Oh, and once you are done with your local competition, don't forget to redirect back to official RoboRumble server and contribute your CPU power!


Download turnkey-roborumble.2011-07-18.zip.torrent

Thursday, July 7, 2011

HowTo: Pass build property from TeamCity into Freemaker email notification template

There is no magic, once you know it. My use-case was to prefix build number with configurable text before sending an email. The text was represented as TeamCity property system.tc.branch.number in my case.

TeamCity email templates are implemented with Freemaker. The TeamCity exposes all build properties as hash table on SBuild.getBuildOwnParameters().

In the template the instance of SBuild is accessible under build variable. Freemaker allows calling bean properties, in our case it would be build.buildOwnParameters, map lookup thru square-bracket syntax [] and literals are enclosed in apostrophes.

#${build.buildOwnParameters['system.tc.branch.number']}.${build.buildNumber}

Tuesday, June 28, 2011

jni4net 0.8.4 - release

Changes

  • Added ability to load proxies into specified classLoader by Jose Chillan.
    Bridge.LoadAndRegisterAssemblyFromClassLoader(File, ClassLoader)
  • JNIEnv.DetachCurrentThread() contributed by Renier B.
  • Bridge.setClrVersion() made static by Leonid Bogdanov
Download here

Saturday, March 26, 2011

Raising Property Changed fast and safe - yet another solution

This Thursday we discussed with my colleagues how to raise property changed event. We learned that it could be done
a) via string literal,
b) via lambda expression tree,
c) via StackTrace or MethodBase.GetCurrentMethod().
Nice summary is here. or here

We did some naive performance test and learned that for 500k iterations on simple property, there is big difference in speed.
a) is really fast, 13ms
b) is slow, 1417ms, I guess because security checks apply for every call and every stack frame, and can't be fired from other properties.
c) is slow, 2518ms, very slow, because expression tree is constructed for every call

So we played with it for a while and I invented solution with anonymous type (at botom).

Update 27.3.2011: I was so focused on speed that I didn't realized that the solution yesterday didn't work nicely for rename. What a shame. I hope people give me another chance today. Here we have postponed creation of the expression tree, it takes about 75ms. And this time my ReSharper renames it correctly :-)
Update 5.12.2011: As Alex noted in comments, there was thread safety issue with Dictionary. The code is now fixed with Hashtable instead.


public abstract class ModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private static readonly Hashtable Names = new Hashtable();

    protected void RaisePropertyChange(Func<string> key)
    {
        if (PropertyChanged != null)
        {
            var propertyName = (PropertyChangedEventArgs)Names[key];
            if (propertyName==null)
            {
                propertyName = new PropertyChangedEventArgs(key());
                lock (Names)
                {
                    Names[key] = propertyName;
                }
            }
            PropertyChanged(this, propertyName);
        }
    }

    protected static string Reg<T>(Expression<Func<T>> property)
    {
        return (property.Body as MemberExpression).Member.Name;
    }
}

public class Model : ModelBase
{
    private string firstName2;
    public string FirstName2
    {
        get { return firstName2; }
        set
        {
            firstName2 = value;
            RaisePropertyChange(() => Reg(() => FirstName2));
        }
    }
}

Doesn't work: The lambda just helps to define the type without creating the instance and calling the getter. It takes about 77ms for half million calls.

public abstract class ModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private static readonly Dictionary<Type, PropertyChangedEventArgs> Names = 
          new Dictionary<Type, PropertyChangedEventArgs>();

        protected void RaisePropertyChange<T>(Func<T> f)
        {
            if (PropertyChanged!=null)
            {
                var key = typeof(T);
                PropertyChangedEventArgs evntArgs;
                if (!Names.TryGetValue(key, out evntArgs))
                {
                    var propertyName = key.GetProperties()[0].Name;
                    evntArgs = new PropertyChangedEventArgs(propertyName);
                    lock(Names)
                    {
                        Names[key] = evntArgs;
                    }
                }
                PropertyChanged(this, evntArgs);
            }
        }
    }

    public class Model : ModelBase
    {
        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set {
                if (firstName != value)
                {
                    firstName = value;
                    RaisePropertyChange(() => new {FirstName});
                }
            }
        }
    }

Sunday, February 20, 2011

jni4net 0.8.3 - release

Changes

  • added support for IBM JRE
  • added drools sample
  • added BridgeSetup.IgnoreJavaHome
  • improved error logging during initialization

Blocked DLLs for CLR 4.0

If you download the distribution package on jni4net and unzip it via Windows Explorer, it will set the DLL security zone as untrusted. That will prevent CLR 4.0 from loading the DLL and you will receive exception while initializing jni4net from Java side.
The message states:
Can't init BridgeExport:An attempt was made to load an assembly from a network l
ocation which would have caused the assembly to be sandboxed in previous version
s of the .NET Framework. This release of the .NET Framework does not enable CAS
policy by default, so this load may be dangerous. If this load is not intended t
o sandbox the assembly, please enable the loadFromRemoteSources switch. See http
://go.microsoft.com/fwlink/?LinkId=155569 for more information.

You can solve it by unblocking the DLLs.
Right-click on the files, open file properties and click unblock button.

Sunday, January 2, 2011

jni4net 0.8.2 - bugfix release

Bug fixes

  • upgraded nMaven, NUnit, made build 32bit only
  • fixed throwing exceptions for missing proxy classes
  • [#18] - C# string[]{null} -> JVM -> null reference exception
  • improved architecture detection

Sunday, November 7, 2010

jni4net 0.8.1 - bugfix release

  • Fixed memory leak reported by Jaco Ackermann
  • Included improved CLR detection contributed by Leonid Bogdanov
Download 0.8.1 here