Thursday, June 30, 2005

More Google Earth

I've just been giddy about Google Earth (new name for the old Keyhole), and it seems like every time I play with it, I discover more and more of the featureset (yeah, I know, RTFM, but it's way more fun to discover features than to read about them beforehand).

Two things totally blew me away today. Actually three, but two of them are combined.

1. 3D buildings: I turned on the checkbox for "3D Buildings", and it streamed in some shapes for buildings in selected metro areas. Big whoop, I thought, as I saw these gray shapes start to cover up the areas of my map. But then I discovered that you can tilt the camera view, so that instead of just looking straight down, you get a perspective view, and then the 3D Buildings really make sense, because you get a skyline representation of a cityscape instead of just a flat map. WAY COOL!

2. Terrain: Living in NW Ohio (and that's what I've spent a lot of time panning around), you don't get the feel for what the "Terrain" option does. But, head out to the Grand Canyon (use the Sightseeing link to automatically fly out there), use the tilt mode with Terrain turned on, and you'll see why this is the best thing in the world! Pick a spot with a lot of geographic features (dramatic elevation changes), and spin around it. The underlying elevations are displayed in 3D!

http://earth.google.com/images/grandcanyon.jpg


TO MICROSOFT FLIGHT SIMULATOR TEAM: If you haven't started already, then you MUST implement this functionality into your scenery! This is what FS is currently lacking! There's no longer any acceptable reason for why I can't fly over an area of the country and not see real imagery (Keyhole, and now Google Earth, proved that point).

Wednesday, June 29, 2005

Carl Franklin Songs: Oldies

So, [obligatory Redmond introduction] I was going through my basement this evening, and came across the box of stuff that I've kept since we moved offices a couple of years ago. In the box was my copy of Visual Basic 4.0 Internet Programming by none other than Carl Franklin.

What I was most interested in was the CD, because I remembered that Carl had included a couple of audio tracks along with the book's data, and I had only listened to the CD once before sometime around 1997. As a regular listener of Toy Boy (i.e., at the beginning and end of every DNR episode), I've gained a certain appreciation for the Sounds o' Franklin.

Anyways, the CD includes three tracks: St. James Infirmary, Bear, and The Last Steam Engine Train. As a beginning guitarist myself, who still finds it hard to go from a G to a D without pausing whatever song I'm struggling to play, I'm absolutely amazed at Carl's abilities when I listen to The Last Steam Engine Train. But, I think of these three, I like Bear the best, which Carl notes as being an original.

Ring Tones

As I sit here, coding and listening to DNR episode 55 (Kevin McNeish), I hear someone's cell phone ringing on their desk--even through my big headphones.

Seems this guy sitting next to me just got up and walked away, leaving his phone behind. Meanwhile, the caller probably thinks that my cubicle neighbor is ignoring the incoming call, so continues to call back. Over and over and over and over.....

This in itself is not that irritating. The phone's ringtone, however, is! Let's just say that I now cannot get the Pink Panther's themesong out of my head.

And thinking about that, I've noticed over the past couple of months that it seems that an unusually high number of people around here have this same ringtone. At first, I thought it was a cultural thing, since most of the time it seems like it's a H-1B employee who is in posession of the Pink-Panther-Squawking-Cell-Phone.

Then, it dawned on me that it's probably more of a reflection of my client and who their mascot is. I'll leave it as an exercise to the reader to figure out who my client is.

Include Namespaces in Sample Code

To people providing code examples: Please, please, please include the class's namespace in your code (use fully-qualified classnames). For example, instead of x=new XmlDocument(); use x=new System.Xml.XmlDocument();

It's easy for someone to put a "using" at the top of a code block, but most people posting sample code on the internet only paste snippets of code, and without having the "using" blocks, we have no idea which namespace the objects belong to!

So, unless the class comes from the System namespace, include the fully-qualified classname in your code. It will go a long way to helping people read and understand your code snippets.

Note to self: Make sure that I use fully-qualified classnames in all of my sample code.....

Northwest Ohio .NET User Group

I discovered that we (Toledo) had a local .NET user group after the spring MSDN event a couple of months ago. Last night, I had the opportunity to attend an actual meeting to see what it's all about.

The speaker was member Joseph Poirier who gave a presentation surrounding some of the process and difficulties that he encountered while developing a mobile dispatch application (that runs on an Intermec PPC). The lessons learned were probably useful, but Joseph made the fatal mistake of installing VS2005 beta 2 on his presentation machine that same day, and not verifying that the application that he was demonstrating correctly ported over to the new environment.

One thing that I learned, realized, or at least started thinking about, is the need to properly secure passwords in XML config files. Typically, I don't store passwords in this manner, but then again, I remember having some connection strings in plain text, which is probably a bad practice.

The decision to make is whether to fully encrypt the string using a strong encryption (System.Security.Cryptography namespace), or to perform your own encryption which is just strong enough to keep prying eyes from discovering the contents.

An algorithm to do the latter may resemble:

1. Convert string to byte array
2. Reverse bytes
3. For each byte in array, XOR the value with (A5H + byte index)
4. Store the Base64 of the byte array in the config file.

