lbsa71.net Just another WordPress weblog

18May/092

lbsa71: wb

So, I moved the blog off a standard web host blog to an wordpress installation of my own. Hopefully, this should mean I can get a bit better control over the site content appearance. Thank you for your patience. ;-)

Filed under: Uncategorized 2 Comments
7May/090

Top ten ways to know you are not doing agile

Alistair Cockburn ('cooburn') is one of my heroes; here's a thought-provoking list to match your team against:

http://alistair.cockburn.us/Top+ten+ways+to+know+you+are+not+doing+agile

Filed under: Programming No Comments
1May/090

Refactoring Tactics Primer

Introduction

In this article I will show how to employ some relatively advanced code refactoring tactics to change a reasonably hairy piece of spaghetti code into something a bit more structured.

Basic familiarity with the JetBrains ReSharper tool is required.

Background

The code in this sample reflects an actual piece of code that a colleague of mine got handed to him. Amongst other abominations, it employed the 'transferring values in and out of Windows Forms by getting and setting public fields on an global static class' anti-pattern. He realized that the code actually introduced a bug (since the static fields would retain their values between subsequent calls) so I thought I'd show him how to wrestle out of some of the more nasty bits of the code. After doing that, I figured I'd write this article so that the world brain could benefit from it.

Instructions

Download the RefactoringPrimer.zip and extract and load the Visual Studio 2008 solution Seminar1.sln, make sure you have ReSharper handy, and follow the walkthrough below.

The solution is split into six steps, Step 1 being the original spaghetti code, and Step 6 the final result.

The Scenario is built around an application (Program) that calls up a (faked) Windows Form (FakeForm), and uses a static utility (Util) class to pass initial values and fetch returned data.

Each solution project corresponds to the starting point in each step, and builds a console project that when run tries to call up forms twice, each time emulating a user entering some data, and reports 'wrong: using tainted maxValue' or 'correct: using default maxValue'.

Points of Interest

This walkthrough is really only a primer to what can be done with taking a "automated refactoring tactics" approach; "tactics" referring to laying out a 'strategy', a chain of automated refactorings to get from a code state a to a code state b.

To create this particular set of refactoring tactics, I made extensive use of scratch refactoring, which is something I've found to be very useful.

Walkthrough

