Articles by Rob

You are currently browsing Rob’s articles.

In OpenSim you’re not just restricted to using LSL for scripting, it’s also possible to use c#. This opens up the possiblilities for far more powerful scripts that can access c# in built libraries.

For example I’ve previously mentioned that the string processing methods in Second Life are not very flexible when it comes to reading formatted data. Thus the reason I implemented the osParseJSON method to make Web APIs easier to use.

Obviously another common data format is XML, in this case I don’t have to implement any new OpenSim script functions because the XML capabilities are available natively in c#.

Here is a simple example of reading the RSS feed for my blog, and reading out the entries in chat.


//c#
// displays the contents of an RSS 2.0 feed

string URL = “http://robsmart.co.uk/feed”;
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
LSL_Types.LSLString requestID;

public void default_event_state_entry()
{
    llSay(0,”RSS reader current Feed is ” + URL);
    getFeedContent();

}

public void getFeedContent()
{
    requestID = llHTTPRequest(URL, new LSL_Types.list(), “” );
}

public void default_event_touch_start(LSL_Types.LSLInteger total_number)
{
    // read out the RSS feed.
    displayFeed();

}

public void displayFeed()
{
    System.Xml.XmlNodeList items = xDoc.GetElementsByTagName(”item”);

    for(int i=0;i
    {
        string title = items[i].SelectSingleNode(”title”).InnerXml;
        string link = items[i].SelectSingleNode(”link”).InnerXml;

        string description=”no description available”;

        if(items[i].SelectSingleNode(”description”)!=null)
            description = items[i].SelectSingleNode(”description”).InnerXml;

    llSay(0,title + “\n” + description + “\n”);
    }
}

public void default_event_http_response(LSL_Types.LSLString request_id, LSL_Types.LSLInteger status, LSL_Types.list metadata, LSL_Types.LSLString body)
{
    if (requestID == request_id)
    {
        // store the xml
        xDoc.LoadXml(body);

        // process the xml
        llOwnerSay(”loaded feed”);
    }
}

Tish Shute very kindly asked me to do an interview for her excellent blog over on Ugotrade. In the interview I discuss where OpenSim fits in with the rest of the Web and particularly how some of the recent work i’ve been doing makes it a more viable platform for consuming data and services from websites.

You can find the interview here.

OpenSim Web 2.0 contribution

As described over on Eightbar I have made my first contribution to the OpenSim opensource project. The contribution is in the form of a new scripting function called osParseJSON. This function allows a c# script in OpenSim to consume the JSON notation provided by many of the major Web 2.0 APIs provided by services such as Flickr and Google translation.

The following example is a script that uses the Google Translate API to let an OpenSim avatar translate ther conversations between 23 different languages.

(disclaimer - please read the terms of conditions of the Google translate API and abide by them)

//c#
// This script is written as an example use of the osParseJSON method
// it uses the Google translate API
// ensure you have read the terms and conditions of the Google translate API
// http://code.google.com/apis/ajaxlanguage/documentation/

LSL_Types.key requestID;
string sourceLang = "en";
string targetLang = "fr";

public void default_event_state_entry()
{
     llSay(0,"translator running say '/1 sentence' to translate something");
     llSay(0,"translator running say '/2 source langage' to change target language e.g. '/2 fr'");
     llSay(0,"translator running say '/3 target langage' to change source language e.g. '/3 en'");
     llSay(0,"translator running say '/4 help', to list languages");
     llListen(1, "", NULL_KEY, "");
     llListen(2, "", NULL_KEY, "");
     llListen(3, "", NULL_KEY, "");
     llListen(4, "", NULL_KEY, "");
}

public void default_event_touch_start(LSL_Types.LSLInteger total_number)
{
     llSay(0,"translator running say '/1 sentence' to translate something");
     llSay(0,"translator running say '/2 source langage' to change target language e.g. '/2 fr'");
     llSay(0,"translator running say '/3 target langage' to change source language e.g. '/3 en'");
     llSay(0,"translator running say '/4 help', to list languages");
}

public void default_event_http_response(LSL_Types.LSLString request_id, LSL_Types.LSLInteger status, LSL_Types.list metadata, LSL_Types.LSLString body)
{
        if (requestID == request_id)
        {
            // the Google JSON string returned wil be of the format
            //  {"responseData": {"translatedText":"Bonjour"}, "responseDetails": null, "responseStatus": 200}
            // call the osParseJSON method so we can read the contents 
            System.Collections.Hashtable response = (System.Collections.Hashtable) osParseJSON(body);
            System.Collections.Hashtable responsedata = (System.Collections.Hashtable) response["responseData"];

            llSay(0,(string)responsedata["translatedText"]);
        }
}

public void default_event_listen(LSL_Types.LSLInteger channelIn, LSL_Types.LSLString name, LSL_Types.LSLString id, LSL_Types.LSLString message)
{
    if(channelIn==1)
    {
        string toTranslate = (string) message;
        requestID = llHTTPRequest( "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q="+toTranslate+"&langpair="+sourceLang+"%7C"+targetLang, new LSL_Types.list(), "" );  

    }
    else if(channelIn==2)
    {
        sourceLang = (string) message;
    }
    else if(channelIn==3)
    {
        targetLang = (string)message;
    }
    else if(channelIn==4)
    {
        llOwnerSay("LANGUAGE (CODE)");
        llOwnerSay("*  Arabic (ar)");
        llOwnerSay("* Bulgarian (bg)");
        llOwnerSay("* Chinese (zh)");
        llOwnerSay("* Croatian (hr)");
        llOwnerSay("* Czech (cs)");
        llOwnerSay("* Danish (da)");
        llOwnerSay("* Dutch (nl)");
        llOwnerSay("* English (en)");
        llOwnerSay("* Finnish (fi)");
        llOwnerSay("* French (fr)");
        llOwnerSay("* German (de)");
        llOwnerSay("* Greek (el)");
        llOwnerSay("* Hindi (hi)");
        llOwnerSay("* Italian (it)");
        llOwnerSay("* Japanese (ja)");
        llOwnerSay("* Korean (ko)");
        llOwnerSay("* Norwegian(no) ");
        llOwnerSay("* Polish (pl)");
        llOwnerSay("* Portuguese (pt-PT)");
        llOwnerSay("* Romanian (ro)");
        llOwnerSay("* Russian (ru)");
        llOwnerSay("* Spanish (es)");
        llOwnerSay("* Swedish (sv)"); 

    }
}

Google ate my blog

A couple of days ago friends at work started telling me that Google was flagging my blog here at robsmart.co.uk as an infested host of nastiness brimming with malware. This was a bit of a shock and kind of an egg on your face moment as I consider myself savvy with this sort of stuff.

However it turns out the slightly old version of Wordpress i was running was open to a couple of SQL injection attacks, and i had been a bit lax in updating to the current version. Googles recent policy of scanning sites for security breaches and then flagging and removing them from search results has brought this to my attention.

So as a solution I deleted my old wordpress install and installed the latest version, one of the issues i found was a line of obfuscated javascript code embedded in the Wordpress theme i was using.

So now I’m all cleaned and security hitch free (promise).

But what about the problem of Google flagging and blocking my site. Well to fix that I used the Google Webmaster tools.

The first step was to add the robsmart.co.uk domain to the webmaster dashboard.

The next step was verifying it belonged to me.

verify ownership

For this i simply made a blank html file as instructed and uploaded it to my website.

next stage was to go to the overview tab and look at the problems listed. I’d completely replaced the wordpress install including the theme and been through each of the pages listed to check they were clean.

after that i hit the “request a review” option

The review happened within 24 hours, i’m now just waiting for the results to propagate back through the google search engine.

Aberdeen twister

While we were up near Aberdeen last weekend i spotted this interesting cloud formation not too far away. By coincidence it turns out that Hanans parents got caught in the middle of this, albeit sheltering in a coffee shop. Apparently it was extremely windy and hailing big chunks of ice…

twister

Computer Business Review magazine did a special edition for IBM Hursleys 50th anniversary, they interviewed me for the ‘future’ section. I’m still finding the ‘Smart says’ bit amusing…

You can have a quick peek here

Eightbar doodles

A group sketch i did using the wacom tablet for Roo’s leaving day. It still needs some more work as i kindda erm rushed it out :)