The benefit of this approach is that it's just strong enough to be effective, does not require complex code (not many people know how to use all of the Cryptography classes, myself included), and may be faster (I haven't benchmarked anything, so please flame away if this is not true).

// Encrypt/encode a string
string plaintext = Console.ReadLine();

byte[] arry = System.Text.Encoding.ASCII.GetBytes(plaintext);

Array.Reverse(arry);

for (int i=0; i < arry.Length; i++)
{
arry[i] ^= (byte)(0xa5 + i);
}

string base64 = Convert.ToBase64String(arry);

Console.WriteLine(base64);


// Decrypt a previously encoded string

byte[] newarry = Convert.FromBase64String(base64);

for (int i=0; i < newarry.Length; i++)
{
newarry[i] ^= (byte)(0xa5 + i);
}

Array.Reverse(newarry);

string newplaintext = System.Text.Encoding.ASCII.GetString(newarry);

Console.WriteLine(newplaintext);
Console.ReadLine();

Tuesday, June 28, 2005

Google Earth

As a followup to my "Hunt for WMD's" post, be sure to check out Google Earth:

http://earth.google.com/

Google Maps is an awesome web application. But, if you're already connected to the web, and have a decent machine (with 3D graphics card), then load up this Lite version of the old Keyhole product, and enjoy all of the benefits of a rich desktop client!

At some point, Microsoft needs to stop trying to compete with all products. Competition is great for innovation, but I'm not sure if they can catch up with the GIS stuff that Google now has (especially after their aquisition of Keyhole).

You, Too, Can Help Search for WMDs in Iraq

Not sure what the date of the satellite images are, but now Google Maps has the world online!

Here's Baghdad from way up:

http://maps.google.com/maps?ll=33.318787,44.338074&spn=1.392517,1.944580&t=k&hl=en

Monday, June 27, 2005

MSDN Lab

Just found this. I'm guessing that it's MSDN's answer to Google Labs where new technology can be previewed before it's made mainstream. I hope to see some great stuff hosted here in the future.

http://lab.msdn.microsoft.com/

Feedburner Now Active

I'm trying out Feedburner for my blog's syndication:

http://feeds.feedburner.com/AViewInsideMyHead

Blogger.com provides an ATOM feed automatically (which Feedburner then consumes), but I get no stats with that. If you currently subscribe to my old feed, please update to use the new Feedburner feed (look for the XML link in the sidebar).

I have no idea at the moment if anyone using news aggregators even read my blog. Most of the traffic that I'm aware of comes from the major search engines.

I admit that my readership is likely very low, but I still write as if some time in the future, I'll get a lot of people wanting to read my past thoughts on various subjects. I think that this is the hallmark of a good blogger, especially one trying to establish a foothold in readership numbers--envision who your audience is, and then write for that audience, even if it does not exist today.

Sunday, June 26, 2005

More Cedar Point Rides

Today was our third visit to Cedar Point this season. Hot day, long lines... :( The babies got cranky after 3 hours (2 hours past their nap time), so we had to leave. We realized that, in the future, we'll probably just have one of us take the twins out to the van for a nap, and likely to relocate the vehicle to a closer parking spot at the same time. This way, the whole day isn't cut short after only a few hours, and my 7-year old and the other adult can still stay in the park.

But, we didn't leave before I got to ride a couple of things, so I'll add to my mini-reviews:

maXair: When you see this thing, you think, "There's no way in hell that I'm going on that!" But, let me tell you, it's not nearly as sickening as you think. This thing is an 80-foot high pendulum (think boat swing) that has a rotating seating platform (think carousel). The effect, while looks absolutely sickening from the ground, is surprisingly more like a roller coaster in feel than you would ever imagine. At the top of the pendulum swing, you can be 140 feet off of the ground and inverted upside down! Because of that, the seating is a conforming shell with shoulder restraints. I had no trouble fitting the seat, but heavier guests will likely need to skip this ride (there is a chair at the ride entrance that you can test-fit yourself, if you're on the large size).

Raptor: I LOVE THIS RIDE! It's got to be just about the most thrilling inverted coaster ever. By inverted, I mean that the track is above the train, and you sit on a seat so that your feet dangle, like a ski-lift. The ride does all kinds of wicked loops and twists, so the seat is again conforming with shoulder restraints. Larger guests beware, and trial-fit at the entrance.

Friday, June 24, 2005

Sandboxing

What would be the ultimate sandbox environment to help protect you from the bad guys on the Internet?

Well, running in Virtual PC is one way. If something rogue takes over your system, it's really only taking over the Virtual PC. Of course, for the normal person, this means that you need to buy an OS license for the VPC's installed OS.

Wouldn't it be cool if your browser (or OS) would abstract out access to the hard drive, and make all writes occur to a virtual/differencing/undo drive?!!

Think of it like this: You run an ActiveX control in your browser, and it needs to write to disk. Maybe this writing to disk is just installing the control in the first place. Doesn't matter, because what we want to avoid is allowing something from the internet to persist to the live hard drive.

