Welcome to MSDN Blogs Sign in | Join | Help

Rule's Roost

Jeremy Rule's blog

Syndication

Using Cloud Services from Second Life

online_small

I was playing around with building scripted objects in Second Life and ran across a function to pull text from the web. I thought it might be neat to create Live Messenger buddy object in Second Life that showed whether I was online or offline. I figured I could query the Windows Live Presence API directly from script and be done. Unfortunately it turns out there is a bit of a gap between Second Life and Windows Live. The Presence API serves up information by way of JSON. Second Life does not know what to do with JSON file coming back as the payload and gives an error.

Given this gap, I thought Azure might make a nice bridge. I could call the Live Presence API from a cloud based service, reproduce the information in a very simple format for Second Life, and then consume the new service with an HTTP call in Second Life.

I had to accomplish three things in order to get everything wired up.

  1. Put something in the cloud to provide a simple service 
  2. Consume JSON from server code instead of a browser
  3. Connect Second Life to Azure

To get started, I registered for the Azure Community Technical Preview. This gave me a sandbox in the cloud to play with and I downloaded the free Visual Studio 2008 Web Developer 2008 which provided all the power I needed for this little project. Once in Visual Studio I created a new Web Cloud Service and used the following code.

   1: using System.Net;
   2: using System.IO;
   3: using System.Text;
   4: using System.Runtime.Serialization.Json; 
   5:  
   6: namespace SecondLife_WebRole
   7: {
   8:  
   9:     [Serializable]
  10:     public class Presence
  11:     {
  12:         public string status;
  13:         public string displayName;
  14:     }
  15:  
  16:     public partial class _Default : System.Web.UI.Page
  17:     {
  18:         string LiveUrl = 
  19:          "http://messenger.services.live.com/users/5a11680377739a32@apps.messenger.live.com/presence";
  20:  
  21:         protected void Page_Load(object sender, EventArgs e)
  22:         {
  23:             // Make a web request to Live service
  24:             HttpWebRequest request = (HttpWebRequest)WebRequest.Create(LiveUrl);
  25:             HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  26:  
  27:             // Hydrate a .Net object from the JSON response
  28:             Stream receiveStream = response.GetResponseStream();
  29:             DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Presence));
  30:             Presence presence = ser.ReadObject(receiveStream) as Presence;
  31:  
  32:             // Output very simple text so Second Life can consume it
  33:             Response.Clear();
  34:             Response.ContentType = "text/plain";
  35:             Response.Write(presence.status + "\n");
  36:             Response.Write(presence.displayName + "\n");
  37:         }
  38:     }
  39: }

I was pretty happy that the .NET Framework had a JSON helper class and a rich language with C# to work with the data. This code worked fine from an ASP.Net application but not from a cloud application. Turns out I needed to set enableNativeCodeExecution to true so that the stream classes would not hit a security exception.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <ServiceDefinition name="SecondLife" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
   3:   <WebRole name="WebRole" enableNativeCodeExecution="true">
   4:     <InputEndpoints>
   5:       <!-- Must use port 80 for http and port 443 for https when running in the cloud -->
   6:       <InputEndpoint name="HttpIn" protocol="http" port="80" />
   7:     </InputEndpoints>
   8:   </WebRole>
   9: </ServiceDefinition>

Once I had that working, I used the cloud deploy feature of Azure to get the service hosted. It worked and my service was now serving something easily consumable by Second Life:

browser

Finally I went into Second Life and added script to a buddy object created all in-game.  The Second Life script simply makes an HTTP request to the cloud service and returns the very-simple-to-parse name and status. If I am online, i set the object to light blue and glowing and if I am offline, I dim the object and use a darker color.

// Use an Azure service in the cloud to get Live Messenger status

string AZUREHOST = "http://secondlife.cloudapp.net/Default.aspx";
key http_request_id;

