feedback
Jul 22 2008

Show Commenter's Latest Post: BlogEngine.NET Extension

by John Dyer

Background

Over the past few weeks, I've seen a few WordPress blogs that pull in the last post from a commenter's website. I also saw a post from Mads about how to find semantic links on a webpage.

So, I mashed his code together with some code from the BlogRoll control and created an extension that goes out and looks for RSS feeds at the commenter's website and then pulls in the latest post. [side note: I wish I could say, "a half hour later ... ", but it actually took me a while to get it to work...]

It all happens asynchronously, so if you comment on this post, it'll take a few seconds for it to show up. Then it will keep checking every so often for new posts.

Example

Last year, I posted a JavaScript color picker and the post now has over 100 comments. Here's what it looks like with the extension running:

 Comments with Recent Posts

Download & Installation

  • Download Commenter's Latest Post Extension
  • The last post is wrapped in the following class so you can style it:
    <span class="commenterslastpost"></span>
  • Sometimes the ResolveLinks extension interferes with this, so you might want to add the following code around the foreach loop:
    if (e.Body.IndexOf("href=\"" + match.Value + "\"") == -1) { ... }

Add a comment to this post to see it in action...

Jul 18 2008

iTunesU Site Utility in C# (.NET)

by John Dyer

In the process of moving Dallas Seminary's content to iTunesU, I created a very simple application to edit site details via the Web Service API. It currently has the following functions:

  • Add/Edit/Delete Sections
  • Add/Edit/Delete Courses
  • Add/Edit/Delete Groups
  • Upload/Edit/Delete Tracks

There are a lot of things it doesn't do, like let you edit themes or add images to courses, but it is really helping us get started. Here's a screenshot:image

You just enter your shared secret and domain name, press "Load Site Tree" and then right click on the various items to add/edit/delete.

And here's what it looks like in iTunes.image

Download & Installation

Links

  • iTunesU Support Site - Here's where I started
  • iTunesU Java Library - this is much more fully featured and documented than my code.
  • Woolamaloo - Rich Wolf's Mac tool which is much more fully featured than this tool. He also has a Windows app, but as far as I can tell it only lets you login.

My source code is very rough, but it someone needs it, I'm happy to provide it. Also, our iTunes U site is not yet public, but it will be in a few weeks.

Jul 17 2008

Programming History

by John Dyer

From Keyvan Nayyari and Janko to Mads Kristensen and now to me comes a challenge to tell how I got into programming...

How old were you when you started programming?

I think I was around 14 or 15.

How did you get started in programming?

My friend and I made text adventure games.

What was your first language?

It was some form of BASIC.

What was the first real program you wrote?

By "text adventure game", I really mean lame spaghetti-coded ASCII choose your own adventure "games." My friend had most of the funny ideas and I did most of the programming. He's now in a crazy band in Austin, TX called Natchet Taylor, and I work at a seminary!

What languages have you used since?

ASP, PHP, C#, ActionScript, SQL, X/HTML, JavaScript, CSS, and all the rest...

What was your first professional programming gig?

When I graduated from college, I took a job as a youth pastor. I needed extra cash, so I got a job as as ASP programmer for http://www.texags.com/. At that point, all I had really done was build a personal webpage in college (with animated flaming gifs!), so I just learned everything on the job. It was great fun. In those days, I'd write everything for IE, and then fix it for Netscape. Funny how things change.

If you knew then what you know now, would you have started programming?

Totally. There's always good work, and it really frees me up to be anywhere. I've made it through an entire masters degree since I could work whenever and wherever, and still be involved with friends and in ministry.

What is the one thing you would tell new developers?

I'll cheat and go with two:

  1. Always, always, always have a signed contract with everything spelled out in detail and a 25-50% payment before writing a single line of code.
  2. Release as much code as you can (to a blog or whatever). If your code is worth publishing, it means you probably did a good job, and would be something you won't hate to go back and modify later.

What’s the most fun you’ve ever had … programming?

I would have to say programming online education stuff with foreign language support. I have no idea what any of it says, but it's really fun to develop stuff that is used in a home in Dallas, a tent in the deserts of Iraq, in the Packers lockerroom, and in an underground church in China - and all of it not just to make a buck, but to make a difference in the world. That's rock-star coding.

Okay, I'm passing this on to Nathan Smith, Chris Merritt, and John Saddington. Have fun guys.

Jun 2 2008

Online Education Player Design Considerations

by John Dyer

