mo.notono.us

Thursday, October 03, 2013

Move along, nothing to see here...

Move along to @austegard on Twitter.

Who has time for more than 140 characters these days?

Labels: , , , , , ,

Friday, April 12, 2013

An experiment in social conscience and greed



A couple weeks ago, one of my coworkers found a dollar bill on the floor, and not knowing whose it was put it on my stand-up desk (aka the file cabinet next to my desk). It sat there for a couple of days, eliciting questions, but no action.

After a week, mysteriously the dollar had gained some friends in the form of five pennies, two nickels, a Chuck-e-cheese token, and a highly dubious coin simply decorated with laurels and a $, and made from cheap plastic. Then another coworker lost a bet and added the $1 pot to the ...uhm.. pot.

Last week an origami dollar bird appeared.


Current total value: $3.15, plus a game of skee ball. All sitting out in the open, ready for the taking. Yet, no.


Update 04/17
The money is gone. Budget-constraints in the snack department caused a reallocation of funding to Mama Zuma and her followers. Instantly additional funding magically appeared; the money is now gone. I blame hunger and masochistic tendencies (if you've tasted Mama's chips you'll know what I mean) more so than greed.

Labels: ,

Thursday, May 10, 2012

Lunch-time fun with QR codes

I'm a happy grouch

Starting with a B/W Oscar the Grouch image, and running it through the QArt Coder, got me here http://research.swtch.com/qr/show/e27c9ec04e3013fe - Paint.net took me the rest of the way...

Read about how this works at http://research.swtch.com/qart

Labels: , , , ,

Friday, March 30, 2012

idea: bookmarklet to persist personal form data in localStorage

As a developer, I frequently have to clear my browsers cache, and also cookies, in order to test a site.  This is a PITA as now I'm logged out from Google, PivotalTracker, etc, etc.

It also showcases how very few sites store login information in localStorage by default (note to devs, if you're to offer a "Remember Me" button, use localStorage, not a cookie). 

So my idea is this: a set of two bookmarklets: the first would retrieve any form data entered in a form (prior to you submitting it) and store that data in localStorage, then the second would fill out a form using the data stored in localStorage for that site.

What about security you might ask?  Well, clearly this should only be used on a personal computer - and maybe password fields should be excluded in any case.  But this is stored locally, it is not transmitted anywhere, and the data is not accessible to any other site, so the data should stay between you and your computer.  One exception would be any potentially malicious script hosted on the site, but that seems like a risk in itself - the same script could much more effectively simply grab the form data on entry.

So - good idea or bad?

Labels: , , , , ,

Wednesday, November 16, 2011

A non-trendy way to wrap text to the width of an image

Say you have an image, whose width is unknown.  You want to display a caption below the image, and the length of the caption text is also unknown.  How do you display the caption so that the text wraps to the width of the image?

As far as I know, there is no way to do this with divs and Css.  It *may* be possible to do it with figures and figcaptions, but now you’re in Html5 land, and to support older browsers you’ll need to do gymnastics.

You could use an img load event handler and resize the caption after the image comes in, but now you have to add javascript for something that should be handled by your html.

So you use tables.  Yes tables, those horrible, horrible remnants of Web 1.0.

And you do it like this (though your styles would obviously be in a css stylesheet somewhere):

<table>
<caption style="caption-side: bottom; margin: 0 5px;">Oh caption, my caption! our fearful task is done!<br>
The layout has weathered every wrack, the prize we sought is won</caption>
<tr><td><img alt="some unknown sized image" src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Ocaptain.jpg/394px-Ocaptain.jpg">
&/lt;tr></table>

which renders thusly (Live writer may corrupt this - sorry view-sourcers):

Oh caption, my caption! our fearful task is done!
The layout has weathered every wrack, the prize we sought is won
some unknown sized image

Also see http://jsfiddle.net/austegard/fGwve/

Labels: , , ,

Tuesday, September 13, 2011

Trying Google Scribe...

This morning I was doing some cleaning of my Bookmarks bar in Chrome, when I came across a forgotten Bookmarklet - Google Scribe.  It looks like the Scribe Lab program has since graduated and been rolled into Blogger's 'Draft' program, which is where I'm trying it as I type this. 

On my phone, I use Swiftkey, which works in a similar manner; I start typing a word, and the program suggests not only the completion of the word, but as soon as I type space, it suggests the statistically most probable next word.

Kind of freaky, but highly effective on my phone at least.  It's also interesting to see what it thinks I should be writing.  Example: I will type a word and let Scribe choose next ones:  Suggested words and word completions are highlighted:

The first day of the week andhave to take a break from the past to the future of my children.   

Pure poetry

Labels: , , ,

Tuesday, March 01, 2011

Practical example of jQuery 1.5’s deferred.when() and .then()

"“Fun with jQuery Templating and AJAX” by Dan Wellman is a generally interesting article, but I found the code in the “Getting the Data” block especially interesting – see how each get function RETURNS the $.ajax function call, which can then be called inside a when() function, vastly simplifying the workflow (there’s an error in the listed code – getTweets() is supposed to return the ajax function, not simply execute it).

http://net.tutsplus.com/tutorials/javascript-ajax/fun-with-jquery-templating-and-ajax/

Even more interesting is this pattern, suggested by commenter Eric Hynds (whose blog has now been added to my Google Reader list):

http://net.tutsplus.com/tutorials/javascript-ajax/fun-with-jquery-templating-and-ajax/comment-page-1/#comment-357637

$.when( $.get('./tmpl/person.tmpl'), $.getJSON('path/to/data') )
   .then(function( template, data ){
      $.tmpl( template, data ).appendTo( "#people" );
   });

The deferred.done() and then() methods will take as arguments the results from each function called in the when() function – in order – i.e. the output of the get will map to template, and the output from the getJson will be mapped to data.  This is pretty sweet!

Perhaps a simpler to observe example of the behavior is shown here: http://jsfiddle.net/austegard/ZaFVg/ - no prize for correct guesses as to the result of this…

/* Hello and World are both treated as resolved deferreds - they 
can be replaced with any function, like a $.get, etc */
$.when( "Hello", "World" ).then(
   function(x, y){ alert(x + " " + y); }
);

Labels: , , , ,

Wednesday, September 15, 2010

IE9 Beta test scores against Underscore.js

Another new browser launch, and another obligatory proves-absolutely-nothing-definite/just-a-single-use-case performance test against the Underscore.js utility framework.

Previous tests showed that IE was gaining on the lead (Chrome), and that is still the case: As seen in the charts below, IE is sometimes faster, but still generally slower than Chrome (longer bars are better):

Again, this test proves very little, other than that IE9’s new Chakra JS engine is still slower than V8 for doing array iterations, and faster for mapping, getting property values, and creating list ranges.  IE9 has a number of features Chrome doesn’t have (yet) such as hardware acceleration (the IE Speed reader demo runs 790% faster in IE than in Chrome!) and ES property getter/setter standard compliance, just to mention two random ones…

IE9 beta is a HUGE step forward for IE.  Not sure if it will become my default browser, but this is at great day for the web.  Now if the EU and other governing bodies can just look the other way while MS quietly replaces all prior IE instances with IE9… ;-)

Labels: , , , ,

Tuesday, August 24, 2010

iPad Mockups To Go

After using the heck out of Peldi’s (here and here) and Simon Herd’s (here) original templates for Balsamiq iPad mockups, I decided to give back to the community by creating some templates that I found were missing:

The iPad Portrait and iPad Landscape templates are 1:1 scale iPad mockups, with an inner frame with 1024x768 resolution.  I assembled the frame of the iPad piecemeal, so as to leave a “hole” in the middle, for your content to shine through.  This is something I sorely missed with Peldi’s templates, forcing me to do far too much work in Paint.Net, manipulating my images to fit his frame exactly.

Complementing these is my iPad Keyboards template.  If you’re already using one of the above templates, this one isn’t necessary, but if you want to use Peldi’s templates, my template will come in handy.  It's simply the iPad keyboard as Simon Herd originally created it, but in 4 different resolutions, with minor corrections:


Enjoy.

Labels: , , , ,

Saturday, June 26, 2010

Undersore.js Performance Tests Revisited (this time with pretty charts)

Out of sheer vanity, I added my own blog feed to my Google Reader, as I was curious if anyone ever Liked my posts.
Answer: Nope. :-(

Anyhow, I came across my post on Underscore.js, and since MS just dropped Platform Preview 3 of IE 9, I thought I’d redo the comparison in Chrome6, IE8 and IE9 (though I know this is hardly any complete benchmark test, it’s still telling).  The results are below: 

As I said in my last post, I can’t wait for IE9 to replace every previous IE version…  I haven’t been this excited about an IE product since IE4, which was more than 10 years ago.

IE 8 – still a dog.

IE8 results

IE 9 PP3 – Starting to look good!  Faster than Chrome in some tests!

IE9 results

Chrome 6 – still the winner in most categories, though the lead is shrinking

Chrome 6 results

Bottom line, though – if you’re doing a lot of looping/mapping, you should use Underscore rather than jQuery.

Labels: , , , , ,

Sunday, June 13, 2010

IE 9 HTML5 Testing: “Works on My Machine”

One of my esteemed colleagues on an internal forum posted about how great IE 9’s HTML5 support was, based on the result of Microsoft’s test pages.  MS’s tests are sadly self-selective however: meaning they only seem to test for elements that IE9 supports: http://samples.msdn.microsoft.com/ietestcenter/

“Cross-browser Test Results Summary:
W3C Web Standards Number of Submitted Tests Internet Explorer 9
Platform Preview
Mozilla Firefox 3.6.3 Opera 10.52 Apple Safari 4.05 Google Chrome 4.1
HTML5 40 78% 63% 48% 43% 43%
...”

Compare that to my own results running html5test.com on the 6(!) browsers I have installed:

html5test

Html5 is the first time in a decade that the browser vendors have had a new major standard to fight over; I’m just grateful that this time around we’ll have an army of frameworks such as jQuery that can level the development playing field for us.

Labels: , , , , , , , , ,

Monday, May 24, 2010

Comparative Performance of Underscore.js in Chrome and IE

I came across the very handy-looking Undersore.js today, and clicked on the test & benchmark link. I first ran the test in Chrome.  The results below show number of operations per second.  Looks like each, map, keys, values, and range are pretty inexpensive operations, whereas uniq and intersect should be used sparingly.  All makes sense. 

Then out of curiosity, I ran the same tests in IE and Firefox.  The exact numbers are not significant as the results vary by 10-20% between subsequent runs in the same browser, but the range is pretty illustrative.  And yes, I know IE9 is harder, better, faster, stronger, so this is not a fair fight.  I can’t wait for IE9 to replace every previous IE version…

  Ops/sec

(higher is

better)
Test Chrome 6 IE 8 Firefox 3.6

_.each()

20213

510

3249

_(list).each()

13570

493

3161

jQuery.each()

3637

209

910

_.map()

18581

303

5488

jQuery.map()

7084

686

8519

_.pluck()

10852

282

4785

_.uniq()

127

1

33

_.uniq() (sorted)

308

210

84

_.sortBy()

1641

45

359

_.isEqual()

4962

869

1826

_.keys()

22675

1142

4295

_.values()

24551

321

5435

_.intersect()

83

1

20

_.range()

33345

1223

5262

Again, why I use Chrome as my default browser.

Labels: , , , , ,

Friday, April 30, 2010

Fun with 1000 Rolling Stone covers, AndreaMosaic and the Deep Zoom Composer

UPDATE 08/11/2011: See post about the new archive, now also for the iPad here: archive.rollingstone.com – another feather in our cap

Having finished helping Rolling Stone magazine put their archive online (our company, AIS, together with Bondi Digital, did the Silverlight-based archive portion (more on the project later, potentially), another company did the main site), I decided to get artsy by generating a mosaic of the latest issue cover, by using thumbnails of some 1000 previous covers.

mosaic partial zoom

AndreaMosaic worked beautifully in creating the mosaic, and even pre-generating the starting point for a Deep Zoom image.  I opened that in Deep Zoom Composer, and generated both a Silverlight and an Seadragon Ajax version of the composite.  I then uploaded the whole shebang to my public s3 bucket.

It all took a bit of fiddling to get right, but if I had to do it again I could probably do the whole thing in 5-10 minutes…  It’s that easy. (Seriously, this blog post is taking longer…)

Of course, now that I’m putting in all the links in this post, I realize I could have simply hosted this at seadragon.com…  Oops.

UPDATE:Since MS is so kind to do the processing for me, I figured I might as well create a bigger version of this. The following is around 180MP, made up of 3000 tiles, each 300px tall... Click the full screen button in the embedded viewer for the best effect.

Update, May 12th: ...and here's the latest 2-page cover:

Labels: , , , , , ,

Thursday, April 08, 2010

Uri Properties

For the life of me I can never remember what each property of the Uri class is meant to return.  SnippetCompiler to the rescue:

public static void RunSnippet()
{
  Uri foo = new Uri("http://some.domain.com/folder/file.htm?param=val#frag");
    foreach(PropertyInfo pi in foo.GetType().GetProperties()){
      if (pi.CanRead) {
        WL("{0}: {1}", pi.Name, pi.GetValue(foo, null));
      }
    }
}

Make sure using System.Reflection; and using System.Web; are is included, and there you have it:

AbsolutePath: /folder/file.htm
AbsoluteUri: http://some.domain.com/folder/file.htm?param=val#frag
Authority: some.domain.com
Host: some.domain.com
HostNameType: Dns
IsDefaultPort: True
IsFile: False
IsLoopback: False
IsUnc: False
LocalPath: /folder/file.htm
PathAndQuery: /folder/file.htm?param=val
Port: 80
Query: ?param=val
Fragment: #frag
Scheme: http
OriginalString: http://some.domain.com/folder/file.htm?param=val#frag
DnsSafeHost: some.domain.com
IsAbsoluteUri: True
Segments: System.String[]
UserEscaped: False
UserInfo:

UPDATE:  Steve Michellotti just showed me how this works beautifully in LinqPad as well, just set the language to C# Statement(s), replace WL with Console.WriteLine and you’re good to go.

Labels: , , , ,

Tuesday, November 17, 2009

How to Upgrade a WSPBuilder Project to SharePoint 2010

<UPDATE date=”2009.12.02”>: WSPBuilder Extensions 2010 Beta 1.3 (or newer) makes the below mostly obsolete – though I was still not able to deploy using the VS add-in – I got a message stating my SPTimer Service was not running.</update>

Based on advice from Bjørn Furuknap (@furuknap, http://furuknap.blogspot.com/2009/11/using-wspbuilder-for-sharepoint-2010.html) I was able to deploy to SP 2010 a rather complex WSPBuilder-based SharePoint solution that I first recompiled in VS 2010.

Steps were:

  1. Download the command line version, with the x64 cablib dll
  2. Upgrade your VS 2008/2005 solution to VS 2010
  3. Replace your 12 references with their 14 equivalents - most will be found in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI
  4. Compile your VS solution - this SHOULD work
  5. Use the wspbuilder command line tool to create, but not deploy your wsp (use wspbuilder -help for instructions)
  6. Use stsadm -o addsolution -filename <yourwsp> to deploy the solution

Labels: , , , , ,

Saturday, September 19, 2009

Mimicking Outlook 2010’s Conversation View in Outlook 2007

One of Outlook 2010 (and Gmail)’s better features is that conversations are grouped together – that is: if you send me a message, and I reply, and you reply again, all three messages are grouped together – not just the two you sent me.

The latter is what Outlook 2007 considers a “conversation” – I’d call it a monologue, or at best half a conversation.

To get the full duplex conversation thread in Outlook 2007 do the following:

  1. Right-click Search Folders, select new Search Folder
  2. In the New Search Folder dialog, scroll all the way to the bottom, and select Create a custom Search Folder, then click the Choose.. button.
  3. In the Custom Search Folder dialog, enter a name that makes sense to you – I’ll call it Inbox2.0 - SKIP THE CRITERIA, then click Browse… to select which folders to include.
  4. In the Select Folder(s) dialog, select the Inbox and Sent Items folders (and any subfolders/other folders that may make sense for your setup), then click OK
  5. Back in the Custom Search Folder dialog, click OK
  6. Outlook will present a warning that all items in the folders will be included – this is precisely what you want, so click Yes
  7. Your new (Inbox2.0) folder will appear listing all received and sent messages
  8. From the View menu, select Arrange By, Conversation – now your messages are threaded by conversation – the full duplex kind.
  9. From here, you may chose to remove/insert colums (I like to show the 'To' recipient and remove the 'In Folder', and also the 'Subject' column – it is (mostly) a duplicate of the conversation title.

Enjoy your new duplex view.

Labels: , , ,

Friday, July 31, 2009

ASP.NET MVC: TagBuilder Extension Methods

I wasn’t happy with the TagBuilder class, so I improved it… See gist below:

This kind of thing could be useful in MOSS WebPart development as well…

Labels: , , , , , , , ,

Monday, July 06, 2009

Testing gist.github.com as a blog code pastebin

I’m new to github, so therefore I’m also new to gist.  At first I couldn’t figure out what they were, but then I watched this great intro video by ByanL which explains it all quite well.

Github seems a bit too command line focused for my taste, but Gist looks useful by itself.

Below I’m going to embed the source for my Twitter Conversations test page, which I copied into my very first Gist – whoa! it loads immediately in the edit panel in Live Writer, nicely color-coded and everything.  Nice!

Thanks to Rob Conery for moving Subsonic 3 to github, which made me look in the first place.  I’ll be using this.

Labels: , , , ,

Wednesday, July 01, 2009

How about this for a business idea

Seth Godin makes some excellent points in his blog post “Graduate school for unemployed college students”.  Basically he says unemployed college grads should just approach the next 12 months as if it was another year of school, and spend the time contributing to the community while learning marketable skills.  Great concept, but as 3rdgirl and snappers15 point out, this is hard to pull off when faced with student loans or other financial responsibilities.  Seth acknowledges this in his followup-post, “Tough!”, but doesn’t offer these people any actual solutions.

How about this for a business idea - and solution to the grad’s financial problem - :

A joint recruiting and student-loan firm that does four things: 

  1. places college grads with non-profits for part time, minimum-wage paid work ($7,540 per year for a 20hr workweek), plus bare-bones health insurance.
  2. provides study-sessions/instruction/seminars/workshops for real world, marketable skills
  3. provides some form of student-loan deferment for the candidate’s current loans, removing that burden for one year from the grad’s shoulders
  4. acts as a recruiter for the grads, generating recruiting fees (to cover costs)

Come to think of it, why can’t our colleges do this, already?  Or why can’t they provide real-world marketable skills in the first place?

Labels: , , , , ,

Wednesday, June 17, 2009

More complicated JavaScript string tokenizer – and Twitter Conversations

(I'm not sure when I started using the term tokenizer - "formatter" may be more common...)

I’ve experimented in the past with a C# string.Format() alternative that would allow property names as tokens rather than the numeric index based tokens that string.Format() uses.  Hardly a unique approach, and many others did it better.

Here’s another first-draft ‘tokenizer’, this time in JavaScript:

String.prototype.format = function(tokens) {
///<summary>
///This is an extension method for strings, using string or numeric tokens (e.g. {foo} or {0}) to format the string.
///<summary>
///<param name="tokens">One or more replacement values
///if a single object is passed, expects to match tokens with object property names, 
///if a single string, number or boolean, replaces any and all tokens with the string
///if multiple arguments are passed, replaces numeric tokens with the arguments, in the order passed
///</param>
///<returns>the string with matched tokens replaced</returns>
  var text = this;
  try  {
    switch (arguments.length) {
      case 0: {
        return this;
      };
      case 1: 
      {
        switch (typeof tokens) {
          case "object":
          {
            //loop through all the properties in the object and replace tokens matching the names
            var token;
            for (token in tokens) {
              if (!tokens.hasOwnProperty(token) || typeof tokens[token] === 'function') {
                break;
              }
              //else
              text = text.replace(new RegExp("\\{" + token + "\\}", "gi"), tokens[token])
            }
            return text;
          };
        case "string":
        case "number":
        case "boolean":
          {
            return text.replace(/{[a-z0-9]*}/gi, tokens.toString());
          };
        default:
            return text;
        };
      };
      default:
      {
        //if multiple parameters, assume numeric tokens, where each number matches the argument position
        for (var i = 0; i < arguments.length; i++) {
          text = text.replace(new RegExp("\\{" + i + "\\}", "gi"), arguments[i].toString());
        }
        return text;
      };
    };
  } catch (e) {
    return text;
  }
};

The comment (in VS Intellisense format) is pretty self-explanatory, note that it doesn’t allow any special formatting as String.Format does, nor does it even support escaping {}‘s – in general it is quite crude.

That said, when used within it’s limitations it works - below are a couple of actual usage scenarios, both from my ongoing Twitter Conversations experiment:

var url = "http://search.twitter.com/search.json?q=from:{p1}+to:{p2}+OR+from:{p2}+to:{p1}&since={d1}&until={d2}&rpp=50".format({ 
  p1: $("#p1").attr("value"), 
  p2: $("#p2").attr("value"),
  d1: $("#d1alt").attr("value"), 
  d2: $("#d2alt").attr("value")
});

and

$.getJSON(url + "&callback=?", function(data) {
  $.each(data.results, function(i, result) {
    content = ' \
<p> \
	<a href="http://twitter.com/{from_user}"><img src="{profile_image_url}" />{from_user}</a> \
	(<a href="http://twitter.com/{from_user}/statuses/{id}">{created_at}</a>): \
	{text} \
</p>'.format(result);

The working Twitter Conversations sample is here, as you can tell it’s really just a wrapper around the Twitter Search API.

Labels: , , ,