Showing posts with label software. Show all posts
Showing posts with label software. Show all posts

Tuesday, January 26, 2010

Announcing ePubLib

I have published a project on CodePlex, ePubLib. ePub is quickly becoming the defacto standard for e readers, and after getting my hands on a (used and cheap) Sony Pocket Reader I wanted to be able to create documents to put on the device.

The format isn't particularly complicated, but there are a lot of little things that have to line up. This library makes it extremely easy. Create a Book object. Create 1 or more Chapter objects. Add the Chapter to Book.Chapters. Call Book.Save(). You can do the same thing for images as of the commit last night. The only knowledge that's required is basic XHTML skills and .NET to use the library.

I also wrote a utility to log me into The Economist's web site (I'm a paying subscriber) and scrape the Print Edition. It works great, a proper TOC, all of the articles and all of the images. I don't think I can upload that source to CodePlex due to perceived copyright concerns, but drop me a comment if you're interested.

Tuesday, December 29, 2009

Updated RSS and Atom Links

As part of the migration to Blogger, I have set up legacy redirect links from travis.pettijohn.com/blog/ to www.pettijohn.com (I'll add to them as I continue importing day by day). I will leave the redirects in place for a few months, at least until Google and Bing stop indexing the old URLs.

If you are a subscriber via RSS, please update your reader to this new link: RSS. Atom.

Saturday, December 26, 2009

Blogger Migration

I'm moving my blog to Blogger, formerly hosted in a custom ASP.NET app running at home. I want to get out of the business of running a server at home, and have migrated that box to Windows Home Server (I'll rave about that in another blog post).

Only one problem to migrating via the Blogger APIs: they rate limit you to fifty posts per day (the failure is an HTTP 400 with a plain text body "Blog has exceeded rate limit or otherwise requires word verification for new posts"). I'm not sure if that includes comments or not (which I'm importing, too). But either way, it will be somewhere between a week or two until I'm done (the code's all written, I just need to run it until it stops every day).


Home, sweet home.

Wednesday, November 25, 2009

Troubleshooting a Custom Resource Provider in ASP.NET

My current project is a large multi-lingual eCommerce engagement. Due to business requirements (on-the-fly updates), we externalized resources into a database (following this MSDN article). Furthermore due to business requirements (uptime for a very high revenue site with regular mid-day content updates), they need to be able to publish markup (aspx & ascx) on the fly without restarting IIS.

We were seeing a sporadic issue where resources would disappear on the page. For example, there was custom control that looked like so:

<custom:CustomHyperLink ID="TL" runat="server" ImageUrl="[Header Image]" SiteMapNodeId="Basket" ToolTip="[Header]" meta:resourcekey="HeaderImage" />