Dallas Seminary has been doing video-based online education for about 5 years now. One of the initial goals was to replicate the classroom teaching experience as much as possible by including the video and the professor's illustrations (Powerpoint, Keynote, etc.). Beyond that, we also wanted to enhance the experience by adding things like a transcript and editing down the video to the most important segments.

Our initial player was created by Yahoo!'s Broadcast.com division and it used HTML frames and Windows media. This limited us to Internet Explorer, but there was no other option at the time. Then Flash 7 came out with video support and I custom built the player below. Since then, video on the web has come a long way, and the introduction of H.264 support means that we only need one format for playing on the web and on the desktop.

Here is the original design using 320x240 video and 480x360 slides:

  • image

Here are some changes we wanted to make:

  • Move from Flash 8 to 9 - use AS3 and enable fullscreen support
  • Use H.264 video - to simplify our workflow
  • Increase the video size, quality, and availability
  • Some users found the auto-scrolling transcript distracting and we need another option for them
  • Many classes don't have slides, so we need to de-emphasize those, yet also provide a good slide navigation system.
  • More narrow player - the current design is about 850px which makes it hard to have many more windows open at the same time.

Here are wireframe mockups of various design proposals

  • First player (2003) using Yahoo!'s Broadcast.com using HTML/Frames/WMV
    Obviously, WMV is limited to really working in IE, and we were stuck with Yahoo!'s platform.
    image
    old_online_ed_Yahoo_Video_Skin
  • Flash player with 320x240 video
    This player is wider since the slides are bigger, but the transcript is more narrow column which makes it easier to read.
    image 
    image

