Rss 2.0 via FEED

About...

I was discussing ‘googlability’  - a new word I made up meaning ‘the ability to find via Google’ – of our knowledgebase with one of the technical guys at work.
It seems that we seldom get matches in Google searches (and the built in search is somewhat lame) – I was quite surprised with the fact that Google wasn’t matching anything.

Looking into it a bit further, I found that although our knowledgebase is public, the Urls are pretty undiscoverable, all having a ‘articleid’ parameter – obviously, the GoogleBot couldn’t just guess at the values and so was skipping the majority of our article, apart from the few listed on the main page.

We needed to give it some hints by adding a sitemap. I (ever so) briefly toyed with adding a sitemap page to the knowledgebase website using the standard XML based sitemap protocol etc, but our site is written in PHP and I didn’t want to get bogged down in all that again…
In a rare burst of being pragmatic and keeping things simple (as opposed to _way_ over engineering a solution) I recalled that Google’s webmaster tools allow you to submit a text file as a sitemap with one Url per line.

I knew the format of the Url for our articles so it just required a bit of PowerShell to generate a bunch of lines containing Urls with sequential numbers and write them to a file. version 1 looked like this :

set-content "c:\sitemap.txt" (1..1000 | %{ "http://support.c2c.com/index.php?_m=knowledgebase&_a=viewarticle&kbarticleid=$_&nav=0`n" })

However, uploading this sitemap caused the Google machine to choke and spew out a bunch of errors about invalid Urls… A little more digging uncovered that the text file uploaded must be encoded in UTF8. So version 2 looked like this :

set-content "c:\sitemap.txt" (1..1000 | %{ "http://support.c2c.com/index.php?_m=knowledgebase&_a=viewarticle&kbarticleid=$_&nav=0`n" }) -encoding UTF8

Out popped a text file with 1000 Urls, in the correct format, with the correct encoding and accepted by the Google machine with no problems.
Probably 10 minute work all in – I wouldn’t have even got the PHP coding tools fired up in that time – reminder to self “KISS works !!

GEO51.4043502807617:-1.28752994537354

Share/Bookmark

Posted: Friday, January 15, 2010 2:40:54 AM (GMT Standard Time, UTC+00:00)  #   Comments [1]
TAGS: PowerShell | Web

I was working on an old (classic) ASP page the other day. It was pulling data from an Access database file and using an ODBC driver to get the connection.

It was working fine on a Windows 2003 server, but when I pulled the file into a local website on my Windows 7 machine (with Office 2010 beta) it kept failing at the ODBC layer. The reported error message was :