The OS intercepts the disk I/O, and instead of denying the request (which breaks the ActiveX control), it simply writes to a shadow drive. When the ActiveX reads from disk, the shadow information supercedes any real-disk information (i.e., if no shadow info exists for the requested I/O, then real-disk info is provided if allowed). So, the ActiveX control really isn't aware that it's not looking at the real drive. And, this shadow information can be thrown away after the session ends.

Surely, this needs to be thought out some more. I just wanted to record the thought while it was more or less fresh in my mind.

SQL Server 2005 Management Studio bug???

I was composing an update query by hand today in Management Studio. I thought it was a simple SQL statement that simply joined my Control table to a Query table using two fields to link the tables. My original SQL looked like this:

update control
set policyprocedure=q.policyprocedure
from control join query q
on control.activityfk=q.activityfk
and control.systemfk=q.systemfk


Management Studio changed the SQL to be this:

UPDATE  Control
SET PolicyProcedure = Control.PolicyProcedure
FROM Control INNER JOIN
Query AS q ON Control.ActivityFK = q.activityfk
AND Control.SystemFK = q.systemfk


Notice that the SET now pulls the PolicyProcedure field from Control instead of my aliased Query (Q). That's not what I ordered!

I finally got the desired results (sans any changing of aliases by Management Studio) using this SQL:

UPDATE  Control
SET PolicyProcedure = x.policyprocedure
FROM (SELECT c.ControlID, q.policyprocedure
FROM Control AS c INNER JOIN
Query AS q ON c.SystemFK = q.systemfk
AND c.ActivityFK = q.activityfk) AS x
INNER JOIN
Control ON x.ControlID = Control.ControlID


Is this a bug, or am I a moron who needs to study up on SQL? Maybe I should have used a CROSS JOIN and WHERE clause in my original update query instead of the INNER JOIN?

Comments anyone?

SnVzdC Bmb3IgZn VuLi4u

TWFkZSB5b3UgbG9vay4gIFRhZywgeW91XCdyZ
SBpdC4gIE5vdyBibG9nIHlvdXIgb3duIEJhc2
UtNjQgZW5jb2RlZCBtZXNzYWdlLg==

Wednesday, June 22, 2005

Overuse of the XPath "//" Shortcut?

I see a lot of people using XPaths with the "//" shortcut (lazy paths). But, consider what the processor must do when evaluating this. For example:

[test]
[a]
[b]
[c]
[d /]
[/c]
[/b]
[e]
[b]
[f /]
[/b]
[/e]
[/a]
[/test]



Using the XPath /test/a/b will return one node.
I'm in total control over which node(s) are returned,
so long as they follow my path exactly:

[b]
[c]
[d /]
[/c]
[/b]



However, using the XPath //b will return two nodes:

[b]
[c]
[d /]
[/c]
[/b]



and

[b]
[f /]
[/b]


This is okay if it's what I expected. However, I would guess that in most cases, having the second [b] node returned would not be expected, and could break an application's code.

Also, with the "//" shortcut, the processor must crawl every node of your tree in order to look for matches. By specifying an XPath that is rooted at the document element, you eliminate the need for the processor to perform this branch crawling, which greatly increases the query performance.

Oh, and as a side note, I'm starting to get irritated with Blogger trying to be smarter than me in handling my code snippets. I'm the human, dammit! You don't always have to change my formatting.

Monday, June 20, 2005

Dot Net Rocks! The Movie

Just finished watching the Dot Net Rocks! 2004 DVD ($15 shipped from Franklins.NET). As a newly established regular listener of the show, I found it absolutely worth the small price.

Think of the DVD as a way of introducing you, the DNR listener, to the DNR hosts and guests using Video (in order to put a face with the name). The DVD switches between the triple view of the taping of show #69 (interviewing Richard Campbell) alternating between Rory, Carl, and Richard (in his pre-host days). In addition, there are scenes inserted from Tech*Ed 2004 and some gathering (Devteach?) that Carl went to in Montreal, Quebec, Canada.