Step1 - Deciding what to break out

  1. Manually create a public inner class called 'FormData' inside the Utils class.
        static class Utils
        {
            public class FormData
            {
            }  
    
            private const int DEFAULT_MAX_VALUE = 5;
            public static int MinValue = 1;
            public static int MaxValue = DEFAULT_MAX_VALUE;
            public static int MeanValue = 10;
  2. Right-click on the MinValue member field, choose "Refactor", then "Move". Check static fields MinValue, MeanValue and MaxValue, and specify Step1.FormData as the target. Press "Next". After the move, note that DEFAULT_MAX_DATA is accessible, since FormData is an inner class. Also, inspect FakeForm and Program to see the updated references.
  3. Run and show wrong result

From now on, I will not write out the 'right-click', "Refactor" or "Click Next" et c - if the istructions aren't obvious to you, I recommend you spend some time familiarize yourself with ReSharper. Either that, or place a request for clarification in the comments.

Step2 - Breaking out of the static cage

  1. "Copy Type" Utils.FormData to InstanceFormData - it will also be an inner class.
  2. Remove all static declarations on the copied type -this will become our 'new' FormData.
            public class InstanceFormData
            {
                public int MinValue = 1;
                public int MaxValue = DEFAULT_MAX_VALUE;
                public int MeanValue = 10;
            }
  3. "Move" InstanceFormData to "Outer scope" giving it the new name "FormData"
  4. The refactoring tool will complain that DEFAULT_MAX_VALUE will no longer be accessible. Turn DEFAULT_MAX_VALUE public and hit 'Refresh'
  5. Change 'internal' on new FormData to "public" (or you will get a build error when we do the manual switch later)
        public class FormData
        {
            public int MinValue = 1;
  6. Manually remove inner FormData type definition and replace with a static Singleton field initializer:
        static class Utils
        {
            public static FormData FormData = new FormData();
            public const int DEFAULT_MAX_VALUE = 5;  
    
            public static bool IsDefaultMaxValue( int val )
            {
                return val == DEFAULT_MAX_VALUE;
            }      
    
            public static bool TestMinGreaterThan3()
            {
                return FormData.MinValue > 3;
            }
        }      
    
        public class FormData
        {
            public int MinValue = 1;
            public int MaxValue = Utils.DEFAULT_MAX_VALUE;
            public int MeanValue = 10;
        }
  7. Run and show wrong result - we're still running on the same instance.

Step3 - Passing the temporary singleton around

  1. "Introduce field" m_formData on FakeForm, initialized in constructor.
  2. "Introduce Parameter" formData on m_formData initializer.
  3. Manually change FakeForm constructor member initializations to
    m_min = formData.MinValue;
    m_mean = formData.MeanValue;
    m_max = formData.MaxValue;

    (remember that the member fields are faking textboxes)

  4. "Safe Delete" all unused (greyed out) constructor parameters
  5. "Introduce Parameter" formData on TestMinGreaterThan3
        static class Utils
        {
            public static FormData FormData = new FormData();
            public const int DEFAULT_MAX_VALUE = 5;      
    
            public static bool IsDefaultMaxValue( int val )
            {
                return val == DEFAULT_MAX_VALUE;
            }      
    
            public static bool TestMinGreaterThan3(FormData formData)
            {
                return formData.MinValue > 3;
            }
        }
  6. "Move" static method TestMinGreaterThan3 to FormData
  7. "Make method non-static" on TestMinGreaterThan3
  8.     public class FormData
        {
            public int MinValue = 1;
            public int MaxValue = Utils.DEFAULT_MAX_VALUE;
            public int MeanValue = 10;  
    
            public bool TestMinGreaterThan3()
            {
                return MinValue > 3;
            }
        }

Step4 - Getting rid of the temporary singleton

  1. "Introduce variable" formData on first Utils.FormData in Run()
       FormData formData = Utils.FormData;  
    
       FakeForm a = new FakeForm(formData);
  2. Manually Change Utils.FormData to new FormData();
       FormData formData = new FormData();  
    
       FakeForm a = new FakeForm(formData);
  3. Manually add another initializer.'
        FormData formData = new FormData();  
    
        FakeForm a = new FakeForm(formData);      
    
        bool result = a.RunCase1(3, 4); // Setting min and max      
    
        formData = new FormData();      
    
        FakeForm b = new FakeForm(formData);
  4. Run and revel in succesful result

Step5 - Some final cleanup

While we've fixed the main issue, there is still some simple refactoring that can be done to give that "cleaner, fresher feeling".

  1. "Inline method" SetMeanValue() in FakeForm
  2. "Rename" FakeForm method SetStatics() to SetFormData
  3. "Move" FormData to its own file FormData.cs

Step6 - The final result

We have now moved from a spaghetti code mess to nice decoupled code, and hopefully you have gotten a glimpse of what chaining automated refactorings can do for your code.

If you've done this excercise and found it worthwhile, please consider giving me your feedback so I can make this article even better - also, illustrative screenshots taken along the way would be greatly appreciated!

Happy tinkering!

Filed under: Programming No Comments
23Apr/090

Installing the JChem Server as a service on Windows Server 2008

The JChem installation instructions points you to using srvany.exe to wrap the server.bat startup script.

Srvany is the old (pre-Vista/2008) way of wrapping any exe or cmd in a service container. (This is needed to provide the service start, stop, pause hooks that services need, and normal exes don't provide)

On Windows 2008 Server and Windows Vista, Instad of installing the server using srvany.exe, you simply create a Scheduled Task that is set to trigger on system startup.

Program/Script should be the
ChemAxonJChemcartridgeserver.bat
argument simply
start

Be sure to specify startup directory
ChemAxonJChemcartridge

and "run wheter user is logged on or not". You should be able to run the task as SYSTEM.

In Task "Properties/Settings" I would suggest you set "run task as soon..." to true, and specify failure recovery policy.

22Apr/090

Using TIBCO Designer with SVN

Since TIBCO Designer doesn't support ignoring .svn, here's how to do it:

http://unentangled.net/posts/use-svn-with-tibco-designer/

Also, here's how to retain SVN history when renaming objects:

http://unentangled.net/posts/retain-svn-history-with-designer/

9Apr/092

Nunit, Custom CategoryAttribute and ReSharper testrunner

JetBrains recently announced the new ReSharper 4.5.

One of the bugs that was fixed in this release, is that the testrunner now correctly displays custom NUnit categories based on CustomAttribute.

Custom NUnit categories is very useful for grouping tests in the same solution, so that you can manually choose what group to run (unit tests, database tests, system tests) - or set a job up that tests using the /exclude and /include command line switches on the runner.

Of course, various other NUnit runners have been honouring subclassed categories since the feature was introduced in NUnit 2.4, but it's nice to have it in my favourite runner.

Filed under: Programming 2 Comments
25Feb/091

On Multi-protocol

From the Not-Invented-Here Dept. 

With the recent breakthroughs in OpenSim with (theoretically) supporting multiple protocols, the question of 'How do you transfer Object of protocol X over protocol Y' and 'how do you change SecondLife(tm) prims into MXP objects and vice versa?

I got a revelation the other day that "Maybe you don't".

 One of the problems with any viewer approach is that any multi-protocol viewer has to support a multitude of protocols to be interesting. Very much a discussion like the one on video streaming and video streaming clients.

So, I propose the following;

On the server side, all objects are stored natively; Second Life compatible Objects are stored as that, X3D objects as X3D objects, and MXP objects as MXP objects.

They collaborate on the server by exposing the same set of behavioural functions (Exposing meshes for the Physics engine, and functions to add, move and change some basic set of attributes) 

All protocols are implemented as "codecs", on the server side they will very much look like OpenSim 'modules'; these codecs

a) set up protocol-specific endpoints for native clients

b) register factories to create protocol-specific instances of core objects

c) register abstracted endpoints for multiplexed transfer over what I chose to call the "Real Time Scene Transfer Protocol"