Microsoft OLE DB Provider for ODBC Drivers error ‘80004005’
[Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified

Looks like the driver specified in my connection string couldn’t be found. I was using the following :

    objConn.Open "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=c:\inetpub\wwwroot\pstdiscovery.mdb;"

This all looked correct and checking the excellent “ConnectionStrings.com” website they were saying the same thing – strange. It then struck me that I’m using Win 7 and Office 2010, either of which could have changed the ODBC driver or installed a new driver, so checking the “Data Sources (ODBC)” tool I see that the driver also works with .accdb files, so I’m guessing this is an updated driver.

Changing the connection string (adding the *.accdb) was the next step.

objConn.Open "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)}; DBQ=c:\inetpub\wwwroot\pstdiscovery.mdb;"

Testing with this new connection string worked fine - problem solved….

image

GEO51.4043502807617:-1.28752994537354

Share/Bookmark

Posted: Wednesday, January 13, 2010 10:23:22 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: Development | Scripting | Web

image Recently I have been working with DotNetNuke. This is a superb open source CMS platform running on ASP.NET with a SQL back end, simple to install, easy to use and there is a thriving community around it. It is also available in a ‘Professional’ version which costs around £2000 per year and provides additional workflow features, a support contract and various other benefits.

image I choose not to go for the pro version, just because I don’t see much point in having some aspects of a website/webapp covered with a support agreement, but not others (any third party controls/extensions are not covered, and I had bought the excellent DataSprings Suite and was using multiple components from it).

Anyway, when I had everything working the way I wanted, I started to look at performance. There are many websites providing tools and tips around maximizing performance of DNN sites – this includes caching strategies, output compression, turning off none essential ‘housekeeping tasks’ and the like.
One of the tweaks (for low traffic sites) was to ‘kick’ the site every few minutes to ensure that IIS does not unload it (and therefore need to spin it up again the next time someone visits – this can take a good few seconds).image

  My initial thoughts were around a scheduled PowerShell command – simple to come up a one liner to request a page and thus keep the web app in memory.

(new-object “System.Net.WebClient”).DownloadString(“http://www.website.com/”)

Then I thought I might have it ‘kick’ a few websites, and make it configurable, so I started thinking ‘Windows Service’. It turns out that there are a load of these apps and services available to buy, some targeted specifically at DNN, some more generic. Reluctant to spend $20/year on a service I decided to craft my own.

It is basically a windows service, that reads an XML file for a timeout and a list of urls to kick. It implements a 1 second timer and counts down the timeout value, when it reaches 0 it kicks each of the urls (recording how long the response took). I haven’t done anything with the measured response time, but it would be fairly easy to write out to a DB or file for later analysis…

Here is a .zip file with everything you need – binaries, sample configuration file, install instructions and full source. It is Creative Commons license so knock yourself out.

WebAppKeepAlive.zip

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Saturday, September 26, 2009 10:30:41 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | ASP.NET | C Sharp | Development | Software | Web

Disclaimer: Screenscraping results like this probably contravening Google’s Terms of Use (or something) and I do not advocate that you do it – this is purely hypothetical, if I did want to do it, this is how I would go about it  ;-)

Further Disclaimer: The results page formats could change at any time and may well break this script, if that happens you are on your own (FireBug and some modified regex should help you out).

image

So, if you wanted to get the Google ranking of a bunch of domains when searching for a particular term you could use one of the many SEO page ranking test sites that are available, but these are a pain in as much it they require you to enter the search term and the domain name you are looking for and they give you the ranking (what position in the results the domain name comes). that is fine for individual searches (like what position is kapie.com if I search on ‘Ken Hughes’), but not very good for doing a comparison of multiple domains against the search term.

I looked at using Googles Search API to get this info, but unfortunately it only returns 4 or 8 results (it is mainly designed to present some brief results in a box on your website), what I needed was to look at a lot more results (like up to 500)….

Back to my trusty friend – PowerShell…

I create a web client, have it download the first X (500) results to the search term, load the link Url and the position into a hashtable and then lookup the hashtable to find the rank position of each of the domain names I am looking for.
It was actually pretty easy, the only difficult part was getting the regex(s) correct – Regex is evil, as evil as Perl….

Here is the script code :

  $domainNames = "google.com", "live.com", "bing.com", "yahoo.com"
  $maxResult = 100
  $searchTerm = "search"

  $urlPattern = "<\s*a\s*[^>]*?href\s*=\s*[`"']*([^`"'>]+)[^>]*?>" 
  $hitPattern = "<\s*(h3)\sclass=r>(.*?)</\1>"

  $wc = new-object "System.Net.WebClient"
  $urlRegex = New-Object System.Text.RegularExpressions.Regex $urlPattern
  $hitRegex = New-Object System.Text.RegularExpressions.Regex $hitPattern
  $urls = @{}

  $resultsIndex = 0
  $count = 1
  while($resultsIndex -lt $maxResults)
  {
    $inputText = $wc.DownloadString("http://www.google.com/search?q=$searchTerm&start=$resultsIndex")
   
    "Parsing : " + $resultsIndex

    $index = 0
    while($index -lt $inputText.Length)
    {
      $match = $hitRegex.Match($inputText, $index)
      if($match.Success -and $match.Length -gt 0)
      {
        $urlMatch = $urlRegex.Match($match.Value.ToString())
        if(($urlMatch.Success) -and ($urlMatch.Length -gt 0))
        {
          $newKey = $urlMatch.Groups[1].Value.ToString()
          if(!$urls.ContainsKey($newKey))
          {
            $urls.Add($newkey, $count)
          }
          $count++
        }
        $index = $match.Index + $match.Length
      }
      else
      {
        $index = $inputText.Length
      }
    }
    $resultsIndex += 10
  }


  foreach($domain in $domainNames)
  {
    $maxPos = -1
    foreach($key in $urls.Keys)
    {
      if($key.Contains($domain))
      { 
        $pos = [int] $urls[$key]
        if(($pos -lt $maxPos) -or ($maxPos = -1))
        {
          $maxPos = $pos
        }
      }
    }
    if($maxPos -eq -1)
    {
      $domain + " : Not Found"
    }
    else
    {
      $domain + " : Found at result #" + $maxPos
    }
  }

Drop me a line in the comments if you find it useful…

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Wednesday, June 03, 2009 11:43:37 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: PowerShell | Scripting | Web