In a funny, but related story, we were watching TV this past Saturday, and my wife does her normal channel surfing during the commercials of whatever regular channel she was watching. All of a sudden, I catch a glimpse of Rory Blyth on my TV. I order her to stop ("please, can we watch this, sweety? Pretty please....") and watch that channel for a little bit. Come to find out, the DNR staff (Carl and Rory, with Nick Landry and maybe someone else that I didn't recognize yet) was at Ceasar's hotel in Las Vegas, I'm assuming for some conference event. The reality show on A&E called Ceasars 24/7 was filming, and did a segment of the bunch of nerds!

I had heard a brief mention about an A&E special on DNR, but I haven't listened to all past episodes yet, so I didn't know any details. It was really cool that I stumbled upon it randomly thanks to the impatience of my wife and her channel speed-surfing abilities.

UPDATE: After reviewing my blog stats today, I notice that a link to this post is being passed around in an email.... hmmm. I welcome my new readers, and hope that you take the time to check out the rest of the blog.

Cedar Point

We went out to Cedar Point again over the weekend. Fathers Day turned out to be a pretty good day to go, and there was great weather this year (temp in 70's, sunny). The parking lot was only half full (up to row 33), and we managed to find a prime spot in row 21, which is just beyond the handicap row nearest the gates.

It must have been Gay Pride day, though, for we noticed an unusually high number of same-sex couples, some sporting pretty funny slogans on T-Shirts, and some dressed in stereotypic "flaming" attire.

The usual eye candy was out and about, but there's a disturbing trend starting where young teenagers are dressing like the older eye candiers. Also, I think braless-ness is a growing trend this year for some reason. Should make walking around the back part of Frontier Trail a little interesting (that's where the water rides are).

And now for my review of the coasters that I got to ride (only a few so far this year):

Blue Streak
This oldie is still pretty good. A wooden coaster built in the mid-1960's. I took my 7 year-old on it for the first time, and she found it pretty frightening. The seats are a lot narrower than I remember (or my waistline is a lot larger than I remember), and it doesn't seem to have as much negative G's as before.

Iron Dragon
My daughter loves this ride, maybe because the train is more enclosed than other rides, so she doesn't feel like she's going to fall out. It's a slower inverted coaster (one of the first of its kind, but later trumped by the Raptor), but still has some thrilling moments.

Gemini
A great wooden racing coaster with hardly any wait at all. In the end, my daughter said that this is a fun ride, but she didn't like the lift hill (that seems to be a recurring theme, and will probably persist until she gets used to the clack-clack-clack noise). The best parts of this coaster is when the track goes through the framing--you think you're going to hit the frame, but dip just in time. There's also a thrilling loop towards the end that provides for some increased G's.

Disaster Transport
This used to be the Avalanch Run, a bobsled coaster, when I was a kid. They later enclosed the whole thing in a big building and added special effects and blacklights to the waiting area to create an experience where you have to evacuate from some catastrophe. Much of the ride itself is in blackout conditions, which is absolutely a thrilling experience. My daughter could ride this over and over again! The building is air conditioned, which helps escape the heat on hot days.

Thursday, June 16, 2005

Z-Machine

I don't know for sure, but I would guess that not many people know what a Z-Machine is.

It's the name given to the virtual (imaginary) computer that ran the old Infocom text adventure games. Even today, decades after the fact, I'm amazed at the foresight that Joel Berez and Marc Blank had in architecting this system.

Very much like .NET (and even more like Java), the Z-Machine provides for a compile-once, run anywhere architecture. Story files were compiled for this imaginary computer, and then all that Infocom had to do was write an "emulator" or virtual machine for each platform that ran the Z-machine's byte code. Very cool!

I found the extremely well written The Z-Machine Standards Document by Graham Nelson on Peer Schaefer's if-resources site. It's 182 pages, but anyone interested in Emulation, Virtualization, Infocom games, Assembly Language, Embedded Architecture, etc, MUST CHECK THIS OUT!

Given that this virtual system was first designed on a coffee table in Pittsburg in 1979 with the intention of porting it to multiple 8-bit platforms that existed at that time, it will certainly give you an appreciation for how easy we have it today.

Also, I remember using disk editors and memory editors to try to find text used by the story files (in order to try to snoop around the various games), but could never find anything more than garbage. I always thought that Infocom either encrypted their text or used an alternate character set.

Well, it's actually a form of compression that they use by stuffing three characters into two bytes. The ZSCII character set was roughly based on ASCII, but used only 5-bits per character. 3 * 5 bits = 15 bits, with the high bit of each word serving as the string termination marker. That explains why I didn't see any plain text!

Oh, and the "Z" in Z-Machine stands for Zork.

Ongoing Quest for Ways to Integrate Reporting Services with Portals

I played around some more with the HTML renderer in reporting services, and found a combination of parameters that would be most useful for portal integration:


http://server/ReportServer?%2fsamples%2fsample
&rs:Command=Render&rs:Format=HTML3.2&rc:HTMLFragment=true
This causes HTML 3.2 output to be generated, and only a fragment (not complete HTML).

The result is that you'll get a [table] with your report in it. Use whatever method you can to place this in your portlet.

An interesting side effect for multiple-page reports: You'll get a continuously rendered report with [hr /] between each page unless you include a "rc:Section=1" parameter (which will then only show the first page).

SQL Server Templates

Who knew.... For years, I've used Query Analyzer to created stored procedures, etc. At times, I've even used the Templates feature to give me a starting point, and found myself using find-and-replace to change the parametersplaceholders.

For example:

IF EXISTS (SELECT *
FROM sysobjects
WHERE name = N'[scalar_function_name,]')
DROP FUNCTION [scalar_function_name,]
GO

CREATE FUNCTION [scalar_function_name,]
([@param1, sysname, @p1] [data_type_for_param1,],
[@param2, sysname, @p2] [data_type_for_param2,])
RETURNS
...
I installed the Yukon (SQL Server 2005) CTP bits last night because I need to get caught up on that technology. I used the Management Studio today to perform some work on my current project (against a SQL 2000 database), and created a new stored procedure.

Management Studio displayed the same type of familiar template, but in the comments, it displayed "Use the Specify Values for Template Parameters command (Ctrl-Shift-M) to fill in the parameter values below".

What's this "Specify Values for Template Parameters" command? Must be something new, I thought. I hit Ctrl-Shift-M, and up pops this window with each parameter, allowing me to specify my own values. It's an automatic multi-value find-and-replace mechanism that's built in!

I opened up the old Query Analyzer, and lo-and-behold, that feature's always been there! It even has a command in the Edit menu. I'm pretty traditional, so I don't think that I'll ever use it, but it's good to know that it's available if I need it.

Monday, June 13, 2005

Grok Talks

Yay! The first of the GrokTalks from Tech Ed have been posted!

http://mediaserver.aspsoft.com/blog/FirstBatchOf6VideosReady.aspx

(GrokTalks are quick 10-minute no-bullshit technology briefings)

Season Tickets

For the first time in my life, I finally broke down and bought season tickets to this place with the intention of forcing myself (and the family) to go more than once per year. Now we won't really have an excuse to head out some evening on a whim to the greatest amusement park in America (and arguably, the entire planet).

Sunday, June 12, 2005

Client-side Business Objects?

There's a lot of buzz around AJAX these days, and I started thinking about how this type of client-side code could be put to alternative use.

I was recently asked about how to interface a web page with code that reads from the PC's serial port. For example, if the PC is connected to a scale or other sensor via the serial port, and this data should automatically be available to a form on the web page.

Of course, the traditional "Use an ActiveX Control" solution came to mind, especially since I've created a control for this exact purpose in the past. Similarly, a UserControl written in .NET can be hosted by IE (after playing with CAS policies). But, then AJAX came to mind, and I thought of this solution:

  1. A native application runs on the client (perhaps as a service, or a console app, windows app, etc). Can be VB6, C/C++, .NET, Java, or whatever, so long as it can perform the tasks that follow.
  2. The native app is able to read and/or write to the serial port as required. Much of this code probably already exists if the developer was prototyping the communications code.
  3. The native app includes a HTTP listener. (I would lean towards .NET, since it's so easy to create and use HTTP listeners).
  4. The web page includes javascript code that does AJAX-like communications between the local "webserver" and the browser.
  5. Upon receiving a request via the HTTP listener, the native app does the serial port comminications necessary to retrieve the results, and then packages it up and sends it to the browser via the response object.

The beauty of this approach is that so much of the "Business Logic" can be written in the native/compiled code, which lets you do far more than what you can do with Javascript alone (image generation/processing anyone?). Also, the AJAX-like code doesn't have to be very long or very complex to interact with the native code, the browser is not limited to Internet Explorer, and the "server" is local, so network communications are reduced.

This was a simplified example of what I feel could become a cool architecture. If security issues could be overcome (nothing that ActiveX and Java Applets haven't struggled with, such as controlling permissions to filesystem and peripherals, etc), then custom business logic could be packaged as simple modules that plug into a master "listener".

This might actually fit well into my Personal Portal Server concept.

Friday, June 10, 2005

Why Not Base 11?

We all know how to count, right? 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. That covers the sum of most people's fingers. But, 10 usually indicates an overflow, or carry, in whatever base you're dealing with. It's the effect of maxing out the digits in the base set.

For instance, in binary, you count 0, 1, 10.

In hexadecimal, you count 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10.

When you count on your fingers, your 10th finger is not the carry--it's the last element in the set. So, counting on our fingers is actually using base 11, not base 10, since you don't carry the digit until you run out of fingers.

So, counting on your fingers should go like this: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, 10 (and 10 in this case is one more than when you run out of fingers).

This doesn't mean that I have 11 fingers, it means that when I hit 10 it shouldn't actually be called 10 because the carry/overflow hasn't occurred yet.

QmxvZyduIG15IHdheS B0byB0aGUgUERDIDA1

SSBhbSBhIGR5aW5nIGJyZWVkIHdpdGhpbiBteSBj
b21wYW55LCB0aGUgbGFzdCBvZiBhIGxvbmcKbGlu
ZSBvZiBjb2RlcnMgd2hvIGJlbGlldmUgaW4gc2lt
cGxpY2l0eS4gIFdoaWxlIGV2ZXJ5b25lIAplbHNl
IHNpbmdzIHRoZSBwcmFpc2VzIG9mIEoyRUUsIEkg
a2VlcCBteSBkaXN0YW5jZSBrbm93aW5nIAp0aGF0
IG15IHNvbHV0aW9ucyB3aWxsIGdldCBkZWxpdmVy
ZWQgZmFzdGVyIGFuZCBjaGVhcGVyIAp0aGFuIG15
IHBlZXJzLiAgSSBhbSBhIFByb2Zlc3Npb25hbCBN
aWNyb3NvZnQgRGV2ZWxvcGVyLgoKQW5kLCBzcGVh
a2luZyBvZiB0aGF0LCBJIG5lZWQgdG8ga25vdyBo
b3cgdG8gdXNlIG15IHRvb2xzIAptb3JlIGVmZmVj
dGl2ZWx5LCB3aGF0IHRvIGV4cGVjdCBmcm9tIHRo
ZSB1cGNvbWluZyBwcm9kdWN0IApyZWxlYXNlcywg
YW5kIG1vc3Qgb2YgYWxsLCBJIG5lZWQgdG8gY29s
bGVjdCBjb29sIHN3YWcgdGhhdCAKd2lsbCBtYWtl
IG15IEphdmEtYmFzZWQgcGVlcnMgamVhbG91cyEK
ClRoZSAyMDA1IFByb2Zlc3Npb25hbCBEZXZlbG9w
ZXJzIENvbmZlcmVuY2Ugd2lsbCBiZSBoZWxkCmZy
b20gU2VwdGVtYmVyIDEzLTE2IGF0IHRoZSBMQSBD
b252ZW50aW9uIENlbnRlci4gIERldGFpbHMKY2Fu
IGJlIGZvdW5kIGF0OiBodHRwOi8vbXNkbi5taWNy
b3NvZnQuY29tL2V2ZW50cy9wZGMvCgpTaG91bGQg
SSBhdHRlbmQsIHlvdSBjYW4gYmV0IHRoYXQgeW91
J2xsIGZpbmQgd3JpdGUtdXAncyAKYW5kIGhvdy10
bydzIHBvc3RlZCBoZXJlISAgU2hvdWxkIEkgbm90
IGF0dGVuZCwgdGhlbiB5b3UnbGwgCnByb2JhYmx5
IHN0aWxsIGZpbmQgd3JpdGUtdXAncyBhbmQgaG93
LXRvJ3MgcG9zdGVkIGhlcmUuCgpPaCwgYW5kIGJ5
IHRoZSB3YXksIHRoYW5rcyBmb3IgdGFraW5nIHRo
ZSB0aW1lIHRvIGRlY29kZSAKbXkgQmFzZTY0IGJs
b2cgbWVzc2FnZS4gIEhvcGVmdWxseSB5b3UgdXNl
ZCB0aGUgc2FtcGxlIGNvZGUgCnRoYXQgSSBwcm92
aWRlZCBpbiBteSBibG9nIGFuZCBjb3VsZCBzZWUg
anVzdCBob3cgZWFzeSB0aGUKLk5FVCBmcmFtZXdv
cmsgbWFrZXMgaXQgdG8gcGVyZm9ybSB0YXNrcyB0
aGF0IG9uY2UgcmVxdWlyZWQKYmxvY2tzIG9mIGNv
ZGUuCgo=


blogging my way to pdc


Note: Base64 Encoded ASCII string. Read the previous entry in my blog if you have no idea what this is.

Base 64 Encoding/Decoding using .NET

Sometimes binary data needs to be represented in a text-friendly format. For instance, maybe you need to include the bits of an image file within an XML document. To do this, we typically use Base64 Encoding.

Back in the VB6 days, I had a couple of subroutines that did my encoding and decoding for me. Now, with the .NET Framework, it's extremely easy to do.

For instance, to encode a string into Base64, you simply do the following:

string b64=Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(s));

But wait! Didn't I say that Base64 was used to encode binary data? Well, yes, but a string can be transformed into binary data (a.k.a., a byte[] array), and that binary data is what is transformed.

There are different ways to represent a string as bytes of data (remember that not everyone uses the same Character Set as us-english, so some languages must use Unicode). In this example, I use the ASCII encoding class's GetBytes() method to generate the byte array for me from my string variable named "s". Each character in "s" will be represented by a single byte in my array.

Decoding a Base64 string is similarly easy:

string s=System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(b64));

A little warning here: I had to guess that my Base64 data was ASCII encoded, so I used the GetString() method of the ASCII class to decode the byte array into a string. If you use the wrong text encoding class to decode the byte array, then you could get garbage data. If you control both ends of the conversion process, then this shouldn't be a problem, but you do need to be aware of what different encoding schemes are out there.

Here is the code for a console app that will decode Base64 strings for you. The assumption is that the byte array was ASCII encoded, as above. Run the application and type or paste your Base64 data into the console. Enter two blank lines at the end, and it will then display the decoded ASCII text.

Notice that if you want to use this as an encoder, then simply uncomment the encoding line and comment out the decoding line.


using System;

namespace scratch
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
string s="";

string y = Console.ReadLine();
while (y != "")
{
s += y + "\n";
y=Console.ReadLine();
if (y=="")
{
s+="\n";
y=Console.ReadLine();
}
}
// Convert collected string to Base64
// Console.WriteLine(
// Convert.ToBase64String(
// System.Text.Encoding.ASCII.GetBytes(s)));


// Convert collected Base64 string to ASCII
Console.WriteLine(
System.Text.Encoding.ASCII.GetString(
Convert.FromBase64String(s)));

Console.ReadLine();
}
}
}

