Jul 24 2010

New Company - Kookaburra Technology

Category: Kurtis @ 09:03

In April 2010, my wife and I formed a corporation named Kookaburra Technology, Inc. Finally, we have our website up and running. Kookaburra is a web design company with a very important focus on customer service. I think that customer service is, bar none, the best thing a business can do to make money. If your customers are happy, they will tell their friends. Good customer service is good advertising - not to mention it's the right thing to do!

Tags: , , ,

Apr 9 2010

json-sharp - Simple .NET Library for JSON Serialization and Deserialization

Category: ProjectsKurtis @ 07:49

I created a very simple and really fast JSON parser for .NET. You can download it here.

Introduction

json-sharp contains 4 methods:

string JSON.Serialize(object o);
string object.ToJSON();
T JSON.Deserialize<T>(string json);
object JSON.Deserialize(string json);

It is of note that only public properties are serialized and deserialized.

Setup

Minimal setup is required to get json-sharp running.

  1. Download either the DLL or the source file.
  2. Include either the DLL or the source file in your project.
  3. Include a using reference to System.Web in the .cs file you intend to use json-sharp if there isn't one already.
    using System.Web;

Examples

Serializing

There are two ways in which you can serialize an object. First of all, you can use the straight-forward Serialize method.

string myJsonString = JSON.Serialize(MyRandomObject);

or you can use the even easier object.ToJSON method.

string myJsonString = MyRandomObject.ToJSON();

Deserializing

There are also two ways in which you can deserialize a JSON string. First of all, you can use the more generic Deserialize method without specifying a type.

ArrayList numberListList = JSON.Deserialize("[[20.4,-30,-42.6,-0.5e10], [-0.5e-3,0.5E2,0.323E-2,50,60]]");

or you can specify a type and get a useful object.

string x = "[[10,20.4,-30,-42.6,-0.5e10], [-0.5e-10,0.5E10,0.323E-10,50,60]]";
double[][] y = JSON.Deserialize(x);

Comparison to other Libraries

I ran some tests against two other popular libraries to test speed and ease of use. The other libraries I tested json-sharp against are Newtonsoft's Json.NET and Microsoft's built in JSON deserializer. The test is a fairly simple, but large (~253 KB), JSON file. The JSON is just a large array of a simple object. This object contains 10 Properties (4 ints, 3 decimals, 2 strings, 1 datetime). I store the json in a string variable, then call each library's deserialization method 100 times and report the overall time it took.

Microsoft

  • Lines of Code: 18
  • Execution time: 3.875 seconds
  • Using statements: 2
  • Libraries imported: 0
  • Size of libraries: 0

Newtonsoft

  • Lines of code: 1
  • Execution time (typecasted): 12.234 seconds
  • Execution time (generic): 8.609 seconds
  • Using statements: 1
  • Libraries imported: 1
  • Size of libraries: 192 KB

json-sharp

  • Lines of code: 1
  • Execution time (typecasted): 5.859 seconds
  • Execution time (generic): 1.688 seconds
  • Using statements: 1
  • Libraries imported 1
  • Size of libraries: 13 KB

Tags:

Dec 22 2009

Guid Replication Odds - Part 2

Category: Kurtis @ 18:34
Say you have an API for which 10 million developers all have a unique Guid they use to authenticate. Some random hacker decides to try to steal one of these API keys by throwing random guids at the API. If they tried 1 trillion different guids every millisecond for 1 year, they would have a 1 in a trillion chance of hitting one of those 10 million API key's you've given out.

Tags: , , ,

Nov 5 2009

How to convert an iTunes audio book (.m4b) into a usable, DRM-Free, MP3 file

Category: Kurtis @ 04:20