twitter_logo Twitter is one of those applications / services that I've had trouble getting to grips with. For me it seems it's like shouting about what you are doing right now to a huge audience that is not listening. Who really cares that @kjhughes is heading to the shops to get some Mint sauce ?? Maybe I'm just not that kind of social animal, maybe I don't have enough friends using it, maybe I should 'but in' to other peoples conversations more, maybe I'm just plain boring...

I do see a use for it though (for me). It's a pretty neat way to do some remote control stuff - like set up a Media Center recording, reboot my PC, and also it's a neat way of getting updates, like new blog comment received, TV recording completed and the like....

So, right now I need to get my Outlook addin project completed, but right afterwards I'm planning an app that interfaces to twitter and accepts direct tweets as remote control instructions, and also can update me on specific events. I am also thinking about adding twitter alerts to dasBlog (on comments, posts, errors, daily reports etc)

I can see myself getting immersed in this twitter thing...

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Sunday, January 18, 2009 9:38:10 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: Development | Software | Twitter | Web

I buy a lot of stuff from online retailers and it never fails to amaze me how bad some aspect of the experience is always poor, seldom do I get a good experience end to end (purchase to delivery).

So, this is Kens 4 step plan for online retailers to raise themselves from 'one of the crowd' to 'the leader'.

google_checkout Step 1 - Get Credibility
The term 'ID fraud' is on everyone's lips right now. You have to give people the confidence to buy from you and that you are not a fly by night outfit that is going to take their money and run.
paypal_logoHow do you get credibility ? get some testimonials, use PayPal as an option for paying, use Google Checkout as an option, at least show me a valid SSL certificate and give some words around how safe it is to do business with you - most people don't care (really) about the technical aspects of payment security they just want to feel safe - Google feels safe, PayPal feels safe, a statement telling me I'm safe feels safe.