New Designs

  • Swapped video and slides sizes, controls at the bottom
    This swaps the video and slide sizes. It's nice, but the transcript is far away and the slides are hard to read. The player is also still very wide.
    image
  • Larger video size, small slides on the side
    To make the video even bigger, the transcript is now a single line like closed captioning on TV. Rather than give the slides their own dedicated space, the slides have a tray on the right and the full size slide appears over the video for a few seconds. The width is slightly smaller, but not much.
    image
     
  • Coverflow Style Player
    To make the player more narrow (for multi-tasking), we move the slides to the bottom and use the Apple CoverFlow to show a lot of them at once. This makes the player more narrow which is good, but also taller. To shorten it, we've moved all the controls on top of the video that appears/diasppears on mouse hover.

     image

    Here is a screenshot of a fairly common desktop size (1680x1050) with MS Word and a preview version of this player open. (note: I've made sure the controls are visible for the screenshot, but they are hidden normally) 
    image
    image

This seems effective, but there is a possible drawback in that the Coverflow might be somewhat distracting to some students (it can be turned off). Also, some may prefer the older style transcript with more than one line visible at once.

Links to preview the players:

Another future goal is to build the player as an AIR application so that videos can be downloaded for offline use.

May 15 2008

ISBN Functions in C# (ISBN-10 to ISBN-13 Conversion)

by John Dyer

While working with some book data, I needed to merge the old ISBN-10 and ISBN-13 data. Unfortunately, I couldn't find any C# code to do the conversion. Search for "ISBN C#" in Google only return book stores with C# books.

So here is a little class that will convert and validate ISBNs. Here's how the code would look:

string isbn10 = "0830818030"; 
string isbn13 = ISBN.Convert10to13(isbn10); // returns "9780830818037"

string isbn = "083081803X"; // this one has a bad checksum (last digit) 
string correctIsbn = ""; 
if (!ISBN.IsValid(isbn, out correctIsbn)) { 
	isbn = corretnIsbn; // returns "0830818030"
}

An ISBN object can also be instantiated and used:

IBSN myBook = new ISBN("0-83081-803-0"); 
string isbn13 = myBook.ISBN13; // returns "9780830818037"
string isbn10 = myBook.ISBN10; // returns "0830818030" 

Here is the class:

public class ISBN
    {

        public ISBN(string isbn)
        {
            SetIsbn(isbn);
        }

        private string _isbn10 = "";
        private string _isbn13 = "";

        public string ISBN10
        {
            get
            {
                return _isbn10;
            }
            set
            {                
                string corrected = "";
               
                if (!IsValid(value, out corrected) && corrected == "")
                    throw new Exception("invalid ISBN");

                SetIsbn(corrected);
            }
        }

        public string ISBN13
        {
            get
            {
                return _isbn13;
            }
            set
            {
                string corrected = "";

                if (!IsValid(value, out corrected) && corrected == "")
                    throw new Exception("invalid ISBN");

                SetIsbn(corrected);
            }
        }

        private void SetIsbn(string isbn)
        {
            isbn = CleanIsbn(isbn);

            if (isbn.Length == 10)
            {
                _isbn10 = isbn;
                _isbn13 = Convert10to13(isbn);
            }
            else if (isbn.Length == 13)
            {
                _isbn13 = isbn;
                _isbn10 = Convert13to10(isbn);
            }
        }

        private static string CleanIsbn(string isbn)
        {
            return isbn.Replace("-", "").Replace(" ", "");
        }


        public static string Convert10to13(string isbn)
        {
            return Convert10to13(isbn, true);
        }
        public static string Convert10to13(string isbn, bool throwError) {
            
            // remove - and space
            string isbn10 = CleanIsbn(isbn);

            if (isbn10.Length != 10 && throwError)
                throw new Exception("ISBN must be 10 characters long");

            // 1) Drop the check digit (the last digit)
            isbn10 = isbn10.Substring(0, 9);

            // 2) Add the prefix '978' 
            string isbn13 = "978" + isbn10;

            // 3) Recalculate check digit 
            isbn13 = isbn13 + Isbn13Checksum(isbn13);

            return isbn13;
        }

        public static string Convert13to10(string isbn)
        {
            return Convert13to10(isbn, true);
        }

        public static string Convert13to10(string isbn, bool throwError)
        {

            // remove - and space
            string isbn13 = CleanIsbn(isbn);

            if (isbn13.Length != 13 && throwError)
                throw new Exception("ISBN must be 13 characters long");

            // 1) Drop the check digit (the last digit) and prefix '978'
            string isbn10 = isbn13.Substring(3, 9);
     
            // 2) Recalculate your check digit using the modules 10 check digit routine.
            isbn10 = isbn10 + Isbn10Checksum(isbn10);

            return isbn10;
        }

        public static bool IsValid(string isbn)
        {
            string correctIsbn = "";
            return IsValid(isbn, out correctIsbn);
        }

        public static bool IsValid(string isbn, out string correctISBN)
        {
            // remove - and space
            isbn = CleanIsbn(isbn);

            if (isbn.Length == 10) {
                return ValidateIsbn10(isbn, out correctISBN);
            }
            else if (isbn.Length == 13)
            {
                return ValidateIsbn13(isbn, out correctISBN);
            }
            else
            {
                correctISBN = "";
                return false;
            }

        }

        private static string Isbn10Checksum(string isbn)
        {
            int sum = 0;
            for (int i = 0; i < 9; i++)
                 sum += (10-i) * Int32.Parse(isbn[i].ToString());
   
            float div = sum / 11;
            float rem = sum % 11;

            if (rem == 0)
                return "0";
            else if (rem == 1)
                return "X";
            else
                return (11 - rem).ToString();
        }

        private static string Isbn13Checksum(string isbn)
        {
            float sum = 0;
            for (int i = 0; i < 12; i++)
                sum += ((i % 2 == 0) ? 1 : 3) * Int32.Parse(isbn[i].ToString());

            float div = sum / 10;
            float rem = sum % 10;

            if (rem == 0)
                return "0";
            else
                return (10 - rem).ToString();
        }


        private static bool ValidateIsbn10(string isbn, out string correctISBN)
        {
            correctISBN = isbn.Substring(0, 9) + Isbn10Checksum(isbn);

            return (correctISBN == isbn);
        }

        private static bool ValidateIsbn13(string isbn, out string correctISBN)
        {
            correctISBN = isbn.Substring(0, 12) + Isbn13Checksum(isbn);

            return (correctISBN == isbn);
        }
}

I initially wanted to also make a method that would add back in the correct dashes, but I found out that the make up is based on country and publisher codes assigned by the International ISBN Agency which regularly updates the list of codes making it pretty much impossible to permanantly functionalize.

May 12 2008

The Best Way to Demo Websites for Clients

by John Dyer

For the last few years, my web team has used a projector to collaborate on web projects. We use it for going through our weekly work items, demoing designs, doing training, and so on.

Unfortunately, it was an old projector with a weak bulb so we always had to turn out the lights to use it. Even then it was hard to see because the contrast and color depth were poor, and the resolution was only 1024x768. So last year I budgeted to get a new projector to solve these problems.

Instead of getting a new projector, I decided to get a LCD HDTV and use it as a monitor. I found a killer deal at Sam's Club on a 65" Olevia. The screen isn't quote as nice as something like a Sony, but for what we are doing, it is absolutely amazing. The 1920x1080 resolution and super bright LCD screen is perfect for looking at web designs. In this pic, We have our task app on the right and a full size web page on the left. Even though the text is tiny it's readable from about 8' away:

IMG_3278 

IMG_3279

I have an old PC running the display, and I'm using a few little utilities to make enhance presentations:

  • PowerStrip - Some PCs and Macs can't natively display 1920x1080 resolution. This little Windows app helps out and can usually enable even really old machines to do HD resolutions.
  • ZoomIt - this is a little app by the former SysInternals.com guys. It lets you zoom into a screen with the mouse scroll wheel and draw on the screen. This features are invaluable for mockups.
  • Zune Theme Modified - I also used a modified Zune theme, because I like how the dark colors make the UI fade into the background and focus attention on the design.

On the fun side, we can occasionally use it for things other than web design. Since we're in a basement, we don't have a good way of getting an antenna to pipe in some HD goodness, but we can watch trailers in full 1080p goodness!

IMG_3281

May 6 2008

Web Marketing using Facebook Ads and Video for Dallas Seminary

by John Dyer

Note: This blog is usually fairly technical, dealing with ASP.NET, Flash, and JavaScript code samples, but this is a brief deviation into the broader world of the web as a technology platform for communicating an institution's message.

For Dallas Theological Seminary, we've been experimenting with "branding" and reaching different audiences by producing some new videos and experimenting with Facebook's relatively new targeted advertising.

Marketing for Seminaries?

Advertising and marketing for churches and seminaries can be a tricky thing, because it seems rather sacrilegious to "market" something spiritual. We've all seen late night and afternoon televangelists that make us cringe. But DTS isn't offering a "product" that someone buys; rather its mission is to train pastors, professors, and missionaries for a lifetime of service. If you call an admissions counselor and ask why you should go to DTS, you won't get a sales pitch. The admissions counselor will tell you that you should go to the school to which God is calling you. The admissions person will then mention some of DTS's strengths, but stay away from comparisons with other schools or "selling DTS."

Still, it is important for DTS to inform prospective students on what kind of school it is and what it's strengths are. Basic marketing ideas can help convey this, and naturally the web is a great place to start.

Context for the Advertisements

Any time you create an ad for a "company," it is important to know the background of the business and the historical context in which the ad is situated. This history of seminaries and churches in America is key to understanding what ads will communicate to the seminary audience. image 

In the early 1900s, was a debate in the Christian church between "fundamentalists" (those who believe certain truths are the most important thing about Christianity) and "liberals" (those who believe certain actions are the most important thing about Christianity). In this debate, it seemed that the "liberals" forgot that Jesus asked Christians to believe something (that he is the savior and the Son of God), while the the fundamentalists often forgot that Jesus asked Christians to do something (love others).

DTS was started in the 1920s during the fundamentalist movement. Unfortunately, many of the seminaries which started during this time period have a reputation of caring about teaching the Bible, but neglecting to meet real world needs. By the 60s and 70s, some Christians wanted to balance the emphases of both the liberals (loving) and fundamentalists (truth), and there they were called "evangelicals." Today, this term has become politically decisive and has less positive connotations in many places, so the word "evangelical" communicates something different than it used it.

Today's students who are considering seminary are more concerned than ever about balancing these two things and so DTS needs new ways to communicate that it wants to care about Christian beliefs and Christian practices without making one too dominate. These students also don't read traditional Christian publications, so DTS needs to shift from print publications to Internet and from top down communication to allowing prospects to connect to real students.

A New Tagline

The older taglines for DTS have been things that primarily emphasize Biblical teaching such as "Standing Strong for the Truth" or "Training You Can Trust. Leaders You Can Follow."

We wanted something shorter and somewhat pithy that emphasized both aspects of truth and love. Here's what we came up with.

  • Teach Truth. Love Well.

Not too revolutionary, but hopefully it's clear and it communicates. Here's how Google sees it :)