Thursday, June 09, 2005

My Thoughts on Portals

I work for a company that makes its fortune off of building portals for companies using IBM Websphere Portal Server. Personally, I've only been involved with one portal project (thankfully), but it gave me some real insight into why portals kind of suck.

First of all, I cannot believe how much money companies are willing to pay for what little they receive. I mean, just the price of the software alone is outrageous, and that only gives you a basic framework and a sample portal. I hope you didn't want anything relevant to your company for that $50-100k, because that will cost you extra! But, hey, it's IBM software written completely in Java (meaning that it's not Microsoft, so it's worth the price, right?)

So, let's say that a company just dropped $50K (or whatever the going price is) to buy Websphere Portal Server Enabled. Who's going to install and configure it? The local IT department???! Really smart people from my company who have been working with Websphere for years still have trouble getting all parts of the thing up and running, and keeping it running smoothly. And each new version of the product introduces new “bugs” that make it impossible to guarantee a perfect installation by a knowledgeable person.

Oh, and I hope you have a lot of new/powerful hardware with LOADS of memory and disk space (because remember, IBM is a hardware company first!), because it ain't gonna run for you unless you do. Our development environments require 1GB minimum RAM just to be usable. Plus, you'll want to cluster your production environment across multiple servers to improve overall performance, which introduces a whole heap-load of complexity to the configuration.