On the viewer side, each protocol is also implemented as a 'codec'; here, the codec is responsible for implementing the transformation of protocol-specific stream data into scene changes.

Now, when a client connects to a Scene, it has the choice of connecting to a native endpoint, or to the RTSTP Endpoint

If it connects to the native endpoint, it will use only that codec, which means all scene changes will go thru that protocol, and the server codec will do its best to transform content from one protocol standard to another, optionally by chaining other server codecs.

But; if it connects to the RTSTP Endpoint, it will be served a stream that is a multiplexed interleave of the output of the different protocol payloads.

If a new object should be created, it's ether going to be recieved as an SL UDP ObjectAdd Packet payload or thru an MXP Object add - depending on what type of object is added on the server.

The Stream Demultiplexer then splits the packets and sens them to the according codec, which is then responsible for adding it to the viewers local scenegraph for rendering.

One central point is that the native endpoints should probably implement the same interfaces as the multiplexed payload endpoint, so an SL EndPoint should be split into the SL UDP Transport layer and the SL Packet layer, where the native endpoint would use one, and the RTSTP multiplexer the other.

The control stream, ie, the information of user intentions, like keyboard presses and avatar navigation, can (probably?) be thought of either being multiplexed into the various protocol tunnels, or as a separate 'control pipe' funnel.

Of course, all this is very half-baked, and I'm definitively not the man to start drawing up formal proposals. I just realized I had a solution for what I foresee as a very real problem in a multi-protocol multi-standard 3D client-server model. In essence, you need a network transfer, a session, an interleaved stream and the different content streams

So, anybody has good already-existing protocols to handle this? SIP or RTSP to negotiate EndPoints configuration? OGG or Matroska for stream interleaving?

Best Regards,

Stefan Andersson aka lbsa71

Filed under: OpenSimulator 1 Comment
20Feb/0911

Hacking Trees

From the Under-the-Hood dept.

Today, I thought I'd show you how to attach a LSL/OSSL script to a tree, and in the process touch on some interesting concepts.