default
{

touch_start(integer total_number)
{
llSetText("", <1,1,1>, 1.0);
string response = "";
http_request_id = llHTTPRequest(AZUREHOST, [], "");
}

http_response(key request_id, integer status, list metadata, string body)
{
if (request_id == http_request_id)
{
list lines = llParseString2List(body, ["\n"], []);
string status = llList2String(lines, 0);
string name = llList2String(lines, 1);

if (status == "Online")
{
llSetText(name + " is Online", <0,0,1>, 1);
llSetLinkColor(LINK_SET, <0.15686, 0.58039, 1.00000>, ALL_SIDES);
llSetLinkPrimitiveParams(LINK_SET, [PRIM_GLOW, ALL_SIDES, .1] );
llSetLinkPrimitiveParams(LINK_SET, [PRIM_BUMP_SHINY, ALL_SIDES, PRIM_SHINY_LOW, PRIM_BUMP_BRIGHT] );

}
else // user offline
{
llSetText("User Offline", <0,0,1>, 1);
llSetLinkColor(LINK_SET, <0.38824, 0.38824, .38824>, ALL_SIDES);
llSetLinkPrimitiveParams(LINK_SET, [PRIM_GLOW, ALL_SIDES, 0] );
llSetLinkPrimitiveParams(LINK_SET, [PRIM_BUMP_SHINY, ALL_SIDES, PRIM_SHINY_NONE, PRIM_BUMP_NONE] );

}

}
}

}
 
The Messenger buddy in second life is darker with no glow if I am logged out of Messenger. For Second Life builders, buddy is 10 prims big:
Offline

… but when I’m logged into Messenger, buddy lights up like a Christmas light:

 Online

 

So what's the big deal? Why use Azure for such a little thing? I think the answer is that it is such a "little thing." As a developer I just wanted to get my service online and working. I didn't want to have to go find a hosting provider, sign up and spend a bunch of money, and then take a few days trying to get everything working. I'd rather just spend time on getting the code to work. If I add significant features later on, or make the service public, I am confident Azure will scale with me. Again, I can just focus on the functionality of the service and not worry about scale and configuration.

When I account for my time on this project, I’m pretty happy with the breakdown. Much of the time was spent on community: Ben Williams pointed me towards the Windows Live Presence API. Jim O’Neil gave me a rough architecture by suggesting I try a WebRequest and then use the JSON Serializer.  The venerable Steve Marx helped me debug by showing me the enableNativeCodeExecution flag. Second Life resident and coffee machine builder, amira Mathilde helped me craft the “buddy” object so it wasn’t terrible looking.

My Second Life resident is “Macaw Roogus” so say hi to me if you see me online and maybe we can find some more interesting things to build.

Posted Wednesday, April 22, 2009 4:02 PM by jrule | 5 Comments

The Ingenuity Point Contest

June 26 - October 31 2007

http://www.theingenuitypoint.com/main/default.aspx

Microsoft is holding a contest to showcase applications written for healthcare, clean technology, and education. Just looking through the People's Choice Gallery... some neat entries and pretty good odds of winning a trip to France.

 

 

 

Posted Tuesday, August 21, 2007 4:20 PM by jrule | 0 Comments

Filed under: ,

Looking for a Solutions Architect in the SF Bay Area

http://members.microsoft.com/careers/search/details.aspx?JobID=DCDAF7C0-9826-4DD3-B8AD-11B7F4EC41E1

Drop me a note with your resume if you are interested!

 

 

 

Posted Tuesday, July 17, 2007 10:39 AM by jrule | 1 Comments

Microsoft SQL Server 2005 Administrator's Companion

 My friend Burzin Patel co-authored a book on SQL Server. Get all your SQL Server knobs turned in the right direction with this book. 

 

Posted Wednesday, January 03, 2007 3:22 PM by jrule | 1 Comments

Prolog.NET? You bet!