I'll have to say, though, that once a WPS portal is completed, that the whole thing is quite impressive. Perhaps in the same way that it is an awe-inspiring feat of engineering that we can send three people to the Moon and back, but in the end, you think about just how much money it took and wonder if the ROI was ever really there.

I'm not going to give a free pass to Microsoft SharePoint, though. While I'm happier with what they're calling a Portal with version 2 (versus the first version, where they slapped the Digital Dashboard onto the document management system and called it a portal), overall, it falls short of where it needs to be in order to draw companies away from WPS. I'll probably detail those shortcomings some other time when I have a comprehensive list, but my point is that SPS does not yet directly compete in the same space as WPS. And that gives my company a huge reason to continue pushing J2EE over .NET.

In my naive opinion, portal platforms are missing a key opportunity by making the technology server-centric. I mean, sure, being server-centric allows anyone from anywhere to connect to the portal with whatever browser is available on the machine that they happen to have access to. But, it also sends us back to the mentality of the mainframe and hub-spoke infrastructure model where you have an all-powerful machine in the center doing all of the work while dumb terminals exist only to provide the user an interface to the brains of the system.

My vision of portal technology places the aggregator at the client instead of the server. Or at least the concept of a “portal server” would be closely tied to one user instead of all of the users of a system. Let this “Personal Portal Server” be responsible for aggregating content and generating/caching the presentation. Then let the user decide what information needs to be displayed, even if that means combining Portlet/WebPart information from multiple providers onto one page.