Eightbar crew

IBM Hursley ETS Rocket Day

My department at work held a rocket day this week, I slacked off a bit and didn’t actually make a rocket but spent my time doing a bit of filming with Hanans new video camera instead…

On a project I’m working on at the moment (Meedan) we need to be able search for content by geographic area as well as by topic …. e.g. give me all the blog articles from the Middle east that relate to the Iraq war.

Luckily we already have a means to geo-locate all this content (handy eh ? ) so we’ve assigned latitude and longitude values to each article/ blog post /conversation participant.

All thats needed then is a means to search by Geographic area.

We’re using PostgreSQL a pretty heavy weight database baring a much closer resemblance to Db2 rather than MySQL. It has some pretty neat geographic search features courtesy of the PostGIS extension. This allows you to perform searches inside lat/lon boundaries of varying complexity as well as many other neat geo functions. These boundaries are defined in a markup called Well Known Text (WKT), for our purpose we search by polygons that are made up of lat/lon points that mark out the geographic search areas, both PostGIS and DB2 spatial extender uses this format.

So that’s all the big pieces in place, the only missing piece is a set of lat/lon points that define the areas we wish to search. I may have been blind or searching for the wrong terms but i couldnt find a set of this data anywhere on the Internet (please point me to a source if you know one). As we only needed the rough continent outlines I decided it would be a fairly trivial effort to make a tool to create the sets of lat/lon points in the correct WKT format for our searches.

map tool

Basically you click around the area you want to define and the hit ‘generate polygon’ this will give a nice WKT formatted polygon ready to use in an SQL query. If you want to delete a point just click on it a second time.

At the moment you just create an area generate the polgon and do the next one.

Next up I may add some storage so that people can share these datasets with each other or come back and change them at a later date.

For now here is the mapping tool.

Troika Binary art

I could watch this all day :)

« Older entries