Eugene Asahara has launched SoftCodedLogic.com. The same idea of soft coding UI and data has been extended to program logic. Eugene's implementation is a clever update to prolog to bring it into the world of SQL, XML, and .NET.

 

 

Posted Tuesday, January 03, 2006 9:15 AM by jrule | 1 Comments

Build Master: Microsoft's Software Configuration Management Best Practices

My colleague, Vince Maraia, has come out with a book on configuration management called The Build Master.

Posted Tuesday, November 08, 2005 7:32 PM by jrule | 0 Comments

Windows for Musicians

Jim Owen, a Technical Account Manager at Microsoft, made a clever song using keyboards and the Windows sounds.

Have a listen.

 

Posted Monday, October 31, 2005 2:54 PM by jrule | 1 Comments

Partner Services Hiring - Bay Area - App. Dev. Consultant

Are you gosu with .NET? Email me your resume. I'll get the full job description posted on the microsoft.com careers site soon.

Deep .Net development expertise

n       C#, J# if possible

n       Extensive experience with performance testing and optimization of .Net applications, and ASP.Net on IIS optimization

o        Profiling

o        Debugging with symbols and trouble shooting application bottlenecks

o        Analysis of performance data

o        Expertise with a myriad of testing/profiling tools

 

Posted Tuesday, April 19, 2005 1:22 PM by jrule | 1 Comments

The Excel Web Query and Predicting the Washington State Governor's Race

Web Queries in Excel let you grab tabular data off of a web page without writing any code or messing with web services. I use this feature all the time as a manager trying to grab internal business data off of many different systems in order to analyze it. In this example, I build a computer model of the political race. The entire project can be done in less than 20 minutes.

  1. Open Excel 2003
  2. Choose Data | Import External Data | New Web Query...
  3. Browse to http://vote.wa.gov/general/status.aspx and select the table that lists ballots left to be counted by county. 

  4. After the table is imported do it again for the results in the race found so far found at http://vote.wa.gov/general/resultsbycounty.aspx?o=3001&t=s

  5. You should now have both tables side-by-side in Excel. You can color and format them however you like:

  6. Create further columns to find the percentage a candidate gets from each county and then multiply that percentage against the remaining ballots in that county.

  7. Finally, total the projected votes with the votes a candidate already has and you will arrive at a projected final outcome.

  8. Now here is the really cool part: whenever new totals are posted on the web sites you can update your spreadsheet with Data | Refresh Data. Excel keeps your nice formatting and fomulas and just gives you the new numbers.

A final solution can be downloaded here.

 

Posted Friday, November 12, 2004 3:42 PM by jrule | 4 Comments

Eugene's blog online

Check it out. One of the most brilliant people I know:

http://weblogs.asp.net/eugenea

 

Posted Wednesday, September 22, 2004 9:48 AM by jrule | 1 Comments

Dynamic Image Generation with ASP.Net

I've was playing around with image generation. Below is a picture of Josh who is a very interesting guy. His picture worked quite well because it was a clean slate to write text on.

The HTML tag <img src="http://www.rulesroost.com/josh.aspx?Text=Got%20Milk?"> produces:

 

And <img src="http://www.rulesroost.com/josh.aspx?Text=This%20is%20a%20much%20longer%20sentence."> shows:

 
And here is the code for the aspx file:

1<%@ OutputCache Duration="500" VaryByParam="Text" %>
2<%@ Page Language="C#" trace="false" Explicit="true" aspcompat="true" Debug="true" %>
3<%@ Import Namespace="System" %>
4<%@ Import Namespace="System.IO" %>
5<%@ Import Namespace="System.Text" %>
6<%@ Import Namespace="System.Drawing" %>
7<%@ Import Namespace="System.Drawing.Imaging" %>
8<%@ Import Namespace="System.Drawing.Text" %>
9<%@ Import Namespace="System.Drawing.Drawing2D" %>
10
11<script runat="server">
12 private void Page_Load(object sender, System.EventArgs e)
13 {
14 Bitmap bitmap = new Bitmap(Server.MapPath("josh.bmp"));
15 MemoryStream memStream = new MemoryStream();
16
17 // generate image
18
19 // Create a graphics object for drawing.
20 Graphics g = Graphics.FromImage(bitmap);
21 g.SmoothingMode = SmoothingMode.AntiAlias;
22
23 int width = bitmap.Width;
24 int height = bitmap.Height;
25
26 string familyName = "Tahoma";
27 string text = Request.Params["Text"];
28
29 // get a rectangle on his shirt
30 Rectangle rect = new Rectangle(150, 216, 210, 135);
31
32 // Set up the text font.
33 Font font;
34 font = new Font(familyName, 16F, FontStyle.Regular);
35
36 // Set up the text format.
37 StringFormat format = new StringFormat();
38 format.Alignment = StringAlignment.Center;
39 format.LineAlignment = StringAlignment.Center;
40
41 // Create a path using the text and warp it to fit over his contour
42 GraphicsPath path = new GraphicsPath();
43 path.AddString(text, font.FontFamily, (int) font.Style, font.Size, rect, format);
44
45 PointF[] points =
46 {
47 new PointF(rect.X - 10, rect.Y - 8),
48 new PointF(rect.X + rect.Width - 20, rect.Y + 4),
49 new PointF(rect.X - 8, rect.Y + rect.Height - 15),
50 new PointF(rect.X + rect.Width - 10, rect.Y + rect.Height + 4)
51 };
52 Matrix matrix = new Matrix();
53 matrix.Translate(0F, 0F);
54 path.Warp(points, rect, matrix, WarpMode.Perspective, 0F);
55
56 // Draw the text.
57 HatchBrush hatchBrush = new HatchBrush(
58 HatchStyle.LargeConfetti,
59 Color.LightGray,
60 Color.DarkGray);
61
62 g.FillPath(hatchBrush, path);
63
64 Response.Clear();
65 Response.ContentType="image/jpeg";
66 bitmap.Save(memStream, ImageFormat.Jpeg);
67 memStream.WriteTo(Response.OutputStream);
68
69 // Clean up.
70 font.Dispose();
71 hatchBrush.Dispose();
72 g.Dispose();
73 bitmap.Dispose();
74
75 }
76
77</script>
78
 
Notice the Reponse.ContentType="image/jpeg" - that causes the output to be a picture and not HTML. 
Also notice the word-wrap is done for me with the StringFormat object.
Other resources:

 

Posted Monday, August 16, 2004 4:11 PM by jrule | 13 Comments

Fark.com Photoshop Contest

“Photoshop what the classic Nintendo games would have been like had they been owned by Microsoft originally”

A few of my favorites:

 

 

Posted Monday, August 09, 2004 12:20 PM by jrule | 3 Comments

Data Protection API (DPAPI)

I've noticed that some recent blog entries talk about the new .NET framework supporting Data Protection API.

What is the Data Protection API? The DPAPI is used to hide secrets like connection strings and user credentials that are typically stored in a config file. Instead of storing the plain text, you can use DPAPI to encrypt and decrypt the secrets at a machine or user specific level.

A couple years ago I posted a sample DPAPI component on GotDotNet. It's still there and you can use it until the real Data Protection API comes out with the next Visual Studio. There are some warts with this one so read the comments people posted in the download link.

The component comes with a WinForms and WebForms example:

 

Code behind the Encrypt button:


1private void Encrypt_Click(object sender, System.EventArgs e)
2 {
3 byte[] entropy = new byte[0];
4 if (UseEntropy.Checked)
5 {
6 entropy = Encoding.Unicode.GetBytes(EntropyText.Text);
7 }
8
9 DataProtector dp = new DataProtector(Store.MachineStore);
10 byte[] dataToEncrypt = Encoding.Unicode.GetBytes(SecretText.Text);
11
12 try
13 {
14 CipherText.Text = Convert.ToBase64String(dp.Encrypt(dataToEncrypt, entropy));
15 }
16 catch (Exception ex)
17 {
18 MessageBox.Show(ex.Message);
19 }
20
21 }

 