If Google Maps and GMail has taught us anything, it's that the client (even a web browser) can offload a lot of processing from the server, and this is not much different than what I'm suggesting here. Centralized servers do not completely go away, but become specialized for the task at hand—providing specific content to a whole host of remote aggregators.

This concept really needs some refinement to become practical, but this is just a View Inside My Head at this moment.

Tuesday, June 07, 2005

Extracting Air From Water

Slashdot had an article the other day about an aparatus that would extract breathable air from water. The way that it works is that a battery powers a centrifuge, which lowers the pressure, allowing the trapped gasses to escape (due to Henry's Law). This is how fish breathe, in stark contrast to using electrolysis to separate hydrogen and oxygen.

I wanted to test this myself to see how it works. Instead of a centrifuge, I used a syringe (when my babies take antibiotics, the pharmacy always gives us a new syringe to use for dosing, so I have lots of them laying around).

I filled the syringe with a couple mL of tap water, got rid of extra air, and then put my thumb tightly over the opening. I then pulled back the plunger, thus lowering the pressure inside the syringe. Immediately, air bubbles began to form on the walls of the syringe (or at least it looked like air, but for all I know, it could be vacuum space). So, it works!

But, as soon as I released the plunger, the air bubbles dissolved back into the water. I wonder how the breathing aparatus inventor solved that issue???

PC's I've Used Over Time

I'll play along with John Koziol's post about odd computers that he's owned over time. I'll just list my history instead of claiming anything odd....

TRS-80 Model I/Level II: My first memories of any computer was that of my Dad sitting in the attic of our home with his Level II in the late 70's. Later, I remember him setting it up on our kitchen table so my brother and I could play with it. That was the same computer that I learned BASIC on (in way of typing in programs from various manuals).

What I remember most about it was that programs were loaded off of cassette tapes, with the computer being plugged into a headphone jack (or something similar) on the cassette recorder. Dad had tons of tapes around, with a large portion of them from "80 Micro" magazine, if I recall. Those cassettes came in handy years down the road when I routinely recorded songs off of the radio (and/or needed a tape for one of the Commodores). ;-)

TRS-80 Model III: My Dad's next computer was the Model III. I believe, if I reach back into the part of my memory that I've long since blocked out, that I was responsible for the death of the Level II. The Model III had dual floppy disk drives, and could play Zaxxon and Zork!