When everything was working (which was 99% of the time), the ImageUrl would be looked up at runtime (via the control's HeaderImage.ImageUrl resource) and substituted in as ~/images/en/header_en.gif. But when it didn't work, we would see an <img src="[Header Image]" />, which obviously is a problem.

Adding to the confusion was that only some of the resources showed this problem. Also, it was seemingly random. Everything would be working one minute, broken the next, in the middle of the day. Putting together steps to reproduce was nearly impossible. It had something to do with loading resources and/or compiling the site and/or restarting iis and/or the planets aligning.

Here's what we didn't understand: Resources in ASP.NET can be declared either explicitly or implicitly. Explicit means code, GetGlobalResourceObject("keyName") or GetLocalResourceObject("keyName"). Implicit means markup, meta:resourcekey="keyName".

Explicit calls are evaluated at runtime, every time, because it is regular code that gets executed in the regular way.

Implicit calls are evaluated once at compile time, and the compiler (essentially) hooks up a binding to between the appropriate property and the explicit / GetLocalResourceObject()* call. To walk through the above control sample:

  • At ASP.NET compile time, that line is parsed. The compiler looks at what’s specified in meta:resourcekey.
  • That key is passed into IImplicitResourceProvider.GetImplicitResourceKeys. This method queries the resource provider for all valid keys starting with HeaderImage, and returns all of those keys in an ICollection. Our example thus returns {"HeaderImage.ImageUrl", "HeaderImage.ToolTip"}.
  • The compiler inspects all of the keys, parses them, and performs databinding. Our example matches HeaderImage.ImageUrl from our resource provider and hooks up a binding between the property and IImplicitResourceProvider.GetObject("HeaderImage.ImageUrl") ... *which I believe calls GetLocalResourceObject() to complete the circle.

If the resource datastore, whatever it may be, is unavailable (or empty!) at ASP.NET compile time, the call to GetImplicitResourceKeys will return nothing and no databinding will occur.

That's what was happening to our resources. We would push new markup and immediately afterwards import new resources. But our import process was naïve; it deleted all of the resources from the database, scanned the filesystem for .resx files, loaded them into memory, and then inserted them into the database. And because it was a live site, many of these controls would be hit by the ASP.NET compiler while the database was empty. This meant the compiler thought it had nothing to do because GetImplicitResourceKeys returned nothing and so would let the resources fall back to their default text, in our case, [Header Image].

The resources that never exhibited a problem were of course retrieved explicitly.

I want to give credit to Rick Strahl, whose blogged frustrations about this topic helped point me in the right direction. Unlike him, I did not have to implement IImplicitResourceProvider (which agrees with MSDN), I just had to trace down a race condition where it was being called at an inopportune time.

In summary, pushing new markup and then immediately emptying the resource datastore on a live site will break implicit (meta:resourcekey) resources due to how the ASP.NET compiler resolves implicit bindings.

Sunday, January 25, 2009

Bootable USB Flash Drive

Reposting these instructions on making a bootable flash drive.

  • On a command prompt, run diskpart.
  • list disk
  • select disk 2 (Replacing 2 with the correct number!)
  • clean
  • create partition primary
  • select partition 1
  • active
  • format fs=fat32 quick (Note that fs=ntfs will NOT be bootable!)
  • assign
  • exit
  • robocopy /MIR [source drive] [destination flash drive]

In short, you create an active, primary partition on the drive (and you have to do this in diskpart, because the Windows UI doesn't support it) and then you copy the files from your Windows installation media to the drive. And here I always thought that this was something difficult!

Sunday, July 27, 2008

Windows Mobile 6.1 Upgrade

I just upgraded my HTC Sprint Mogul/PPC6800 to Windows Mobile 6.1. Before I upgraded, I took down a list of the key software that I needed to reinstall. In no particular order, I present my key Windows Mobile utilities:

  • S2U2 - an iPhone screen locker clone. Search to find the latest version in the XDA developers forums.
  • gpsVP - Open source/Garmin Research project for GPS. Works with most (all?) Garmin GPS maps, and best of all, it can be used offline (no active cell/data connection required). Save trails, import & export waypoints, etc. Very cool.
  • Live Search - Good for turn-by-turn driving directions and location-based services (like, show me bars near where I am right now).
  • OneNote Mobile - Take your favorite notebook on the road. You do use OneNote, don't you? Install from OneNote on the desktop: Tools / Options / OneNote Mobile.
  • SKTools - Utility for cleaning up the Notifications Queue on Windows Mobile. If you have ever experienced the "phantom alarm," this utility can clean that up.
  • Google Maps - Good for driving directions and "where am I right now." Not as feature-rich as Live Search, but more user-friendly. Depends on what I'm after.
  • VisualGPSce - Another GPS utility. Just gives raw data from the satellites.
  • TouchPal - The best on-screen keyboard I've found. I have stopped using the hardware keyboard on the Mogul in deference to this.
  • Streaming Media - For playing streaming media, especially from m.youtube.com.
  • Remote Desktop - Sprint removes Remote Desktop from their firmware. Why? I add it back in.
  • Total Commander - Replacement for Explorer, and also a registry editor.

Thursday, June 19, 2008

How to make URLs clickable in Office Communicator

Edit: This is the lame. All it does is make links that you send clickable. All incoming URLs are still plain text.

Source.

  1. Open registry editor and go to the following registry entry:
    HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Communicator
  2. Add the following key to above mentioned entry
    EnableURL (Type:DWORD), value can be either 0 (URL will appear as plain text) or 1 (makes URL clickable)

Now close the registry editor and restart Microsoft Office Communicator 2007, URLs should now be clickable. Administrators can control values of this feature via group policy settings.

Wednesday, June 11, 2008

WMP Keys

WMP Keys, a Media Player plugin to let you assign global keyboard shortcuts. Pretty handy to not have to alt-tab or jump to the mouse to perform common WMP functions.

Sunday, June 08, 2008

Sideshow for Windows Mobile

I'm a few days late with this one, but Microsoft has released a Sideshow application for Windows Mobile. Download link for the Developer Preview.

Tuesday, May 27, 2008

Hyper-V

This weekend I added a second hard drive to my Toshiba M9 laptop (in the CD-ROM bay). I then was able to install Windows Server 2008 on a second partition on the primary drive. After that was up and running, I set up Hyper-V with the goal of migrating my primary Vista installation (the one on the first partition) to a virtual machine. The process was easy enough: in the Hyper-V Manager, create a new VHD and tell it to clone a copy of the existing first hard drive. A few hours later, I now had a VHD on my second hard drive that was an exact clone of the first drive. I mounted it in a virtual machine and booted: to my surprise, there were my boot options, Server 2008 and Vista. And Vista x64 started right up (amazing it didn't blue screen during boot with all the hardware changes; also amazing, a 64-bit guest OS). But, here's the rub and the deal breaker: I couldn't install the "virtual machine additions" (I forget the correct Hyper-V term), as they aren't supported on 64-bit Vista. Performance was quite good, and I was able to share both physical CPUs inside the virtual machine. Here's to hoping they fully support 64-bit Vista as a guest!

Tuesday, April 08, 2008

reCAPTCHA: Stop Spam, Read Books

I just discovered this site, http://recaptcha.net/. They do the regular "image verification" stuff you see to prevent spam on web sites, except they use scans from real books. They present two words: one for which the result is known and a second for which the OCR had low confidence. If you match the known word, they assume you're probably right on the unknown word, too (and they verify it multiple times to improve confidence). I think it's a great idea: as a side effect of preventing spam, they're digitizing old books. Cool.

Sunday, March 02, 2008

SSTP VPN

Now that I have Vista SP1 on my primary machine, I wanted to set up my Windows Server 2008 box to act as an SSTP VPN endpoint. SSTP essentially tunnels a PPP VPN over HTTPS. What's great about this is that port 443 is almost always open, increasing the odds that I can connect to home from anywhere. I actually bought an SSL certificate (see?) from GoDaddy (it was $15/year). I had a couple issues installing the certificate and making the VPN work. First, I had to install the certificate on the command line, as the UI was giving me an error (ASN1 bad tag value met). Second, I had to remap the certificate to port bindings. I believe that my setup was incorrect because it had only ever been bound through the IIS UI. Again, using the command line fixed it.

Further Reading:
Detailed post of how SSTP works.
More blog entries on SSTP.

Sunday, February 17, 2008

uTorrent

After the aforementioned upgrade, I was going to install Azureus, but instead decided to try uTorrent. I have to say, it's pretty slick. Super light and fast, and the UI is very familiar-feeling for an Azureus convert. But the best part is that it doesn't have any of that Vuze content crap that I don't want. Just a lightweight BitTorrent client—you know, like Azureus used to be.

Saturday, February 16, 2008

Upgraded

I had a little down time this morning as I upgraded from Server 2008 RC0 to RTM. The upgrade blue-screened, so I ended up wiping the boot partition and reinstalling from scratch. A little more time consuming, unfortunately.

Tuesday, January 15, 2008

TouchPal

I just discovered TouchPal, an on-screen keyboard for Windows Mobile optimized for fat-fingering. I'm pretty happy with my Mogul, but one of my biggest gripes is the delay when I slide out the hardware keyboard (and it switches from portrait to landscape mode), and the on-screen keyboard requires a stylus (or the corner of a fingernail). This little freeware utility has nice finger-sized buttons, predictive input and an easy way to be precise (tap on the big QW key and then slide right to pick W, or left to pick Q). If you share my gripes, check out this utility.

Sunday, January 06, 2008

FLAC to WMA Lossless Script

Requires Windows Media Encoders and FLAC.

foreach ( $file in dir *.flac )
{
	# Prep input and output filenames 
	$shortName = $file.Name.Substring(0, $file.Name.Length - $file.Extension.Length);
	$wav = $shortName + ".wav";
	$wma = $shortName + ".wma";
	
	# Decode FLAC to WAV
	& 'C:\Program Files (x86)\FLAC\flac.exe' -d $file.Name

	# Encode WAV to WMA Lossless
	cscript "C:\Program Files\Windows Media Components\Encoder\WMCmd.vbs" -input $wav -output $wma -a_codec WMA9LSL -a_mode 2

	# Cleanup
	del $wav;
}

Wednesday, January 02, 2008

Yikes!

After the first drive in my old file server died, I made a backup of all of my photos...or so I had thought. But actually, I didn't get them all. For some reason NONE of my Africa pictures got backed up!! YIKES. I discovered this tonight when I wanted the original image for the header on this web site. I checked the original card in my camera, my external hard drive..., the copy I had made on the new file server...nothing. A few minutes later I remembered that I had at one time burned other copies: one I sent to my Dad so he could view a slideshow on his DVD player, and another that I kept for myself. Thankfully, I found my copy in my "box 'o pictures" and have recovered all of the photos...PHEW.

It goes to show you: even when you make a backup (or even when you have an implicit backup with a RAID), you could make a mistake and unknowingly miss something. Be proactive in making backups, ESPECIALLY with irreplaceable things like photographs.

I would have been a sad little boy if I had lost all of those pictures. Imagine how it would make you feel if you lost all of those digital photos you have of your kids/grandkids/friends/whatever. Consider even burning another copy and sending the CD/DVD to someone else.

(Now that this blog is online, I may devote some time to that Amazon S3 application I've been wanting to write for encrypted off-site backups.)

Tuesday, January 01, 2008

Back Online

Hi, everyone. I'm back online after a pretty catastrophic file server crash. I built a new file server (Quad Core Q6600 (2.4GHz x4), 4GB RAM, 3x500GB hard drives in RAID 5 for 1TB storage) and then wrote a new blog engine. There's more than meets the eye to this engine, as it supports an extensible typing system at its core (I'll be able to create a Restaurant Review type with extended properties for the name, the type of cuisine and a 0-5 star rating, for example) that is strongly typed, indexable and searchable, yet transparent to the data access layer. More on that later. It also supports tagging and nicely designed URLs (courtesy of Intelligentcia's URL Rewriter). I was able to recover about half of my existing blog posts from the Live Search API's cache and Google's Cache.

Some links have changed, yet I'm doing a 301 Moved Permanently for all legacy URLs, so you're probably reading this as a result of that. Regardless: RSS. Home page (unchanged). Feels good to be back! Stop by and check out the new layout, while you're at it.

Saturday, June 23, 2007

Vista Elevated Command Prompt

Registry hack to let you right click on any directory and open an administrator command prompt. Pretty cool trick. I added /T:4f to the command line to give it a nice, clear administrator designation (red background). My reg file looks like this:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\runas]
@="Administrator Command Prompt here"
"NoWorkingDirectory"=""

[HKEY_CLASSES_ROOT\Directory\shell\runas\command]
@="cmd.exe /T:4f /k \"pushd %L && title Command Prompt\""

[HKEY_CLASSES_ROOT\Drive\shell\runas]
@="Administrator Command Prompt here"
"NoWorkingDirectory"=""

[HKEY_CLASSES_ROOT\Drive\shell\runas\command]
@="cmd.exe /T:4f /k \"pushd %L && title Command Prompt\""

Does anyone know a command line to elevate me? I mean...if I start a regular non-admin cmd.exe and I want to elevate at some point, is there an easy way?

Tuesday, June 05, 2007

Tom Hollander article

Tom Hollander has a good post on the success of software projects.

Each project is governed by the "iron triangle" of scope, schedule and resources. ... The thing I am trying to understand is why we (meaning both the development teams and the business groups) insist on playing this game by pretending it can all be done. ... The business can blame the development teams for failing to meet the agreed deadlines or requirements. The development teams can blame the business that the initial requirements were not detailed or accurate enough. Everyone walks away vindicated that it wasn't their fault that the project failed.