image

Facebook Page and Ads Summary

DTS has traditionally run ads on large Christian website like ChristianityToday.com and OnePlace.com. But to reach younger students, we moved over to Facebook.

Also, in the past, a traditional DTS ad might have emphasized something like "Want to be a Pastor?", but many of today's seminarians are going into non-traditional forms of ministry. DTS grads still have a very strong emphasis on teaching the Bible, but more students are doing this outside the traditional church pastor role. The first few ads we ran emphasize these other forms of ministry. We ran each one for around a week and paid per click with click-through rates of around 0.10%.

image image

Which one do you like more?

The second ad turned out to be more successful (higher click-through rates). This is probably because the image is more appealing and "Dallas Seminary" doesn't show up until later in the text of the ad.

In addition to advertisements, we also setup a Facebook Page for DTS. Rather than aggressively market to students through physical mail or email blasts, this allows interested students to check out DTS and ask questions of current students and alumni before talking to an admissions counselor. On the GoingToSeminary blog, there is a great post about connecting to a current student to get real answers. Below is an example of a prospect asking a question that a current student answered on Facebook. That person got a real answer from a real student without ever needing to visit the main seminary website.

image

Connecting with Video

DTS's excellent AV team has also produced several videos that communicate the "Teach truth. Love Well." message. These are sent to alumni and supporters via email every few months.