TRS-80 Model 100: Can you tell that my Dad was a frequent visitor to Radio Shack??? The Model 100 was a portable that used AA batteries. It had a small LCD display built into the same plane as the keyboard (not a clamshell like today's laptops), and sported a 300 baud modem built in! I remember sneaking this to school in the 6th grade and used it during an oral presentation instead of notebook paper.

Commodore VIC-20: This was my own computer, and I believe that I got it for my 7th or 8th birthday. Maybe it was Christmas... Can't remember, but at first, I only had the computer, and spent many hours typing in programs from COMPUTE! Gazette. I couldn't save the programs, though, so they were lost as soon as power was lost (or the computer locked up).

Then, I think for Christmas (or birthday, whichever was next), I got the Dataset, which was a silent cassette recorder (no speakers) that plugged into a data port. Finally, I could save programs!

TI-99/4A: I didn't actually own this computer, but my neighbor Mike Trumbauer did. He was a great programmer as a 4th/5th grader, and I'm sure he's gone on to become an impressive technologist (he moved away when I was young, and I heard that he went to Purdue). This guy could create from scratch a version of just about any video game, and they were actually fun to play! I remember versions of Missile Command and Donkey Kong for sure, but there were so many more.

Commodore 64: The defining moments of my childhood (and early teenage years) were spent programming this beast. I had the floppy drive, and 1200 baud modem, though that modem got me into a lot of trouble when a $300 phone bill came through. A Seikosha printer rounded the system out.

Three of us at school (Tim, Jon, and myself) shared warez (there, I said it), with some of the best things included were known as "Demos" (kind of a packaged marquee program that the pirate groups would include with the warez to play music and show text). We were also fans of the Infocom adventure games (Zork, Planetfall, Hitchikers Guide to the Galaxy, etc). But, this all leads to a little story that I think is humorous:

We had heard of these computer viruses that were infecting, well, probably IBM's. So, I told Tim that I had the latest copy of Double Dragon, or something cool like that. I give him the disk, he goes home and then LOAD "*", 8, 1 (something like that), and WHAM! There's a sprite of an evil looking PacMan floating around his screen with words that says "YOU ARE INFECTED WITH A VIRUS".... He promptly calls me sounding freaked out, and I let him in on the fact that I wrote the program the previous afternoon.

IBM Portable: Don't know the model number, but during my first two years of Yearbook Staff, I used this old 45-lb beast of a computer that had floppy drives and a small amber monitor built in.

IBM PS/2: I convinced my teacher that we needed this for Yearbook because it allowed us to run the newer yearbook publisher's software. It was better than the old portable.

386-DX: Just some clone that I picked up in college. I think it had 4MB RAM, a 40MB hard drive, and I put in the 3.5" floppy drive myself. It ran Geoworks just fine (even better than Windows 3.1!).

And then we come to the "modern" platforms with various versions of the Pentium architecture that I won't get into.

Removing Special Characters from .NET Strings

I came across a need today where I couldn't find an easy method on the internet. I had strings that I wanted to turn into simple filenames by removing a list of bad characters. I would have loved to have been able to use Trim(char[]) to do this, but that only works at the beginning and ending of strings.

I'm not sure how elegant and/or efficient my solution turns out to be, but here it is for anyone googling years down the road:



public override string ToString()
{
string junk = "~!@#$%^&*<()+=`',.?>/\\\"";
string[] ret = _displayText.Split(junk.ToCharArray());

return string.Concat(ret);
}



The Split(char[]) method creates an array using the provided characters as deliminators. This effectively strips out the "junk" characters, leaving you with broken bits of your original string. The Concat on the return line brings together the broken bits into one string.

Friday, June 03, 2005

Improve Browser History, Please!

The browser session history is linear, and works fairly well, but it really doesn't take advantage of how people surf the web. The way that it works today is that while you're surfing, you can hit the back button go return to a previous page, and once you use the back button, you have the option to use the forward button.

But, if you go back a couple of clicks in history, and then navigate to a new link, then you lose everything that was in your "forward history".

How do you improve this behavior? Instead of having the history be stack based (or whatever linear data structure is actually used), make it tree based. In this way, if you go back a couple of clicks and then follow a different hyperlink, a new branch is started in the session history. When you click the forward button from a page with multiple branches, you're prompted as to which branch to forward into.

Thursday, June 02, 2005

My Stats

It's interesting to see where my readers come from. Especially those arriving here from search engines. Just for fun, here's a summary of keyword themes that have brought readers to my blog:

30% Dog Crap in Lawn
25% GBPVR
10% Arcade monitors
10% Rejuvenator
8% 2004MN
6% ILWWCM
6% Other
5% Presidential Aircraft

Wednesday, June 01, 2005

Using VB Functions from C#

This seems like a no-brainer, but let's say that you're struggling trying to figure out how to do something in C# that you know how to do in VB. Like, maybe taking the right 5 characters of a string.

It's not that you can't do this in C#, because you surely can (it's trivial after working with C# strings for a while), but in a RAD or prototyping environment, you may find yourself wishing that the Right() function existed in C#, and may even be tempted to write one. [Some people would be wondering why you're not just using VB.NET in the first place, but that'$ a different argument].

The point here is that you can access all of the VB.NET functions that you're used to from C# by simply adding a reference to the Microsoft Visual Basic .NET Runtime assembly.

Consider the following code, which at least demonstrates how to get to the Mid and Format functions:



using vb=Microsoft.VisualBasic.Strings;

namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine(vb.Mid("FOOSBALL",3,2));
Console.WriteLine(vb.Format(12345, "00000000.00"));
Console.ReadLine();
}
}
}



I highly recommend that you explore to see what other familiar functions are available in the Microsoft.VisualBasic namespace (for example, the Microsoft.VisualBasic.FileSystem class could be real helpful!)