Step 2 - Have Stuff in Stock (or Tell Me If You Don't)
out_of-stockThis is important, there are a thousand other people out there selling that very same item. if you don't have it in stock then they'll just move on to the next one. Hand in hand with this is, "be up-front about the fact if you don't have it in stock". If you imply you have it in stock, someone buys and then has to wait 235 days for delivery they will most likely cancel the order (in which case you just cost yourself admin time for nothing) and you can also be sure they will not be using your services again - better to be honest and hope they come back than try to force the sale and know they'll never come back

boxesStep 3 - Don't Rip Me Off With Shipping / Delivery Charges
Ship at (or close to) cost. People do not appreciate being ripped off (and that is often all it can be called) with excessive shipping, handling and delivery charges. You want to charge me £8 for shipping and handling for a book that you send me in a small padded envelope, I'm going to get annoyed and look elsewhere. Everyone (and by that I mean everyone) has cottoned on to the retailers' great money spinner idea of making 'shipping' a profit centre. 

Step 4 - Ship It Fast
This is my personal bug bear - when I choose to buy something, I have persuaded myself I had a 'need' (or more likely a 'want') for it. I took the plunge and ordered it from you, I'm excited about my new purchase. I do not want to wait 5 - 8 business days for delivery. Actually I see no need for this every to happen (unless you are bound by the delivery service) - as a retailer / warehouse manager you are either keeping up with orders or you are getting behind, if it's the latter then you need more staff because things will just get worse (if you continue to sell stuff, which you probably hope you do); if it's the former then just get the 3 day continuous backlog cleared and you can then keep up with a continuous 0 day backlog and your customers are all happy.

Do these and you'll get my custom...

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Wednesday, September 10, 2008 6:40:40 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: Service | Web

imageToo much effort reading my ramblings ? Want to listen instead ? Now you can !!

Courtesy of the excellent odiogo, the excellent text to speech service. This is a free service that bloggers can use, it takes your RSS feed, splits it out to each separate post and then creates a MP3 for the post.

The text-to-speech quality is really good, only about 1 in 50 words is corrupt/unintelligible - easily high enough quality to get a good rendition of the post. Obviously it depends on the content of the post, I have not yet listened to a post with lots of sample code or the like, but I expect it would be pretty hard going.

Get the audio for this blog here. You can even subscribe in iTunes. I will also update the site to include the links in the sidebar.

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Monday, July 21, 2008 4:22:56 PM (GMT Daylight Time, UTC+01:00)  #   Comments [1]
TAGS: Dasblog | RSS | Technical | Tools | Web

One of the things I find really helpful in terms of motivation (for running) is having easy visibility of weekly, monthly and total mileages, times, paces etc.

nikeplus_sportband So, a couple of weeks ago I bought myself a Nike+ Sportband. This promised it all - a senor that fits in your shoe and automatically records your distance, time and speed and wirelessly transmits it to a wristband. The wristband also has a detachable USB connector / screen that you simply plug into your PC and the data is auto uploaded to the Nike+ web site.

For too long I have been using an Excel spreadsheet and manually copying it between PCs, in the past couple of months I had started getting to grips with WCF by putting together a running log application that I had planned to host on my web site (just for me) - no need for that any longer, Nike+ was going to solve all my problems and more...

How wrong I was. I cannot tell you (although that is exactly what this post is trying to do) how technically inept this product is, not just the wristband but also the web site, the whole experience in fact.

coding-horror-official-logo-small If you are familiar with the class book 'Code Complete' you will know about a 'Coding Horror' (things you really should not do when writing software), Jeff Atwood even used the term for the name of his great blog - well this isn't all software, so lets call them 'Design Horrors'.

The first 'Design Horror' comes from trying to invent a new and snazzy way to secure a piece of technology to your wrist. Watch straps have been around for hundreds of years, everyone knows how to use it right ?, the only advancement in wrist fastening / securing technology ever was to use a Velcro patch to secure the two separate lengths of strap together (typically in sports pieces, for added speed). Did this stop the Nike engineers, no way - they came up with a new paradigm in wrist strap technology. One length of strap has 10 small holes, spaced by about 2 or 3 mm, the other length has two stud like protrusions that (using one hand) you must line up with the required two holes and push into place with a force just less than that required to push your thumb through the flesh of your wrist.

'Design Horror' 2 (DH2) is similar to that of DH1, remember the detachable USB connector / screen thing I mentioned, well to secure it the USB connector pushing into a slot in the wristband and then it is secured by one of these studs pressed into a hole, however the button on the face of the screen is exactly above that stud and pushing the USB thingy down to make sure it is secured typically results in the button being forcibly pressed for a few seconds (resulting in the device trying to locate the shoe sensor), also I'm not comfortable with the amount of pressure placed upon the button this regularly (thumb through the wrist pressure)....

nikeplus_logo 'Design Horror' 3 (DH3) is the 'clock' facility of the wristband. I may be being unfair here, this could be a 'by design' issue that was never part of the requirements (which would make it a Product Requirements Horror instead). The wristband has the ability to display the current time, as well as the mileages, pace etc. Naturally you would think that Nike position it as a watch replacement for runners, however I cannot believe that is the case. how could they imagine it would replace my watch which not only has alarms, date functions, countdown timers etc with something that only shows the time, nothing else, and does so without any form of backlighting, so that trying to read it outside the core hours of 10am to 4pm result in a painful headache and a trip to the optician for thick lenses. Obviously the decision to save what couldn't be more than 10p, for a tiny surface mount device giving date/time features, in the cost of materials seemed important to them.

'Design Horror' 4 (DH4) is the orientation of the display. This is in the most difficult to read position available (regardless of how the thing is worn). The display does not read along the length/drop of your arm like most watches - no, it reads perpendicular to the length/drop of your arm. So, now, instead of just squinting at the display with no backlighting you are also skewing your arm / wrist into some crazy angle like a contortionist.

nikeplus_utility 'Design Horror' 5 (DH5) brings us to the client side software that you need on your PC to interface with the USB thingy and auto upload your run data. When you plug the USB thingy in it auto starts the 'Nike+ Utility', however it is started behind all other application windows. Further, on first using it it displays a login facility pre-populated with the username of 'Guest'. Clicking in the username textbox to try and change it results in nothing ?? Nowhere does it mention it, but I have since determined that you log into the site via a browser and then the Username is picked up for the 'Nike+ Utility' from a cookie or something...
What part of "we'll show a username that the user knows is not theirs and give them no visible means of changing it" seemed sensible at the design stage ??

'Design Horror' 6 (DH6) falls into the areas of calibration and uploading runs. You can see from the screen shot that there is a calibration tab (the sensor is basically a pedometer and it needs to be calibrated to your stride length for accuracy) - the problem is that as soon as the USB thingy is plugged in the Nike+ utility starts and uploads any outstanding runs, before you calibrate. So my very first experience with this, when I'm still in the 'happy' zone about my purchase is a run being uploaded that is the wrong distance. All the shiny graphics depict that I am considerably slower and run shorter distances than I actually do - what a deflation. of course, my first though is that I'll just edit the run and update it with the correct distance  - leading me nicely to DH7.

'Design Horror' 7 (DH7) is the fact that I cannot edit any of the runs I upload, neither can I manually upload/input runs. With all the (fun) challenges available on the site, design to further motivate people, not providing this feature is a big letdown. Just in terms of personal motivation, Nike+ shows my Total for this year as 18 odd miles, but I didn't buy it till July, being able to correct that with accurate values should be possible, unfortunately it's not. Likewise some kind of import facility for all my old runs, should be - but isn't...

'Design Horror' 8 (DH8) is the communication between the wristband and the Nike+ web site - it seems to be one way, certainly none of the totals from the web site are reflected in the wristband figures - I 'reset' my wristband the other day to recalibrate (the distances suggested by the unit were 1.05 miles in 8 out, even after calibration) and now it tells me my total is 1.93 miles (even though I calibrated it to 2 miles exactly).nikeplus_run

The final 'Design Horror' (DH9) is the accuracy of the data. The run depicted in the image was an 8 miler I did, steady pace, no walking, flat terrain and a fast finish. the data does not reflect that, it looks like I actually stopped around 2.5 miles and slowed at the end. Nice graphs are great, but if I don't trust your data then what's the point.

The whole web site is flash/shockwave based and pretty slow, it is also difficult to navigate and non intuitive.

On the flip side, it is a great idea, some of the web site features are really neat - the ability to challenge other runners, join 'virtual teams' and have team challenges - it's a pretty good social networking for runners site all in all. It only costs £40 for the kit (sensor and wristband), so it doesn't break the bank.
BUT - It could be incredible if the hardware and software are sorted out !!

My message to Nike - Just Do It

GEO 51.4043197631836:-1.28760504722595 

Share/Bookmark

Posted: Sunday, July 13, 2008 10:57:15 PM (GMT Daylight Time, UTC+01:00)  #   Comments [5]
TAGS: Hardware | Running | Technical | Web

A while back I restructured my website so that this blog no longer started at the root, instead starting from /blog. This was so that I could introduce some other web apps and have a subfolder for projects etc.

One of the pains of this restructure was modifying all the links - I thought I had caught all this with a Redirector HttpModule, but recently realised that for some reason I had not caught images embedded in the posts themselves.
Also it was becoming a pain having to remember to include the HttpModule in my web.config everytime I upgraded my blog (dasBlog)

I wanted it fixed properly this time, so grabbed a copy of all the XML files in my 'content' folder, copied them to a local folder and cracked open PowerShell...

I wanted every instance of www.mywebsite.com changed to www.mywebsite.com/blog - not difficult, but this would also change valid urls such as www.mywebsite.com/blog/page.aspx to www.mywebsite.com/blog/blog/page.aspx (note the /blog/blog in the url)

So I got everything I needed done with two 'one liners' in PowerShell...

dir | %{ $a = get-content $_ ; $a = $a -replace ("www.mywebsite.com", "www.mywebsite.com/blog") ; set-content $_ $a }

...and...

dir | %{ $a = get-content $_ ; $a = $a -replace ("www.mywebsite.com/blog/blog", "www.mywebsite.com/blog") ; set-content $_ $a }

All fixed...

 

GEO 51.4043197631836:-1.28760504722595 

Share/Bookmark

Posted: Sunday, July 06, 2008 3:35:38 PM (GMT Daylight Time, UTC+01:00)  #   Comments [1]
TAGS: Dasblog | PowerShell | Scripting | Web

I was recording some audio earlier today and the quality from my cheap, generic headset/microphone was woeful.dropio_logo-1, so I searched around for a service that I could make a telephone call into and it would record the spoken audio and give me a WAV or MP3file.

I came across http://drop.io - this is a neat little Web 2.0 service that allows sharing of files, media etc, sending stuff via email, receiving stuff via email, fax, voice etc.

One of the features was a US telephone voicemail service that recorded my spoken content and stored it in my private 'drop' as an MP3 - exactly what I was looking for.

Whilst I could have, undoubtedly, found the specific service I was looking for from a UK provider the cool features that these guys provide made me want to use them :-

  • Conference Calling number (not recorded). drop.io
  • Voicemail Number (audio is recorded and left in your 'drop' as a MP3).
  • Add content via a custom @drop.io email address.
  • Add content via fax.
  • Email alerts to any updates to your drop.
  • RSS feed for action on your drop.
  • Security model where I can invite people to view my drop, or add content etc.
  • Add notes / links to your drop.
  • Zip up the whole drop and provide a link.
  • Really nice, clean look and feel.
  • FREE !!

You can also upgrade to pro version (paid for) that provide more than the 1GB of storage or keep drops open for longer than the defaults or even shorten the url of your drop (in the free version this is http://drop.io/user_chosen_drop_name min of 7 characters) - to two letters http://drop.io.kj for example...

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Friday, June 27, 2008 4:30:24 PM (GMT Daylight Time, UTC+01:00)  #   Comments [1]
TAGS: Tools | Web

OutlookIMAPFoldersNow that I have moved us over to Google Apps For Your Domain (GAFYD) completely, I have been fighting with Outlook to get a decent user / email experience.

It just doesn't seem to flow well - I got the SMTP/IMAP send/receive stuff all set up and working correctly, but it's clunky.

I have all the folders appearing in my Outlook client but the UX just does not flow - in order to LABEL a email (in google terms) I have to move it to a folder named as the LABEL I want to apply (if I want to label it 'Outdoor' I simply move it to the 'Outdoor' folder). Equally, anything I have labelled will be visible in that folder (if I labelled it 'Outdoor' then it'll be in my 'Outdoor' folder).

There are plenty of sites with step by step guides for configuring Outlook with GoogleMail, so I wont go into that but I will share this tip:

To download full emails (not just headers) you need to do the following :-

  • Tools -> Send/Receive -> Send/Receive Settings -> Define Send/Receive Groups...
  • Select the group your IMAP account is in (typically 'All Accounts')
  • Click 'Edit'
  • Select the account if there is more than one
  • Select the option for 'Download complete items' (this is different for OL2003 and OL2007, below is OL2003)

OutlookIMAPDownload

 

However the biggest pain with Outlook is that it does not by default open in any account that does not have the usual default folders (Contacts, Calendar, Inbox etc).

As a Google IMAP account does not have these it automatically adds a 'Personal Folders' PST file and opens at the Inbox folder folder of that instead.

I am pretty much settled on letting OL grab a copy of my mail (just in case I need to edit offline), but am finding myself using Google's web mail interface most of the time.

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Wednesday, June 25, 2008 1:24:06 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: Outlook | Web

imageOriginally I had my website set up to default to my blog (so dasBlog was installed at the website root level instead of in a /blog subfolder).

Recently I have been writing some Web Applications and wanted to restructure my website so that there is a subfolder for each app / main area (blog, projects, etc).

The problem being that all the links out there point to http://www.kapie.com/2007/12/19/RedirectorHttpModule.aspx and these would all be dead link when moved to http://www.kapie.com/blog/2007/12/19/RedirectorHttpModule.aspx, so I needed to respond with a HTTP 302 to the original links and tell the client that it should temporarily redirect to the new location (changing to a HTTP 301 when I am happy that it is all working).

This called for a HttpModule...

namespace KSL
{
public class BlogRedirector : IHttpModule
{
VisualStudioLogo private EventHandler onBeginRequest;

public BlogRedirector()
{
onBeginRequest = new EventHandler(this.HandleBeginRequest);
}

void IHttpModule.Dispose()
{
}

void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += onBeginRequest;
}

private void HandleBeginRequest( object sender, EventArgs evargs )
{
HttpApplication app = sender as HttpApplication;

if ( app != null )
{
HttpContext context = app.Context;
string host = app.Request.Url.Host;
string requestUrl = app.Request.Url.PathAndQuery;

if (requestUrl.Contains(@"/blog/")
|| requestUrl.Contains(@"/foo1/")
|| requestUrl.Contains(@"/foo2/")
|| requestUrl.Contains(@"/foo3/")
|| requestUrl.Contains(@"/foo4/")
|| (requestUrl.ToLower() == app.Request.Url.Scheme + @"://" + host + @"/default.aspx"))
{
return;
}
else
{
Uri newURL = new Uri(app.Request.Url.Scheme + @"://" + host + @"/blog" + requestUrl);
context.Response.RedirectLocation = newURL.ToString();
context.Response.StatusCode = 302;
context.Response.End();
return;
}
}
}
}
}

This basically allows me to redirect any url that does not contain /blog/ or /foo*/ or is not /default.aspx by sending a 302 status code and adding /blog/ to the url to generate the redirect url. The compiled DLLs were stored in the bin folder off the root and the web.config in the root needed the following adding...

<?xml version="1.0" encoding="UTF-8"?>
<
configuration>
<
system.web>
<
httpModules>
<
add type="KSL.BlogRedirector,BlogRedirector" name="BlogRedirector" />
</
httpModules>
</
system.web>
</
configuration>

This seemed to work fine some of the time, but was a bit hit and miss.... Further investigation pointed me at the web.config files in the subfolders and that they would inherit the sections from the root web.config. So all the subfolder web.config files got the following added.

<?xml version="1.0" encoding="UTF-8"?>
<
configuration>
<
system.web>
<
httpModules>
<
remove name="BlogRedirector" />
</
httpModules>
</
system.web>
</
configuration>
GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Wednesday, December 19, 2007 7:09:38 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | ASP.NET | C Sharp | Development | Web

ruby_kaiserchiefs Sarah wanted 'Ruby Ruby Ruby' by the Kaiser Chiefs as her ringtone. Her mobile doesn't have any easy way of connecting to a PC, so she joined one of the rip-off 'Ringtones R Us' services that force you into paying £4.50 / week for as many ringtone downloads as you want (aside: I must be getting old - why would anyone want to change their ringtone that often ??).

Anyway, after downloading the mp3 she found it start relatively quietly and she was missing some calls. What she had actually wanted was the chorus....

So cue Kens Do It Yourself Ringtone Creater and Transferer... image

Step by step instructions :-

  1. Rip the song to an MP3 (from the CD which we do own - no copyright issues) 
  2. Download Audacity.
  3. Cut the chorus out of the original track (loaded MP3 file)
  4. Create a new stereo track and paste the chorus into the new track.
  5. Mute the original tracksimage
  6. Play / listen to the new track, make sure you are happy with it.
  7. Download lame_enc.dll to allow Audacity to export as MP3 (see this Audacity FAQ)
  8. Export the new track from Audacity as an MP3.
  9. FTP the MP3 file to your website
  10. Using 3G / GPRS etc on the mobile phone connect to the internet
  11. Browse to the MP3 file and download it to the mobile
  12. Set the MP3 as the ringtone.
  13. Cancel the expensive MP3 ringtone service (if applicable).
 
GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Thursday, October 11, 2007 2:29:31 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: Family | Software | Technical | Web

I spent a day this past week visiting one of our Technology Partners in New Jersey. The objective was do put together a proof concept for some integration we are planning.

We have some very cool stuff, about to be announced at one of the big shows coming up and the integration is around this new stuff. Anyway one of the things we had to do was to connect to a Web Service that returned complex types from a dynamic language.

I chose VBScript as the language because it's widely available and can be executed on virtually any windows machine. I also wanted to ensure we only used commonly available (installed) ActiveX objects. The other constraint was the Web Services only used SOAP and HTTP POSTs, no HTTP GET support.

So the work involved was to :

  1. Create an XMLHTTP object
  2. Create the SOAP Body
  3. Send it to the Web Service
  4. Parse the results

Below is how we went about it.
It is messy and pretty horrible text manipulation to generate the SOAP bodies etc, but it is the only way I found from scripting..

Let me know if you have better / easier methods...

 

Const URL = "http://www.domain.com/folder/service.asmx"
Const nsUrl = "http://www.domain.com/namespace-name"


' Create the http request text
Dim strSoapReq
strSoapReq = GenerateSoapBodyStart()
strSoapReq = strSoapReq + GenerateSoapFunctionCallStart("WebServiceFunctionName")
strSoapReq = strSoapReq + GenerateSoapParameter("paramName1", paramValue1)
strSoapReq = strSoapReq + GenerateSoapParameter("paramName2", paramValue2)
strSoapReq = strSoapReq + GenerateSoapFunctionCallEnd("WebServiceFunctionName")
strSoapReq = strSoapReq + GenerateSoapBodyEnd()

Dim oHttp
Dim strResult
Set oHttp = CreateObject("Msxml2.XMLHTTP")
oHttp.open "POST", URL, false
oHttp.setRequestHeader "Content-Type", "text/xml"
oHttp.setRequestHeader "SOAPAction", URL + "WebServiceFunctionName"
oHttp.send strSoapReq
strResult = oHttp.responseText

' parse XML in strResult




Function GetResult(byval responseText, byval resultParam)
    
    Dim oXml
    Set oXml = CreateObject("Msxml2.DOMDocument")
    oXml.Async = true
    oXml.LoadXml responseText

    Dim strPath
    strPath = "/*/*/*/" + resultParam
    Dim oNode
    Set oNode = oXml.documentElement.SelectSingleNode(strPath)
    GetResult = oNode.Text
    
End Function 


Function GenerateSoapBodyStart()
    
    Dim strSoap
    strSoap = "<?xml version=""1.0"" encoding=""utf-8""?>"
    strSoap = strSoap + "<soap12:Envelope "
    strSoap = strSoap + "xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" "
    strSoap = strSoap + "xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" "
    strSoap = strSoap + "xmlns:soap12=""http://www.w3.org/2003/05/soap-envelope""> "
    strSoap = strSoap + "<soap12:Body>"
    GenerateSoapBodyStart = strSoap
    
End Function

Function GenerateSoapBodyEnd()

    Dim strSoap
    strSoap = "</soap12:Body>"
    strSoap = strSoap + "</soap12:Envelope>"
    GenerateSoapBodyEnd = strSoap
    
End Function

Function GenerateSoapFunctionCallStart(byval strFunction)

    Dim strSoap
    strSoap = "<" + strFunction + " xmlns=""" + nsUrl + """>"
    GenerateSoapFunctionCallStart = strSoap
    
End Function

Function GenerateSoapFunctionCallEnd(byval strFunction)

    Dim strSoap
    strSoap = "</" + strFunction + ">"
    GenerateSoapFunctionCallEnd = strSoap
    
End Function

Function GenerateSoapParameter(byval strParam, byval strValue)

    Dim strSoap
    strSoap = "<" + strParam + ">"
    strSoap = strSoap + strValue
    strSoap = strSoap + "</" + strParam + ">"
    GenerateSoapParameter = strSoap
    
End Function
 
 
Fair Lawn, NJ - 40.9381556054652:-74.132137298584
 

Share/Bookmark

Posted: Wednesday, October 03, 2007 6:21:17 PM (GMT Daylight Time, UTC+01:00)  #   Comments [3]
TAGS: Scripting | Web | WS*

InsertPanel I have just completed a new Windows Live Writer plugin. This extension allows ease insertion of geo microformat information.

It allows the user to easily choose the location they want to insert (in microformat) from a Virtual Earth map and also configure how it is displayed (if at all on the post.

Recently I (with considerable help from Alexander Groß) added GeoRss support for dasBlog. The co-ordinates can be specified when adding a post via the web interface. This plugin is stage two of this support, stage three will be parsing the geo microformat when a post is added and using that to populate the GeoRss info.

The end goal being to allow the geo info to be entered when creating a post in Writer and having that info available in GeoRss format in the feed.

I started this plugin with the view to using Google Maps, however they require that you get an API key and that key is only valid for a particular web site / URL path. This foiled my plans to embed the map in a Windows Forms WebBrowser control (I did look at producing an html page that was served from my web site, and using it embedded in the WebBrowser - not scaleable and too much configuration for a normal user to do.

InsertMicroformat 

I hadn't looked in depth at Virtual Earth, but recently went to MixUK:07 and saw a couple of demos / presentations on it - a quick look found that it didn't need a API and was not tied to a particular URL / path - the JavaScript for it is pretty similar to the one for Google Maps so learning curve was pretty short. The only issue I have with http://local.live.com is that there is no (currently) facility to enter a GeoRss feed in the search query and just display the data (the current method of displaying this kind of data is to embed a map in your own pages and use their API to display the items as a 'collection').

You can get the installer for it here InsertGeoFormatSetup.msi (325Kb).

GEO 51.4043243116043:-1.28760516643523

Share/Bookmark

Posted: Saturday, September 15, 2007 11:12:11 PM (GMT Daylight Time, UTC+01:00)  #   Comments [5]
TAGS: .NET | ASP.NET | C Sharp | Dasblog | GPS | RSS | Web

Mixuk I registered for Mix:UK a few weeks ago and today got an email from the Mix team about a social networking tool they are using to help people make the most of the conference.

backnetworkThey are using backnetwork, which allows creation of profiles, blogging, photos, adding friends / colleagues etc (all the usual social networking stuff). It also allows you to add any colleagues / friends automagically from any previous backnetwork events you have been to.

 This is certainly a step in the right direction, but it's missing an 'auto-suggest relationship' feature that could analyze your profile (or tags) and suggest other people who have similar interests.

So... my profile is here, anyone interested in any of my tags feel free to contact me and set up a meeting/chat/lunch/coffee/whatever...

Share/Bookmark

Posted: Tuesday, August 28, 2007 4:51:16 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: ASP.NET | Development | mixuk07  | Web
Copyright © 2010 Ken Hughes. All rights reserved.

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.0 UK: England & Wales License.