The first thing you need to know is that tree and grass are really just prims with a special 'PCode' that tells the viewer to render them differently. In theory, you would be able to attach scripts to trees and grass in Second Life™ - with OpenSim, theory becomes practise!

  • set up an empty region
  • create a Tree, call it 'My Tree' or something so you can identify it later
  • create a Box, call it 'My Box'
  • create a script in the box, call it 'Tree Script'.
  • on the opensim region console, issue the command
    save xml2 test.xml
  • the file will be saved in the OpenSim root /bin directory as test.xml. Open it up, preferrably, in an xml-savvy editor for readablity.
  • inspect the xml code. It's a mouthful, but after some careful scrutiny, you will start to understand some of the nodes. You're now looking at the under-the-hood representation of objects in OpenSim, which incidentally is based on the binary data protocol that the viewer and region uses to communicate. Doesn't look anything like the numbers you see in the edit object tabs, right? That's because the viewer is trying to present stuff in a way that you as a user will feel more familiar with.
  • Now copy the full <Shape>...</Shape> node block of 'My Tree' and paste it over the full <Shape>...</Shape> node block of 'My Box', replacing it. This is the tricky part, but done right, you've replaced the box shape values with the tree shape values, turning the box definition into a tree definition.
  • Save the modified test.xml file to disk.
  • Delete 'My Box' and 'My Tree' from the region, making room for importing the new hacked versions.
  • Issue the command
    load xml2 test.xml
  • Hey Presto! You will have two trees, probably of wildly differing sizes. (If so, this is because the <Scale> of 'My Box' was different from that of 'My Tree'.)A tree with content from Shortdog
  • Now, right click on 'My Tree', and chose 'Open' (not 'Edit'!) from the Pie menu - In OpenSim you can actually Open the contents of a tree - in Second Life™, this pie option woul be grayed out. In 'My Tree' the content is empty.
  • Now, right click on the tree called 'My Box', and chose 'Open' - we still have our script there!
  • Now, script away, you can basically do anything with the tree/grass that you can do with any other prim - set the params, size, position, communicate, do http requests. Go wild!
  • Here's a little demo script to get you started: it toggles the tree position and size every second, while saying 'timer' every tick.
integer toggle = 0;
default
{
    state_entry()
    {
        llSay(0, "Script running");
       
        llSetTimerEvent( 1.0 );
    }
   
    timer()
    {
        toggle = 2-toggle;                      

        float newval = toggle + 3;                      

        llSay(0, "timer");
       
        list rules = [ PRIM_SIZE, < newval, newval, newval >, PRIM_POSITION, < 128+newval, 128+newval, 30+newval >];
       
        llSetPrimitiveParams( rules );
    }
}
  • You can now take this object to inventory, clone it and give it to your fellow man.

For extra credit:

  • The <State> field of the tree prim represents the tree type*.
  • Explore changing the TextureEntry, Particle Systems, SculptTexture, CollisionSound of a tree - does it do anything? Please report back to me.Trees with particle systems and ambient sound changing size from Shortdog
  • What with defining sit targets, attaching to link sets, defining touch_start() events? Can you find a way to interact with the trees in interesting ways?
  • Can you add other objects into the content? Make a wishing tree where people can actually 'Open' the tree and pillage the goodies?
  • How about "Megatrees"? Find the <Scale> nodes and create a 100 meter Tolkien forest? (There are two but only one of them needs changing, figure out which)
  • What fun can be had with 'grass'? (Create and save 'My Grass' and inspect the xml.)
  • How would one go about to export the scripted trees to other grids, where you don't have console access?
  • Is there an even simpler way to do this? Can Prims Rez trees from inventory, give them active scripts, and if so, can trees Rez their spawn? Please report back with your findings, or blog about them.
  • Take screenshots of the steps along the way, and send them to me so I can illustrate this article better.

Thank you for taking your time reading all of this. I hope that you have learned at least something about Prims, Trees, Grass, Love, OpenSim, the xml2 format and life in general.

Best regards,

Stefan Andersson aka lbsa71

*       Pine1 = 0,
        Oak = 1,
        TropicalBush1 = 2,
        Palm1 = 3,
        Dogwood = 4,
        TropicalBush2 = 5,
        Palm2 = 6,
        Cypress1 = 7,
        Cypress2 = 8,
        Pine2 = 9,
        Plumeria = 10,
        WinterPine1 = 11,
        WinterAspen = 12,
        WinterPine2 = 13,
        Eucalyptus = 14,
        Fern = 15,
        Eelgrass = 16,
        SeaSword = 17,
        Kelp1 = 18,
        BeachGrass1 = 19,
        Kelp2 = 20

Filed under: OpenSimulator 11 Comments
21Jan/090

Working with the Hypergrid

A recent and exciting development in OpenSim is support for what is called 'hypergridding' or 'hyper-linking'