Code behind the Decrypt button:


1private void Decrypt_Click(object sender, System.EventArgs e)
2 {
3 byte[] entropy = new byte[0];
4 if (UseEntropy.Checked)
5 {
6 entropy = Encoding.Unicode.GetBytes(EntropyText.Text);
7 }
8
9 DataProtector dp = new DataProtector(Store.MachineStore);
10 byte[] dataToDecrypt = Convert.FromBase64String(CipherText.Text);
11
12 try
13 {
14 DecryptResults.Text = Encoding.Unicode.GetString(dp.Decrypt(dataToDecrypt, entropy));
15 }
16 catch (Exception ex)
17 {
18 MessageBox.Show(ex.Message);
19 }
20
21 }

 

The DataProtector class imports CryptProtectData and CryptUnprotectData from the CryptoAPI to do the work.

Other options:

  1. The .Net Security Blog has two articles on DPAPI.
  2. MSDN has an article on DPAPI that you could use to construct a component.
  3. Jerry Dixon has an excellent DPAPI wrapper posted on his blog.

Posted Tuesday, August 03, 2004 1:44 PM by jrule | 2 Comments

99 Bottles Of Beer

Many years ago (1994) programmer, and my geek idol, Tim Robinson compiled a list of ways to output the lyrics to the song 99 Bottles of Beer. It started with someone posting to a mailing list the entire lyrics to the song and then someone else replied with a Basic version of the song:

10 REM BASIC Version of 99 Bottles of beer
20 FOR X=100 TO 1 STEP -1
30 PRINT X;"Bottle(s) of beer on the wall,";X;"bottle(s) of beer"
40 PRINT "Take one down and pass it around,"
50 PRINT X-1;"bottle(s) of beer on the wall"
60 NEXT

Tim posted a C++ version and it grew from there to hundreds of versions. Unfortunately Tim's web site (and Tim) disappeared from the 'net and all was lost for a few years. Now, Oliver Schade has posted the entire collection and then some on a web site: http://www.99-bottles-of-beer.net.

One of my contributions was Modula-2:

MODULE BottlesOfBeer;

FROM InOut IMPORT WriteCard, WriteString, WriteLn;

CONST
        BOTTLES = 99;
VAR
        counter : CARDINAL;
BEGIN
        counter := BOTTLES;
        REPEAT
                WriteCard( counter,2 );
                WriteString(" bottles of beer on the wall, ");
                WriteCard( counter,2 );
                WriteString(" bottles of beer."); WriteLn;
                WriteString(" Take one down, and pass it around, ");
                DEC( counter );
                WriteCard( counter,2 );
                WriteString(" bottles of beer on the wall."); WriteLn;
        UNTIL ( counter = 1 );
        WriteString("1 bottle of beer on the wall, 1 bottle of beer"); WriteLn;
        WriteString("Take it down and pass it around, ");
        WriteString("No more bottles of beer on the wall."); WriteLn;

END BottlesOfBeer.

What I enjoy about this catalog is that people tried to incorporate features from the language. Along with the usual cast of languages like SQL, C#, and various C++ versions, some clever languages were posted. Here are some of my favorites:

SmallTalk

99 to: 1 by: -1 do: [ :i |
 i print. ' bottles of beer on the wall, ' print.
 i print. ' bottles of beer. ' print.
 'take one down, pass it around, ' print.
 (i-1) print. ' bottles of beer on the wall, ' print.
]

Meta HTML

<html>
<head> <title> 99 Bottles of Beer: The Compleat Lyrics </title> </head>
<body>
;;;
;;; The actual source code to The Compleat Lyrics.
<defsubst plural whitespace=delete>
  <if <not <eq %0 1>> s>