Ben Stuart
Ben leads a college ministry called BreakAway which is attended by about 5,000 Texas A&M (my alma mater) students. His story is classic DTS and emphasizes "Teach Truth".

Christ in North Africa
Where Ben highlights "Teach Truth," Christy highlights "Love Well." She is an English teacher North Africa, but never "teaches" Christianity verbally; she does it by loving the girls in her classes.

William "Duce" Branch
"Duce" Branch is a pastor who ministers to the hip hop generation through his music.This is a guy who took 120 hours of course work and still managed to keep his love for his culture. He really embraces both elements of "Teach Truth. Love Well."

This last video also has a great metaphor for communicating to different audiences where the president of the school is shown on an upper-middle-class HDTV while Duce is shown on various older TVs. They both are working for the same goal with the same message, but the context and transmission system changes to be audience appropriate. Good stuff.

I hope this is a helpful summary of how DTS works and how the newer media forms can be used to communicate to changing audiences.

Apr 23 2008

Dynamic Text Replacement with JavaScript and C# ASP.NET

by John Dyer

What it Does

You write some basic markup and include a JavaScript file and some code which replaces normal text with a .NET generated image:

<style type="text/css">
h2 { color: #9E100F; size: 22px; }
</style>

<!-- This says "Frequently asked questions in zh-TW -->
<!-- If you just see boxes, you need to install Asian fonts on your machine --> <h2>關於網上教育常見的問題</h2> <script type="text/javascript" src="fontreplacer.js"></script> <script type="text/javascript"> FontReplacer.replace('h2','*', 'MyGreatFont'); </script>

This will take all h2 tags with any class (*) and replace them with and image rendered using 'MyGreatFont'. This font needs to be installed the c:\windows\fonts\ folder of your server or in the same folder as the .NET script which generates it. Initially the page will look like this (using the standard font for Chinese script on a PC which is 'MS Mincho'):

image

But after the replacement happens, it looks like this:

image

With another less formal font, it could look like this:

image

Of course, you can use any font installed on the server and it is not limited to Chinese text. Here is an example replacing the default Times New Roman text with Century Gothic:

image

image

This may be useful in other scenarios for viewing Unicode text on a machine without Unicode fonts installed (Greek, Hebrew, Arabic, etc.).

It can also produce anti-aliased PNGs for use on top of an image:

image image

Why I did it

Recently, I needed to have the titles for a series of webpages be rendered in a specific Chinese font (see http://www.dts.edu/chinese and click on "zh-TW" in the upper right) because the default doesn't look very official (according to my Chinese friends). I wanted to use sIFR which replaces the HTML text node with a Flash file that has the font embedded. The problem is that Chinese fonts are 3-8MB which means the user has to download a gigantic SWF. Also, there can be copyright problems with using sIFR.

So I turned to .NET to generate images using the font. The basic technique was first published back in a 2004 A List Apart article titled Dynamic Text Replacement. ALA used JavaScript and PHP and, since then, there have been many permutations of the basic idea, some using pure CSS instead of JavaScript. I haven't seen a good one for .NET, so I had to write my own. I don't like using CSS for some of the reasons mentioned here, so I went with JavaScript for the replacement. This way users without images or JavaScript can still see the text. Users with images and JavaScript get a slightly nicer view.

How it Works

The JavaScript method looks at the HTML element(s) you send it and pulls out the text and font color. It then sends a request to ASP.NET to return an image which renders the text using your assigned font and colors. There are three ways to call it:

// elements by tag and class
FontReplacer.replace(tag, class, fontName);
// elements by tag and class inside a given elmenent
FontReplacer.replaceIn(element, tag, class, fontName);
// replace array of elements
FontReplacer.replaceElements(elementArray, fontName);

This calls up a .NET script which writes the text to an image using the specified font. The C# code can generate a JPG or transparent PNG which happily sits on top of any background and looks very nice. (There is a flag in the JavaScript to to allow the PNG transparency). There are some tricks in .NET for generating a PNG with alpha channels and for saving a JPEG with a specified quality, so here's the full code for that part.

if (backColor == "transparent")
{
	MemoryStream io = new MemoryStream();
	bitmap.Save(io, ImageFormat.Png);

	context.Response.ContentType = "image/png";
	context.Response.BinaryWrite(io.GetBuffer());
}
else
{
	context.Response.ContentType = "image/jpg";
	SaveAsJpeg(bitmap, context.Response.OutputStream, (long)100);
}
void SaveAsJpeg(Image inputImage, Stream stream, long quality)
{
	 // generate JPEG stuff
	 ImageCodecInfo codecEncoder = GetEncoder("image/jpeg");
	 EncoderParameters encoderParams = new EncoderParameters(1);
	 EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
	 encoderParams.Param[0] = qualityParam;
	 inputImage.Save(stream, codecEncoder, encoderParams);
}
ImageCodecInfo GetEncoder(string mimeType)
{
	ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
	foreach (ImageCodecInfo codec in codecs)
	{
		if (codec.MimeType == mimeType)
		{
			return codec;
		}
	}
	return null;

}

There are also flags in the JavaScript to force the returned image to be the same height and width as the element you are replacing. By default, the height is forced so that the page doesn't jerk at all, but you should be aware that browsers often report the font size inaccurately. Also, .NET's measurement of the size a given string will take up can include some padding depending on the font, so you may have to play with it for your scenario.

Lastly, there are some important things to know about using fonts on the server.

  1. When you install a font on c:\windows\fonts\, IIS doesn't immediately know it's there. You'll need to run the "resetiis" command for IIS to pick up the new fonts.
  2. If you're in a hosted environment and can't install fonts, you're still in luck. There is some code to load a *.TTF file in the fontwriter.ashx script. In this case, you'll need to specify the font file name ('gothic.ttf') rather than the installed font name ('Century Gothic').
  3. You might want to adjust the TextRenderingHint hint property at the top if you don't want anti-aliased rendering.

Download & Example

Apr 16 2008

var baby = john.Meiosis() + amber.Meiosis();

by John Dyer

Just a little genetics (my college major) humor written in C# 3.0 syntax (with overloaded operators and an implicitely typed local var) to announce that we're going to be parents later this fall! Check out the sweet spin moves below. I'm calling all-star running back...

offspring01_sonogram
This video requires Adobe Flash player

Behold, children are a gift of the LORD; The fruit of the womb is a reward.” Psalm 127:3

 

Apr 14 2008

Dallas Seminary Mobile Site

by John Dyer

Since Microsoft and Apple finally decided to allow/license versions of Flash Lite 3.0 for their mobile devices (Windows Mobile and iPhone), I created an initial build of a mobile site for Dallas Seminary which will eventually use Flash Lite 3.0 for all the audio and video content.

The goal was to make it look like an iPhone application using the list format, but have it work properly on other mobile devices by not specifically targeting the iPhone's screen size such as Windows Mobile and Blackberry. It's a bit more cramped on the smaller WM screen, but it works well.

Here are a few screen shots:

iPhone Windows Mobile
image dts_wm_home
image dts_wm_media

 

There is one gotcha on the iPhone that doesn't show up using Safari. The iPhone may try to startup zoomed out like it would need for a normal website. If your <div> tags are set to expand, the iPhone will stretch everything out and then zoom out.

 image

To fix this add the following:

<meta name="viewport" content="user-scalable=no,width=320,scale=1.0" />
Apr 10 2008

Totally Unobtrusive (and totally awesome) Upside Down Text

by John Dyer

There is a huge need for upside down text on the web. With everyone "going mobile," developers cannot simply rely on users having their screens oriented the same way all the time. I went through all of the possible options for creating upside down text and finally came up with a totally unobtrusive, Unicode enabled, completely web-changing piece of code (which is mostly from someone else and using this and this).

Options for Upside Down Text

  1. Images - The most obvious option for upside down text is to open up Photoshop, enter some text, and use Rotate Canvas.
    Pros: easy to do.
    Cons: must be done for every piece of text. Not every OS/browser in the world can display images. This is just unacceptable.

  2. sIFR - I know it's a little 2005 of me to say it, but a great use of Flash is to replace text and rotate it around.
    Pros: works for any HTML text element.
    Cons: requires Flash which has even less support than images. Also, requires extra coding.

  3. Canvas - one day it might be possible to do more with text drawing on a canvas tag, but right now its not
    Pros: none, for now.
    Cons: doesn't exist.

  4. JavaScript - Everyone knows JavaScript can do anything. See my experiments in 3D and color and this guy's port of Mario. Using this great script its possible to simulate upside down characters using Unicode equivalents.
    Pros: is awesome.
    Cons: nothing at all.

Usage &Implementation

Just give your HTML element a class called "upsidedowntext" and add the script in the header and you have pure greatness:

<script type="text/javascript" src="upsidedown.js"></script>

<div class="upsidedowntext">I can be read in any orientation</div>
<div>I can be read in any orientation</div> <div class="upsidedowntext">This is Tom Cruise taking your picture</div> <div>This is a boring Russian Mig</div>

Result:

uoıʇɐʇuǝıɹo ʎuɐ uı pɐǝɹ ǝq uɐɔ ı
I can be read in any orientation

ǝɹnʇɔıd ɹnoʎ ƃuıʞɐʇ ǝsınɹɔ ɯoʇ sı sıɥʇ
This is a boring Russian Mig

Demo and Download


Note: this post was intended to be an light-hearted (late) April's fools poke at all the random stuff developers are doing with JavaScript, sometimes in the name of a standard or idea that really isn't really needed. Also, I think upside down text is funny.

Mar 16 2008

QTVR like Panoramas of Chichen Itza made in Flash with Papervision3D

by John Dyer

Last week, I visited Cancun with my in-laws and had a chance to see the ruins at Chichen Itza. I took a series of photos and made them into a panorama using Papervision3D (as done here by BlitzAgency for NBC's The Office and here by a company selling a product called Flash Panoramas). I made a little script that can handle both spherical and cubic images to see how both would look. Here's some previews of the two versions (The lines are there to show how the panorama is being constructed):

Spherical  
CropperCapture[45]
Cubic
CropperCapture[42]

A cubsic panorama is composed of six images (top, bottom, left, right, front, back) while a spherical panorama is made using a single image which is stretched at the top and bottom (like a map of the world where Greenland and Antarctica are distorted). In general, it looks like the spherical version can generate the same level of detail with fewer polygons and thus more speed, but the cubic images can be a little smaller and are more easily edited.

Each of these is composed from approximately 45-50 images. I took around 15 in a circle at the horizon, 15 looking up about 45 degrees, and 15 looking down 45 degrees. Unfortunately, I didn't take enough pictures to complete the sky or the ground below, so you'll see some black spots if you "look" up or down. I used Hugin to stitch the images together, and it did a pretty good job considering I didn't have a tripod or wide angle lens to accurately take the pictures. (link: the best tutorial I have seen on image stitching)

3D Panoramas

Original Images

The view page also has a list of commands (f=fullscreen) and links to the original files.

Update: I changed the navigation to be more like QTVR where you have to click to move, and there is an arrow cursor. Also, smoothing and precision are automatically applied when you stop moving.

Mar 12 2008

Data Portability Pack now in BlogEngine.NET Core

by John Dyer

The Data Portability Pack that I posted about a few weeks ago has now made it into the core of BlogEngine.NET for version 1.4. Mads Kristensen added the SIOC and APML handlers, and Roman Clarkson is working on a FOAF implementation that includes adding some Profile data (first and last name, etc.) to users of a BE.NET instance.

FOAF (friend of a friend) currently doesn't have any way of (1) automatting "Add as Friend" style interactions (like Facebook or Myspace) or (2) verifying connections between people. Roman and I would like to find a secure way of implementing this functionality which would in effect create a decentralized social network. There are however, several problems to work through regarding security (public vs. private friends lists), identification (unique IDs: email or OpenID?), verification (preventing friend spam), and so on. These issues have been talked about for some time in the FOAF community, but so far there hasn't been an implementation. Here are some older (2003) and newer (2007) discussions on the subject to get caught up:

Feb 21 2008

Implementing Map Mashups with Mapstraction

by John Dyer

image A few years ago, I made my first map mashup with Google Maps for Dallas Theological Seminary. It allows visitors to search for churches around the world where DTS alumni are serving. Recently, we decided to update the mashup with several features in mind:

  1. Larger map - 2 years ago we were using a 800px wide layout and now we can use a 1024px layout
  2. Use updated API - Google has changed APIs since then
  3. Implement other maps - Yahoo and Microsoft each have good points
  4. Use custom icons - we are not just showing churches now, but also schools and counselors

To handle all of this, especially the implementation of other multiple map engines, I chose to use mapstraction, a JavaScript layer which allows developers to program against a common API for all mapping engines. It turns these two proprietary mapping code blocks:

// Google maps specific code
var gmap = new GMap2(document.getElementById("map"));
map.addControl(new GMapTypeControl());
gmap.setCenter(new GLatLng(37.4419, -122.1419), 13);
var gmarker = new GMarker( new GLatLng(37.443, -122.166) );
gmap.addOverlay(gmarker);
// Microsoft Live maps specific code
mmap = new VEMap('map');
mmap.SetDashboardSize(VEDashboardSize.Normal);
mmap.LoadMap();
mmap.SetCenterAndZoom(new VELatLong(37.4419, -122.1419), 10);
var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(37.443, -122.166));
map.AddShape(shape);

into this single common set of code:

// universal map API, just change 'google' to 'yahoo', 'microsoft', etc.
var mapstraction = new Mapstraction('map','google');
mapstraction.addControls({ pan: true, zoom: 'large', overview: false, scale: true, map_type: true });
mapstraction.setCenterAndZoom(new LatLonPoint(37.4419, -122.1419), 12);
var marker = new Marker(new LatLonPoint(37.443, -122.166));
mapstraction.addMarker(marker);

In addition to Microsoft, Yahoo, and Google maps, you also get free access to a 3D map called Freeearth which is an amazing implementation of a 3D globe map (like Google Earth) using Papervision3D.

Examples

Here are examples using all four mapping engines. The only unique code is the shadow on the icons under Google maps. Also, prototype (which is used throughout the site) is handling the AJAX calls.

image image

image image

Try it out

Links

Feb 14 2008

Data Portability Pack for BlogEngine.NET

by John Dyer

What it Does

This is an initial release of 3 extensions which will add the follow protocols to your BlogEngine.NET blog:

  • SIOC - Somewhat like RSS, but utilizes RDF to describe connections to  other sites and between users and posts (example).
  • APML - Creates an "attention profile" of your interests based on tags and categories. Each is given a value based on its frequency (example).
  • FOAF - A list of your friends, their websites, and a hashed version of their email for a unique key (example).

You can see examples of each of these by clicking on the links on the upper right of this blog. To learn more about data portability, see this post. The following links show this data in a browsable format:

How it Works

imageEach of these has a Handler, a Generator, and an Extension file. The extension files automatically add <meta> discovery files to your <head> tag.

Note: Currently, the FOAF information is stored in two different Extension files due to a limitation in BE.NET 1.3 (it cannot store both scalar and table data). One extension is for your personal information and the other is for your friends' data. BE 1.4 will allow these to be merged into one file.

Warning: BE.NET currently deletes extension data when you change *.cs files, so please backup your extension file when adding or changing extensions.

Installation and Usage

  1. Download Data Portability Pack for BlogEngine.NET
  2. Copy the *.cs files into your /App_Code/Extensions folder (you can also create a sub-directory within that folder)
  3. Add the following to your web.config file
    	<add verb="*" path="sioc.axd" type="BlogEngine.DataPortability.SiocHandler, App_Code" validate="false"/>
    	<add verb="*" path="foaf.axd" type="BlogEngine.DataPortability.FoafHandler, App_Code" validate="false"/>
    	<add verb="*" path="apml.axd" type="BlogEngine.DataPortability.ApmlHandler, App_Code" validate="false"/>	
    	
  4. Go to your Admin->Extensions page and you should see 4 extensions prefixed with "DP_". The FoafFriends and MyProfile extensions need data entered, the other ones you can just leave as their defaults.
    image
  5. Optionally, you can add links to each of these files (as I have on the upper right)

Future Work

  • Merge FOAF extensions for BE 1.4
  • Possibly store FOAF data in a separate file rather than as Extension data
  • Add additional settings to APML such as parsing blog roll
  • If you also add OpenID support to your blog, then you will have everything that is currently on the data portability standards list.

kick it on DotNetKicks.com