I hate iTunes with a passion, however, it is the only online store from which you can buy the Harry Potter audio books in a digital format. The best way to listen to an audio book (for me) is via an MP3 CD (I can use my remote control to pause, etc, and I don't have to swap discs every hour or so).  You can't burn an audio book to an MP3 CD from iTunes, and I became very frustrated after trying several methods of conversion that were touted online (and didn't work). So, I decided to come up with my own method of breaking Apple's ridiculous DRM.

Be warned that this is a 1x conversion (it takes as long to convert it as it does to listen to it), but it can be applied to any audio format that can be played on your computer, including audio from videos (though i'm not immediately sure why you'd want to do that). Also, I use this method to free up the digital audio for my own personal use. I do not share or distribute it in any way. If your intents are nefarious, please do not read further. I will not be responsible for anything done using the following method.

Requirements:

  1. A Windows PC
  2. A Sound Card 
  3. Some audio source you want to convert to MP3 (such as an iTunes audio book)

 

Here are the steps:

  1. Download and install Audacity
  2. Download and install the LAME MP3 Encoder for Audacity.
  3. Enable Stereo Mix on the Audio Input of your sound card.
  4. Open Audacity and click the record button.
  5. Play the audio file in iTunes (or wherever).
  6. When the audio file (or series of audio files) has finished playing, click the Stop button in Audacity.
  7. Remove the silence at the beginning and ending of the audio track by clicking on the track right before it goes from a flat line to bumpy and then dragging all the way to the beginning of the track (if you are trimming the start -- drag to the end if you are trimming the end). Then press the delete key.
  8. In Audacity, choose Analyze -> Regular Interval Labels
  9. Change "Label Interval [seconds]:" to "180" for 3 minute tracks.
  10. Change "Label text:" to "Track"
  11. "Label Placement method" should be "Label interval"
  12. "Prepend numbers to label text?" should be "No"
  13. "Include final label?" should be "Yes"
  14. "Final audio segment equal with others?" should be "No"
  15. Click OK.
  16. Choose File -> Export Multiple
  17. "Export format" should be "MP3 Files".
  18. Choose and Export Location
  19. "Split files based on" should be "Labels"
  20. "Name Files" should be "Numbering consecutively" with a "File name prefix" of "Track"
  21. Click Export
  22. Click OK for each "Edit metadata" dialog that comes up, or fill in the information for each.
  23. Done!

 

Tags: , , , , ,

May 1 2009

Dictation audio transcription -- Few options that need massive improvement

Category: Kurtis @ 15:30

A yet to be named project that is related to this post has recently led me on a search for a good way to transcribe dictation audio (convert free-form speech into text). The only real usable package out there is Microsoft Speech API. It does a great job of transcribing speech from a limited set of options. However, when it comes to free-form speech, it is downright terrible. This is odd, I thought, because I've seen some services that do an excellent job of transcribing voicemail messages. TrapCall is one of these services. So, a couple of days ago, I emailed TrapCall and asked them how they did it. Their response: "We use human transcribers not automation." Wow. I guess since the quality of automated transcription is so terrible, it is more economical to do the transcription manually.

That leaves me two options for my service. Option 1 is manual transcription. Option 2 is to improve the existing speech to text engine.

Now, keep in mind that free-form speech transcription is not essential for my service at this time. But, it would blow it out of the water. Also, if I were to develop an accurate free-form speech transcription engine, that is valueable enough that I could sell it all on its own and make a pretty penny. So, I started thinking about how I could improve upon this existing technology.

  1.  Performance Matters. Microsoft has a default 'DictationGrammar' that you are supposed to use for free-form speech. That's the one that sucks. So, I had an idea to just create my own grammar consisting of a simple list of 80,000 words and see how well that did. When I went to load the grammar file, I sat there for 15 minutes and it was still loading. So I killed it. Then I tried 20,000 common words. That took 2 or 3 minutes to load and like 30 seconds to process each word, and it would only process one word at a time; and the quality sucks. Again failure. What this tells me is that even though Microsoft's DictationGrammar produces terrible results, at least it is fast. It also rules out a massive, complicated grammar based on common sentence structure. It would just be too slow. We need to be processing this audio in at least 1/2x speed (it takes 2 seconds to process 1 second of audio).
  2. Consider certainty. Did she say "I want to play with your bells" (you know, the ones you play with your Christmas orchestra) or did she say something else? That is a very important word, and it's better to ask and verify than to assume she wants to go shoot some hoops. The problem is, computers lack linguistic skills and there is no way for a computer to know if a word is important. Better safe than sorry. All words that are below a certain threshold of uncertainty are suspect.
  3. Making a list, checking it twice. My engine would take a two prong approach. First, results are stored in a 2 dimensional array. The sentence proceeds across the top row, with each column being closely sounding alternatives to the engine's picks. For example, the first column might consist of A, Lay, Pay; the second column: fog, dog, cog; and third: guns, nuns, runs. Secondly, the engine looks at word triplets that word compiled from web content. These are 3 word groups that appear together in text. They are rated by how common they are. Using this approach, one can clearly see that the transcription should be "A dog runs" as those words would appear most commonly together. We would run this test on each individual word. Which scores higher? A fog/a dog/a cog, lay fog/lay dog/lay cog, or pay fog/pay dog/pay cog. "A" is clearly the correct choice. The same goes for dog, but since it's in the middle, we can use the word before and the word after. We have chose "A" so we don't have to compare the other options here. So we have (a fog guns/a fog nuns/a fog runs), (a dog guns/a dog nuns/a dog runs), and (a cog guns/a cog nuns/a cog runs). "Dog" would likely stand out from the rest.

Tags: , , ,

Apr 25 2009

Combining Highrise and Twilio -- Taking notes has never been easier

Category: ProjectsKurtis @ 14:15

Twilio is a "telephony in the cloud" service that allows developers to write code to create telephony apps.

Highrise is an online contact management system created by 37 signals.

I've developed a system that combines the two to record phone calls and place appropriate notes within the highrise system for select callers. Here's how it works:

  1. I programmed my cellphone to forward all calls that receive a busy signal (ie. I hit the 'reject' button) to my twilio number.
  2. When a caller gets sent to my twilio number, twilio records the call and sends it back to my cell.
  3. I accept the call.
  4. When I hang up, twilio posts the url of the recording to my server.
  5. My server then grabs the recording from twilio and puts it on Amazon S3.
  6. The server looks up who the caller was and puts a note on highrise under that caller containing a link to play the audio file.

That works great for when a client calls and I'm not in a position to take notes. I can still accept the call and review it later. I developed this system for that need, but lately I've become more dependant on it, because it is so nice to make calls without having to take notes right then. You can review the call later if necessary. So, I developed a similar method that allows me to initiate recorded calls, with a little voice recognition snazziness.

  1. I call my Twilio number.
  2. It recognizes that it's me calling and says "Who would you like to call?" 
  3. I say "Bob Jones".
  4. It matches my audio against the list of contacts in my Highrise account and grabs the appropriate phone number.
  5. It says "Calling Bob Jones at Work... 903-555-5555 If this is wrong, press any key now"
  6. If I press a key, it starts over; otherwise it calls Bob.
  7. Repeat 4-6 in the previous list.

Right now it calls the first number listed under that contact. I would like to expand the system so I say: "Call Bob Jones at Work" and it calls Bob's work number or "Call Bob Jones at Home" and it calls Bob's home number. Also, it would be nice to have a simple way to store voice notes for a contact. For example I call my Twilio number and say "Note for Bob Jones" the system responds "Recording" then it ramble on about the meeting we just had. It would also be useful to initiate todo items via phone. I call and say "Make ToDo reminder 4:45" the system response "Go ahead" and I say "Pickup River at 5:00." Then at 4:45, twilio calls me and plays the audio I recorded: "Pickup River at 5:00".

To add to this, I would love to be able to more accurately convert a dictation to text. I've been able to pretty accurately be able to recognize commands from a small list, but the dictation recognition is pretty inaccurate. It gets maybe 5% of the words correct on a phone conversation. If anyone has any suggestions, I'll take 'em.

 

Tags: ,

Apr 24 2009

Get Website Thumbnail in C#

Category: C#Kurtis @ 07:30

Ever needed to generate a thumbnail for a website? Well I have. I looked around on the net and found some code that would do just that. I put that code on my server and created a simple web interface for generating thumbnails: http://kurtiswelch.com/util/DownloadThumbnail.aspx

If you are interested, attached is the code I found.

Here is how this class is used:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Diagnostics;

namespace GetSiteThumbnail
{
    class Program
    {
        public delegate void WebBrowserDocumentCompletedEventHandler(object sender,
            WebBrowserDocumentCompletedEventArgs e);

        [STAThread]
        static void Main(string[] args)
        {

            if (args.Length < 2)
            {
                MessageBox.Show("Usage:\nGetSiteThumbnail.exe "+
                        "http://www.yoursite.com/ thumbnail.jpg [browser_width"+
                        "(defaults to 800) browser_height (defaults to 600) ] "+
                        "[thumbnail_width thumbnail_height]\n\nSample:\n"+
                        "GetSiteThumbnail.exe http://www.cognifide.com/ "+
                        "cognifide.jpg 1280 1024 640 480\n\n",
                    "Get Site Thumbnail");
                return;
            }

            int width = 800;
            int height = 600;

            if (args.Length > 2)
            {
                width = Int32.Parse(args[2]);
                height = Int32.Parse(args[3]);
            }

            int thumbwidth = width;
            int thumbheight = height;

            if (args.Length > 4)
            {
                thumbwidth = Int32.Parse(args[4]);
                thumbheight = Int32.Parse(args[5]);
            }

            WebPageBitmap webBitmap = new WebPageBitmap(args[0], width,
                height, false, 10000);

            if (webBitmap.IsOk)
            {
                webBitmap.Fetch();
                Bitmap thumbnail = webBitmap.GetBitmap(thumbwidth, thumbheight);
                thumbnail.Save(args[1], ImageFormat.Jpeg);
                thumbnail.Dispose();
            }
            else
            {
                MessageBox.Show(webBitmap.ErrorMessage);
            }
        }
    }
}
 

 

Downloads:

WebPageBitmap.cs (7.09 kb)

Program.cs (1.93 kb)

GetSiteThumbnail.zip (55.66 kb)

Tags:

Mar 30 2009

Guid Replication Odds

Category: Kurtis @ 09:01
Your chances of winning the Texas Lottery jackpot three drawings in a row are 22 million times better than generating any one particular Guid.

Tags:

Jan 26 2009

A C# class to send email via gmail

Category: Kurtis @ 06:29

The easiest and cheapest way to get a good email solution up and running for your small business is to sign up for Google Apps. This basically gives your employees an email address at your domain through gmail. So, you get lots of storage, great spam protection, and it's free.

Most small businesses on the web will need to be able to send automated mails through their Google Apps account (I know I do). Below is a class I created in C# that does just that.

public class Email
{
    public string Subject { get; set; }
    public string Body { get; set; }
    public string To { get; set; }
    public string From { get; set; }

    public Email()
    {
        
    }

    public Email(string from, string to, string subject, string body)
    {
        From = from;
        To = to;
        Subject = subject;
        Body = body;
    }

    public bool Send()
    {
        MailMessage m = new MailMessage();
        m.To.Add(new MailAddress(To));
        m.From = new MailAddress(From);
        m.Subject = Subject;

        m.Body = Body;

        m.IsBodyHtml = true;

        try
        {
            SmtpClient client = new SmtpClient();
            client.EnableSsl = true;
            client.UseDefaultCredentials = false;
            client.Credentials = new NetworkCredential("user@domain.com", "password");
            client.Port = 587;//or use 465            
            client.Host = "smtp.gmail.com";
            object userState = m;
            client.Send(m);
        }
        catch (Exception)
        {
            return false;
        }

        return true;
    }
}

 It is used like:

Email m = new Email();
m.To = "to@example.com";
m.From = "from@example.com";
m.Subject = "This is the subject of the email";

m.Body = "This is the email body.";

if (!m.Send())
    throw new Exception("Email could not be sent!");

Tags: , ,