In effect, what it does, is just to let avatars ('guests') teleport into 'foreign' regions (on other grids) and in the process inform the target region where to look for inventory and assets for that guest - in theory, allowing for free teleports between grids.

Now, how have drm issues been solved, you wonder? The short answer: "we haven't".

As of this moment, you are adviced to think of 'hypergridding' as one big security and drm vulnerability. It is actually the very lax security of the OpenSim OGS protocol (Open Grid Services) that has allowed for the hypergrid to emerge.

It still has some heavy benefits, but more in the 'weak protection needed for loading a webpage' corner than the 'strong protection needed for participating in interchange within an economic system based on artificial scarceness' one.

So, how would you, as a grid owner, concerned for your users, work with this? I suggest something like this;

First of all, set a completely isolated Hypergrid standalone DMZ 'island' up parallell with your 'main grid', like thus:

Disconnected Standalone DMZ

By specifying gridmode=false in your OpenSim.ini and setting the standalone region to use a private database in the [Standalone] section.

Make sure you specify/create an dmz region 'master avatar' on startup, otherwise you will not have any account with permissions to modify the region once it's up. If you just start the region up from scratch, the startup procedure will ask you to create a master avatar account. Choose a strong password.

What this setup gives you is the opportunity to start trying hypergrid interlinking out, while ensuring none of your main grid data or content leaks out. Again, if you decide to use a shared database server, make sure you specify a new database clearly separated from your main grid database on that server.

I would suggest you create what I call a 'storefront' on this region, non-drm sensitive demo and pr content that ushers prospective users onto to your main grid through the grid registration page. The point here is to keep the hypergrid region air-tightly separated from your main grid whilst still allowing you to expose content that people can make part of their own grids. A '3D banner exchange program', if you will.

Do note that the only way to work with or access this dmz region is to either log on as the specified master avatar (if you specified one) or to hyperjump into it. And the only editing options is either to log on as the master avatar, or to turn perms off.

After familiarizing yourself with the hypergrid, we can start thinking of how to start sharing user data and content with the main grid, whilst retaining basic drm security. This I will cover in my next 'Working with the Hypergrid' blog.

(If all this sounds interesting, but you don't have a clue as of how to do all this, visit the opensimulator.org web site, join the #opensim irc channel on freenode, or send me an e-mail.)

Filed under: OpenSimulator No Comments
21Jan/090

OpenSim turns two

We are 2

The 3D Application platform Open Simulator, or 'OpenSim' for short, turns two years old January 29th 2009.

The consensus is that this date 2007 OpenSim was 'born' when Darren Guard (aka MW) made his prototypical C# 3D world server publicly available.

You can help celebrate this joyous occasion in a number of ways;

  • Read OpenSim History for some recap of the early days, and help continue documenting it.  
  • If you're in the position to run a region or grid, or already do, this is an excellent opportunity for you to further OpenSim and yourself by 
    • taking the opportunity to demo and publicize noteworthy services or content.
    • set up what we call a 'hypergridded dmz storefront' - in effect, a public standalone region not connected to the main grid services - and be part of the hypergrid link-fest
    • blog about this joyous occasion, draw attention to OpenSim, the second birthday, and tell your own OpenSim story.
    • set some demo content up, demoing your grid and what's going on there
      • establishing a media parcel url going to a live voice feed so that you could hold voice demonstrations, dj sessions and panel discussions on topics relevant to your grid.
      • some avatar appearance/merchandise items that you are ready to give to the public domain
  • Attend the party, dressed to kill, socialize, go hypergrid club hopping, generally helping out and enjoying what will still be referred to in the history books as 'back in the early days of the 3D web'!

This is a great opportunity to acquaint yourself with OpenSim and what it means to run a region, optionally hypergridded - and we hope to see lots of cool stuff happen and scare a bunch of ugly bugs out of their holes in the process!

Regardless,

If you're planning on doing anything for OpenSims second birthday, be sure to post it on

http://opensimulator.org/wiki/Second_Birthday

If there is no heading suitable for your project, just make one - it's a wiki!

Love,

Stefan Andersson aka 'lbsa71'

Filed under: OpenSimulator No Comments

Pages

Categories

twitter.com/lbsa71

    Blogroll

    Comics

    Meta