</defsubst>
<set-var beers=99>
<while <gt beers 0>>
  <get-var beers> bottle<plural beers> of beer on the wall, <br>
  <get-var beers> bottle<plural beers> of beer, <br>
  You take one down, pass it around, <br>
  <decrement beers>
  <get-var beers> bottle<plural beers> of beer on the wall.
  <p>
</while>
No more bottles of beer on the wall, <br>
No more bottles of beer, <br>
Go to the store, and buy some more, <br>
<form method=GET action="<get-var mhtml::current-url>">
  <input type="submit" name="button" value="99 Bottles of beer on the wall">
</form>
</body>
</html>

Perl for Signature

#!/usr/bin/perl -iake_one_down_pass_it_around:_bottles_of_beer:_on_the_wall:99
for(($t,$a,$b,$i)=split/:/,$^I;$i;print){$_="-$i$a$b,-$i$a,-T$t,-".--$i."$a$b
";s/(-1_.*?e)s/$1/g;y/_-/ \n/}#     by Randolph Chung and Joey Hess

POV Ray

POV-Ray is a ray-tracing program.
// povray 3 file for the 99 bottles of beer ...
#declare S1 = " bottles"
#declare L1 = " of beer on the wall,\n"
#declare L2 = " of beer.\n"
#declare L3 = "Take one down and pass it around,\n"
#declare L4 = " of beer on the wall.\n\n"
#declare Beer = 99
#declare S2 = concat(str(Beer,0,0),S1)
#render "\n"
#while (Beer > 0)
  #render concat(S2,L1)
  #render concat(S2,L2)
  #render L3
  #declare Beer = Beer - 1
  #if (Beer = 1)
    #declare S2 = "1 bottle"
  #else
    #if (Beer = 0)
      #declare S2 = "No more bottles"
    #else
      #declare S2 = concat(str(Beer,0,0),S1)
    #end
  #end
  #render concat(S2,L4)
#end
sphere { 0, 1 pigment { colour rgb <1,0,0> } }
light_source { x*2, colour rgb 1 }
camera {
  perspective
  location x*2
  look_at 0
}

There are also some unmentionables like this one and this one. 621 versions so far. One glaring omission is Managed C++ [looks over at Yves Dolce]. I also wonder whatever happened to Tim Robinson. He was the brains behind Excalibur BBS which was a Windows based BBS that served up screens with meta-driven GUI. Instead of writing classic BBS doors you would write DLL add-in's. It was unfortunately timed to come out just as the WWW was emerging but the software was very cool nonetheless. 

 

Posted Friday, July 30, 2004 12:43 PM by jrule | 6 Comments

Giant Fresnel Lens

I found a company that sells giant fresnel lenses. What is a Fresnel lens? Think of a lighthouse or the top of an overhead projector. As light goes through the lens, spiral cut ridges focus the light to a focal point. You end up with the equivalent of a giant magnifying glass or parabolic mirror. There is some really juicy math invovled in calculating how to create a lens, determining the focal length and lens strength.

I framed the lens with some 2“x2“ lumber and secured it with electrical tape. When I carried the lens out of the garage, I knew we were in for a good show. The asphalt driveway started smoking. Our first target was a penny which the lens quickly melted into slag. Next up was a hamburger. We widened the focus and it flash cooked the top of the burger.

 

What I learned:

  1. You really need welding goggles. I have none so we had to use a spotter from a distance to help us focus. If you knelt down and tried to focus it without eye protection, you would surely suffer eye damage.
  2. If the sun is directly overhead, the lens is easier to focus and burns significantly hotter.
  3. Burgers cooked with a giant death ray don't taste very good. It's about like cooking in a microwave: you don't get the smoky taste that a BBQ gives you.

 

Posted Thursday, July 29, 2004 2:17 PM by jrule | 32 Comments

More Posts Next page »
Page view tracker