<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A08BQH4yfip7ImA9WhBaEUs.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674</id><updated>2013-05-21T21:57:31.096+01:00</updated><category term="bugfix" /><category term="published" /><category term="Team Foundation Server" /><category term="tfs" /><category term="javascript" /><category term="bug" /><category term="compile error" /><category term="screen scraping" /><category term="ObjectDataSource" /><category term="Windows Live Writer" /><category term="analytics" /><category term="general" /><category term="validation" /><category term="c#" /><category term="MSDN" /><category term="base64" /><category term="accessibility" /><category term="favicon" /><category term="wsat" /><category term="telnet" /><category term="cross-browser" /><category term="roles" /><category term="membership" /><category term=".net" /><category term="asp.net 4.0" /><category term="Windows Service" /><category term="basics" /><category term="createuserwizard" /><category term="theory" /><category term="enum" /><category term="Windows Vista" /><category term="jQuery" /><category term="wizard" /><category term="UserControl" /><category term="EntityFramework" /><category term="HtmlAgilityPack" /><category term="SiteMap" /><category term="IIS" /><category term="blog" /><category term="AjaxControlToolkit" /><category term="Url Rewriting" /><category term="sql server" /><category term="vb" /><category term="visual studio" /><category term="Google Analytics" /><category term="DateTime" /><category term="index post" /><category term="Firefox" /><category term="blogger" /><category term="paypal" /><category term="html" /><category term="install error" /><category term="visual studio 2010" /><category term="tfs2010" /><category term="asp.net" /><category term="news sources" /><category term="article" /><category term="UrlRewriter.net" /><category term="IIS7" /><category term="runtime error" /><title>Run Tings Proper</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://runtingsproper.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>70</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/RunTingsProper" /><feedburner:info uri="runtingsproper" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;Ak8MQXo_fyp7ImA9WhJQFE0.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-4676091949382982976</id><published>2012-07-27T18:08:00.000+01:00</published><updated>2012-07-27T18:08:00.447+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-07-27T18:08:00.447+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="wsat" /><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><title>SOLVED: “An error was encountered” in WSAT (Website Admin Tool)</title><content type="html">&lt;p&gt;If you’re seeing a cryptic error when you try to add users via the built in WSAT tool that says “An error was encountered. Please return to the previous page and try again.” then this article will probably help you get to the bottom of it.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Problem&lt;/h4&gt;  &lt;p&gt;I could add roles using the WSAT without any problem but whenever I tried to add a user I would see this cryptic and unhelpful error message:&lt;/p&gt;  &lt;pre&gt;An error was encountered. Please return to the previous page and try again. 

The following message may help in diagnosing the problem: Exception has been thrown by the target of an invocation. at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct&amp;amp; sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Web.Administration.WebAdminMembershipProvider.CallWebAdminMembershipProviderHelperMethodOutParams(String methodName, Object[] parameters, Type[] paramTypes) at System.Web.Administration.WebAdminMembershipProvider.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object providerUserKey, MembershipCreateStatus&amp;amp; status) at System.Web.UI.WebControls.CreateUserWizard.AttemptCreateUser() at System.Web.UI.WebControls.CreateUserWizard.OnNextButtonClick(WizardNavigationEventArgs e) at System.Web.UI.WebControls.Wizard.OnBubbleEvent(Object source, EventArgs e) at System.Web.UI.WebControls.CreateUserWizard.OnBubbleEvent(Object source, EventArgs e) at System.Web.UI.WebControls.Wizard.WizardChildTable.OnBubbleEvent(Object source, EventArgs args) at System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) at System.Web.UI.WebControls.Button.OnCommand(CommandEventArgs e) at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)&lt;/pre&gt;

&lt;h4&gt;Solution&lt;/h4&gt;

&lt;p&gt;This one turned out to be a straightforward solution – in my haste I had forgotten to generate a machinekey element for the project.&lt;/p&gt;

&lt;p&gt;All you need to stop the error is visit one of the many online machinekey generators:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://aspnetresources.com/tools/machineKey"&gt;http://aspnetresources.com/tools/machineKey&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.developerfusion.com/tools/generatemachinekey/"&gt;http://www.developerfusion.com/tools/generatemachinekey/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then paste the generated markup key into your web.config under &amp;lt;system.web&amp;gt;.&lt;/p&gt;

&lt;p&gt;Note the links above are good for generating keys up to the latest version of asp.net 4. It may be that it doesn’t change but if you’re reading this from the distant future then its worth a quick Google to check there hasn’t been any changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.google.co.uk/search?q=machinekey+generator"&gt;https://www.google.co.uk/search?q=machinekey+generator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you have added the key to your web.config just restart the WSAT and you will be able to create users!&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/PesmHNgAkYc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/4676091949382982976/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=4676091949382982976" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/4676091949382982976?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/4676091949382982976?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/PesmHNgAkYc/solved-error-was-encountered-in-wsat.html" title="SOLVED: “An error was encountered” in WSAT (Website Admin Tool)" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2012/07/solved-error-was-encountered-in-wsat.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ECQ346eSp7ImA9WhJRF04.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8624087217328673675</id><published>2012-07-19T22:55:00.000+01:00</published><updated>2012-07-19T23:07:42.011+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-07-19T23:07:42.011+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="HtmlAgilityPack" /><category scheme="http://www.blogger.com/atom/ns#" term="screen scraping" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><title>A straightforward method to detecting RSS and Atom feeds in websites with HtmlAgilityPack</title><content type="html">&lt;p&gt;Let's create a tool that will be able to query any website and detect if they provide feeds in one of the common syndication formats. By using HtmlAgilityPack we can apply screen scraping techniques and examine the meta tags to see what alternative formats are available.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;    &lt;h4&gt;A little background&lt;/h4&gt;  &lt;p&gt;If you haven't heard about HtmlAgilityPack yet then you have landed on the wrong post. Head over to the main article index and check out the introduction post.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="http://runtingsproper.blogspot.co.uk/2009/09/htmlagilitypack-article-series.html" href="http://runtingsproper.blogspot.co.uk/2009/09/htmlagilitypack-article-series.html"&gt;HtmlAgilityPack Article Series&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Syndication feeds? RSS? Atom?&lt;/h4&gt;  &lt;p&gt;Well if you don't know what these are then you probably don't have much interest in reading an article about detecting them but for completeness I will provide a brief introduction.&lt;/p&gt;  &lt;p&gt;Its possible to make a copy of a websites news posts available in a special computer readable format. There are two main standards around; RSS and Atom. Collectively this is referred to as syndication. &lt;/p&gt;  &lt;p&gt;These data feeds are normally used in two main ways:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Collected together in special software called feed readers &lt;/li&gt;    &lt;li&gt;Republished on other websites as content &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Users can add feeds into feed readers to consume the feeds. By keeping feeds inside a feed reader users can read the latest news from their favourite websites without having to check every site for updates.&lt;/p&gt;  &lt;p&gt;For content creators it means that their content can easily be integrated into other websites. The other websites like the fresh content and the content creators like being able to generate traffic back to their websites by linking to themselves within the articles.&lt;/p&gt;  &lt;p&gt;For a much deeper discussion of this topic check out this Wikipedia article:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Web_syndication"&gt;http://en.wikipedia.org/wiki/Web_syndication&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Feed discovery&lt;/h4&gt;  &lt;p&gt;There is a standard to detect if a website provides an alternate format RSS or Atom feed. This process is called autodiscovery and has been standardised by the RSS Advisory Board and adopted by the Atom feed format.&lt;/p&gt;  &lt;p&gt;The mechanism is simply a &amp;lt;link&amp;gt; tag placed in the &amp;lt;head&amp;gt; of a webpage. The basic rules are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Set rel to &amp;quot;alternate&amp;quot; &lt;/li&gt;    &lt;li&gt;Each href must be a different feed &lt;/li&gt;    &lt;li&gt;The type must contain the feed's mime type &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can have as many feeds as you want in a page and you can mix and match feed formats.&lt;/p&gt;  &lt;p&gt;This web site uses the following tags to allow feed autodiscovery. &lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;link rel=&amp;quot;alternate&amp;quot; type=&amp;quot;application/atom+xml&amp;quot; title=&amp;quot;Run Tings Proper - Atom&amp;quot; href=&amp;quot;http://runtingsproper.blogspot.com/feeds/posts/default&amp;quot; /&amp;gt;
&amp;lt;link rel=&amp;quot;alternate&amp;quot; type=&amp;quot;application/rss+xml&amp;quot; title=&amp;quot;Run Tings Proper - RSS&amp;quot; href=&amp;quot;http://runtingsproper.blogspot.com/feeds/posts/default?alt=rss&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;You can read more about RSS autodiscovery here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.rssboard.org/rss-autodiscovery"&gt;http://www.rssboard.org/rss-autodiscovery&lt;/a&gt;&amp;#160; &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Writing the application&lt;/h4&gt;

&lt;p&gt;We are going to build this application together from scratch. I am actually writing the sample as I write the article so the steps I describe are the steps I’m taking - there won't be any Blue Peter &amp;quot;here's one I made earlier&amp;quot; style magic!&lt;/p&gt;

&lt;p&gt;The first step is to load up Microsoft Visual Studio. I am using Visual Studio 2011 Beta but I'm not planning on using any special tricks so it should be virtually identical even if you are on an older or express version.&lt;/p&gt;

&lt;p&gt;The first step is to create a new website project.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Load up Visual Studio &lt;/li&gt;

  &lt;li&gt;Click File | New | New Website &lt;/li&gt;

  &lt;li&gt;Choose an asp.net website template and the C# language. In my Visual Studio I picked .NET Framework 4, Visual C#, ASP.NET Empty Web Site. &lt;/li&gt;

  &lt;li&gt;Give your project a name. I called mine &amp;quot;HtmlAgilityPackExample-DetectSyndicationFeeds&amp;quot; but you can call it whatever you like. &lt;/li&gt;

  &lt;li&gt;Click OK to create your new website. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simple start to the tutorial! As this tutorial relies on the HtmlAgilityPack we are going to need to download it. &lt;/p&gt;

&lt;h4&gt;Download the HtmlAgilityPack – NuGet&lt;/h4&gt;

&lt;p&gt;This article was originally written back in 2009 before we had the joys of NuGet in our lives but it never got finished. Well we should all have NuGet installed now so I’ll run through this section really quickly.&lt;/p&gt;

&lt;p&gt;If you don’t have NuGet then either &lt;a href="http://www.nuget.org/" target="_blank"&gt;get it&lt;/a&gt; or follow the guide in the next section to manually install it.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Click the Website menu (or right click on the top project node in your Solution Explorer window) &lt;/li&gt;

  &lt;li&gt;Choose Manage NuGet packages… &lt;/li&gt;

  &lt;li&gt;Click the Online tab in the left hand side then All &lt;/li&gt;

  &lt;li&gt;Search for HtmlAgilityPack in the top right hand corner &lt;/li&gt;

  &lt;li&gt;Click the Install button on the HtmlAgilityPack entry in the results list that's in the centre of the window. &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Download the HtmlAgilityPack – Manual&lt;/h4&gt;

&lt;p&gt;Note: You can skip this section if you just followed the NuGet installation instructions.&lt;/p&gt;

&lt;p&gt;For our purposes we only need the binary release of the HtmlAgilityPack. Go to the site below and download the latest binary release.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://htmlagilitypack.codeplex.com/releases/"&gt;http://htmlagilitypack.codeplex.com/releases/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time of writing the latest version is 1.4.0.&lt;/p&gt;

&lt;p&gt;I recommend extracting this to a common location. Personally I keep all my 3rd party library downloads in F:\libraries\ and when I need one I can easily browse to it from any project.&lt;/p&gt;

&lt;p&gt;If you follow this method then one advantage is that the assembly will have a .refresh file automatically generated for it. This allows Visual Studio to check that it has the latest version on your hard drive before compiling the main project.&lt;/p&gt;

&lt;p&gt;In any case you should now do the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Extract the archive and make a note of the path. &lt;/li&gt;

  &lt;li&gt;Return to Visual Studio and right click on the Website menu then choose Add Reference. 
    &lt;ul&gt;
      &lt;li&gt;If there isn't a menu called Website just move your mouse over to the Solution Explorer tool window and click on any file inside your website. The Project menu will be replaced with a Website menu. &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;Click the Browse tab and navigate to the location you extracted the code to. &lt;/li&gt;

  &lt;li&gt;Select HtmlAgilityPack.dll and click OK &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Lay out the user interface&lt;/h4&gt;

&lt;p&gt;The next stage of the article is to lay out the user interface. The interface will have a TextBox to take the website address, a Button to fire it off, a GridView to display the results.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Click Website | Add New Item (or press Ctrl-Shift-A) &lt;/li&gt;

  &lt;li&gt;Select Web Form and click Add (leaving the name as Default.aspx, Place code in separate file ticked and Select master page unticked) &lt;/li&gt;

  &lt;li&gt;Either copy and paste the code below or drop a TextBox, Button and GridView onto the page until your page looks like this: &lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;%@ Page Language=&amp;quot;C#&amp;quot; AutoEventWireup=&amp;quot;true&amp;quot; CodeFile=&amp;quot;Default.aspx.cs&amp;quot; Inherits=&amp;quot;_Default&amp;quot; %&amp;gt;

&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;

&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;
&amp;lt;head runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;Html Agility Pack Example - Extract All Syndication Feeds From A Web Page&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;form id=&amp;quot;form1&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;
            Html Agility Pack Example - Extract All Syndication Feeds From A Web Page&amp;lt;/h1&amp;gt;
        &amp;lt;p&amp;gt;
            This example shows you how to use Html Agility Pack to load a remote url and parse
            out the urls of all the syndication feeds it contains.&amp;lt;/p&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;asp:Label ID=&amp;quot;Label1&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;quot;URL:&amp;quot; /&amp;gt;
            &amp;lt;asp:TextBox ID=&amp;quot;Url&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;quot;http://www.cnn.com/&amp;quot;&amp;gt;&amp;lt;/asp:TextBox&amp;gt;
            &amp;lt;asp:Button ID=&amp;quot;RetrieveButton&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;quot;Get Feeds&amp;quot;/&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;asp:GridView ID=&amp;quot;ResultsGrid&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
        &amp;lt;/asp:GridView&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;h4&gt;Making a DataObject&lt;/h4&gt;

&lt;p&gt;We are going to package up the code that does all the heavy lifting inside a class of its own. This will allow us to reuse the code on multiple pages without duplicating the code. &lt;/p&gt;

&lt;p&gt;As an added bonus we can tag this class up with DataObject attributes and then codelessly bind it to a databound control via an ObjectDataSource.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Right click on the App_Code folder 
    &lt;ul&gt;
      &lt;li&gt;If the App_Code folder isn't in your project just right click on the project node and choose Add ASP.NET folder | App_Code &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;

  &lt;li&gt;Choose Add New Item &lt;/li&gt;

  &lt;li&gt;Select Class and call the class SyndicationFeedsDataObject.cs &lt;/li&gt;

  &lt;li&gt;Add a using statement to the top: 
    &lt;br /&gt;

    &lt;pre class="brush: csharp;"&gt;using System.ComponentModel;
using HtmlAgilityPack;&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;Tag the class with a [DataObject(true)] attribute 
    &lt;br /&gt;

    &lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;
/// Summary description for SyndicationFeedsDataObject
/// &amp;lt;/summary&amp;gt;
[DataObject(true)]
public class SyndicationFeedsDataObject
{
}&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;Add a Select() method to the class that has the following signature: 
    &lt;br /&gt;

    &lt;pre class="brush: csharp;"&gt;public IEnumerable&amp;lt;SyndicationFeedsDataObject&amp;gt; Select(string WebsiteUrl)&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;The last part is to tag the Select() method with the correct attribute: 
    &lt;br /&gt;

    &lt;pre class="brush: csharp;"&gt;[DataObjectMethod(DataObjectMethodType.Select, true)]
public IEnumerable&amp;lt;SyndicationFeedsDataObject&amp;gt; Select(string WebsiteUrl)&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;At this point your complete class should look like this: &lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="brush: csharp;"&gt;using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using HtmlAgilityPack;

/// &amp;lt;summary&amp;gt;
/// Summary description for SyndicationFeedsDataObject
/// &amp;lt;/summary&amp;gt;
[DataObject(true)]
public class SyndicationFeedsDataObject
{
    public SyndicationFeedsDataObject()
    {
    }

    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public IEnumerable&amp;lt;SyndicationFeedsDataObject&amp;gt; Select(string WebsiteUrl)
    {
        throw new NotImplementedException();
    }
}&lt;/pre&gt;

&lt;h4&gt;Adding bindable public properties&lt;/h4&gt;

&lt;p&gt;We need to add some public properties to our DataObject so that we have something to bind against in our GridView. I think that we need to capture the following information about the feed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Feed Url &lt;/li&gt;

  &lt;li&gt;Title &lt;/li&gt;

  &lt;li&gt;Mime Type &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To add a property you should go to the top of the class definition and type:&lt;/p&gt;

&lt;p&gt;prop [tab] [tab]&lt;/p&gt;

&lt;p&gt;This is a shortcut in Visual Studio which lays out what is known as an Automatic Property. It looks like this by default:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;public int MyProperty { get; set; }&lt;/pre&gt;

&lt;p&gt;Your cursor is positioned at the data type so that you can then enter it (like string). Then pressing tab again will let you input the property name. Finally press enter to complete the property insert.&lt;/p&gt;

&lt;p&gt;Now you know how to do this you need to add properties until your class looks like this:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;[DataObject(true)]
public class SyndicationFeedsDataObject
{
    public string FeedUrl { get; set; }
    public string Title { get; set; }
    public string MimeType { get; set; }

    // ...
}&lt;/pre&gt;

&lt;h4&gt;Preparing the Select() statement&lt;/h4&gt;

&lt;p&gt;The Select() method we stubbed out earlier is going to be the main workhorse of this application. It will take in a website url, parse it for correctness, retrieve the html page located at that url, extract the feed urls and return that data.&lt;/p&gt;

&lt;p&gt;If an exception occurs that's going to prevent a valid collection of feeds being returned then I intend to return null. The data bound control will handle this seamlessly and execute its empty dataset code.&lt;/p&gt;

&lt;p&gt;When I want to start out a new method I usually like to put in a series of comments which describe what the method is going to do. This gives focus to the work that I am doing. This approach is discussed in detail in Steven McConnell's book Code Complete (if you buy it make sure you get the second edition).&lt;/p&gt;

&lt;p&gt;Following that technique lets us lay out the plans we just made so we can get started on the coding:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public IEnumerable&amp;lt;SyndicationFeedsDataObject&amp;gt; Select(string WebsiteUrl)
    {
        // parse the url
        // retrieve the website html
        // extract all tags
        // convert extracted tags to SyndicationFeedsDataObjects
        // return the data
    }&lt;/pre&gt;

&lt;h4&gt;Url Validation&lt;/h4&gt;

&lt;p&gt;So the first part should be pretty simple. If you pass an invalid url to Html Agility Pack it throws a UriFormatException. We don't want to force a user to remember the http:// at the start so if they forget it then we will add it in to this method. We can then check if the url is formatted correctly by trying to instantiate a new Uri() from it:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;    private static string ParseUrl(string WebsiteUrl)
    {
        if (string.IsNullOrEmpty(WebsiteUrl))
        {
            return string.Empty;
        }

        if (!Regex.IsMatch(WebsiteUrl, &amp;quot;^http://&amp;quot;, RegexOptions.IgnoreCase))
        {
            WebsiteUrl = &amp;quot;http://&amp;quot; + WebsiteUrl;
        }

        try
        {
            Uri TestUrl = new Uri(WebsiteUrl);
        }
        catch (UriFormatException)
        {
            WebsiteUrl = string.Empty;
        }

        return WebsiteUrl;
    }&lt;/pre&gt;

&lt;p&gt;This could have been done in the UI using a RegularExpressionValidator control or even a CustomValidator control but I felt that if we are going to make it idiot proof then it should be a seamless implementation rather than forcing the user to read an error message and then type the http:// themselves.&lt;/p&gt;

&lt;h4&gt;Using HtmlDocument and HtmlWeb&lt;/h4&gt;

&lt;p&gt;When we know we have a valid url we can rely on we can then make our first use of the HtmlAgilityPack so far in this tutorial. &lt;/p&gt;

&lt;p&gt;The HtmlDocument class is the main class used by HtmlAgilityPack. This is the workhorse which contains all of the nodes and attributes with a document. There are two ways to load html into this class. &lt;/p&gt;

&lt;p&gt;The first one (which was demonstrated in my &lt;a href="http://runtingsproper.blogspot.com/2009/11/easily-extracting-links-from-snippet-of.html"&gt;easily extracting links from a snippet of html&lt;/a&gt; article) is to use the HtmlDocument methods. LoadHtml() will load html in from a string. Load() will load html from a path, Stream, or TextReader.&lt;/p&gt;

&lt;p&gt;The new trick that we are going to use today is to load in remote html in with a simple command. The HtmlWeb class included with HtmlAgilityPack will take a valid url, retrieve the contents and return it as a HtmlDocument.&lt;/p&gt;

&lt;p&gt;The code looks like this:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(WebsiteUrl);&lt;/pre&gt;

&lt;p&gt;Simple!&lt;/p&gt;

&lt;h4&gt;Link tag extraction&lt;/h4&gt;

&lt;p&gt;This part of the code is where we really see the power of HtmlAgilityPack. All of the tags in the html document we just retrieved are placed inside the Document.ChildNodes property. To select them based on your requirements you can pass an XPath statement to the SelectNodes method.&lt;/p&gt;

&lt;p&gt;XPath is an &lt;a href="http://www.w3.org/TR/xpath/"&gt;official w3c standard&lt;/a&gt; designed to give you a structured query language for extracting nodes in an xml document. In this case it is being applied to the (probably) invalid html mark-up by the HtmlAgilityPack library.&lt;/p&gt;

&lt;p&gt;Take a look at the following XPath statement:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;//link[(@type='application/rss+xml' or @type='application/atom+xml') and @rel='alternate']&lt;/pre&gt;

&lt;p&gt;What it is looking for is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;all &amp;lt;link&amp;gt; tags &lt;/li&gt;

  &lt;li&gt;where the type attribute is equal to either an rss or atom feed &lt;/li&gt;

  &lt;li&gt;and the rel attribute is equal to alternate &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rel=&amp;quot;alternate&amp;quot; is important because without it you can get false positives. For example, the atom format lets you define the endpoint that you can connect to if you wanted to post an item to a blog as a &amp;lt;link&amp;gt; tag. &lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;link rel=&amp;quot;service.post&amp;quot; type=&amp;quot;application/atom+xml&amp;quot; title=&amp;quot;Example&amp;quot; href=&amp;quot;http://www.example.com/endpoint&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;The type attribute is the same as above but the rel tag is &amp;quot;service.post&amp;quot;.&lt;/p&gt;

&lt;p&gt;So to wrap this up in a convenient method we would pass in the XPath statement above to the SelectNodes() method which would return a HtmlNodeCollection containing only the tags we wanted. It would look like this:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;private static HtmlNodeCollection SelectFeeds(HtmlDocument doc)
{
    return doc.DocumentNode.SelectNodes(&amp;quot;//link[(@type='application/rss+xml' or @type='application/atom+xml') and @rel='alternate']&amp;quot;);
}&lt;/pre&gt;

&lt;h4&gt;Preparing for Data Binding&lt;/h4&gt;

&lt;p&gt;The last stage we need to do is to convert all of the data extracted so far into a format that can be data bound. The reason that we need to convert them is that the HtmlNode's inside the HtmlNodeCollection contain weakly typed attributes that look like this:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;link.Attributes[&amp;quot;href&amp;quot;].Value&lt;/pre&gt;

&lt;p&gt;So the conversion is required in order to be able to pass these in to our databound controls and access them using clean notation such as:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;Eval(&amp;quot;Href&amp;quot;);&lt;/pre&gt;

&lt;p&gt;This means using a helper method to convert the HtmlNode's into SyndicatedFeedsDataObject's. &lt;/p&gt;

&lt;p&gt;Apart from being a requirement in this case it's also a good programming practice. This is known as a code seam. By converting to our own class before we return the data we are actually fully encapsulating our use of HtmlAgilityPack. The dataobject takes a string for input (the website url) and returns a collection of itself (the feeds it found at the website url). As far as the outside world is concerned HtmlAgilityPack doesn't exist. &lt;/p&gt;

&lt;p&gt;This means that if you write an application that depends on the SyndicatedFeedsDataObject and then you find some whizzo new html parsing library you can swap it out without changing any of the calling code. For our sample application this doesn't mean much but in your full blown application you will certainly appreciate not having to change line after line of code to remove your dependency on the HtmlNode class.&lt;/p&gt;

&lt;p&gt;A simple method which uses a linq query to translate the data would look like this:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;private static IEnumerable&amp;lt;SyndicationFeedsDataObject&amp;gt; ConvertNodesToSyndicationFeeds(HtmlNodeCollection feeds)
{
    var query = from link in feeds
                select new SyndicationFeedsDataObject
                {
                    FeedUrl = link.Attributes[&amp;quot;href&amp;quot;].Value,
                    Title = link.Attributes[&amp;quot;title&amp;quot;].Value,
                    MimeType = link.Attributes[&amp;quot;type&amp;quot;].Value
                };
    return query;
}&lt;/pre&gt;

&lt;p&gt;It is written in LINQ query syntax and projects the data into the new class using object initializers. At this point I'm just pleased to be using some of the technical jargon that I've been brushing up on recently. If you don't understand the snippet above then it is far beyond the scope of this tutorial to start explaining it but I will say that I have been very happy with my recent purchase of &lt;a href="http://www.amazon.co.uk/4-0-Nutshell-Definitive-Reference-OReilly/dp/0596800959/ref=sr_1_2?ie=UTF8&amp;amp;s=books&amp;amp;qid=1273793029&amp;amp;sr=8-2"&gt;C# 4.0 in a nutshell&lt;/a&gt; (no affiliate codes embedded in there - I'm just a happy customer).&lt;/p&gt;

&lt;p&gt;Disregarding the technical jargon in the last paragraph you should be able to see that it simply assigns the values of one class to the values of another class and returns a collection of the converted classes.&lt;/p&gt;

&lt;h4&gt;Putting our Select() together&lt;/h4&gt;

&lt;p&gt;A few sections back we made a list of comments that outlined the plan for the Select(). We then spent the next few sections writing the key functionality that would be needed to turn these comments into working code.&lt;/p&gt;

&lt;p&gt;This means that we can now flesh out each of these comments into blocks of code.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;// parse the url
WebsiteUrl = ParseUrl(WebsiteUrl);

if (!IsValidUrl(WebsiteUrl))
{
    return null;
}&lt;/pre&gt;

&lt;p&gt;The IsValidUrl() is just a simple check to make sure the string isn't empty:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;private static bool IsValidUrl(string WebsiteUrl)
{
    return !string.IsNullOrWhiteSpace(WebsiteUrl);
}&lt;/pre&gt;

&lt;p&gt;I could have put this check inline but after reading Uncle Bob’s book &lt;a href="http://www.amazon.co.uk/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" target="_blank"&gt;Clean Code&lt;/a&gt; I developed a habit of showing the intention of my code by refactoring it into many small functions.&lt;/p&gt;

&lt;p&gt;Then we use two of the functions we wrote, RetrieveHtml and SelectFeeds to pull the data in, plus a quick sanity check on the data:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;// retrieve the website html
HtmlDocument doc = RetrieveHtml(WebsiteUrl);

// extract all tags
HtmlNodeCollection feeds = SelectFeeds(doc);

if (!IsValidFeedCollection(feeds))
{
    return null;
}&lt;/pre&gt;

&lt;p&gt;IsValidFeedCollection() is another one of my seemingly pointless methods which simply checks if the input is null or not. Again I could have put this inline but it allows me to express what my intention was for the if statement. It prevents me from having to drop down to a lower level of abstraction. In fact in “real” code I would probably have used var rather than HtmlDocument and HtmlNodeCollection as it would make it ready a lot more smoothly and datatypes are not important at this stage. I only included the types verbosely for the sake of introducing them in this tutorial.&lt;/p&gt;

&lt;p&gt;Here is that IsValidFeedCollection function for the curious:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;private static bool IsValidFeedCollection(HtmlNodeCollection feeds)
{
    return feeds != null;
}&lt;/pre&gt;

&lt;p&gt;Then I throw the collected feeds data through the conversion routine and return it:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;// convert extracted tags to SyndicationFeedsDataObjects
var query = ConvertNodesToSyndicationFeeds(feeds);

// return the data
return query;&lt;/pre&gt;

&lt;p&gt;We are working with IEnumerable&amp;lt;&amp;gt; collection types so this is easily understood by the data bound controls that are going to use the DataObject we just made.&lt;/p&gt;

&lt;h4&gt;How to bind our results to the GridView&lt;/h4&gt;

&lt;p&gt;Because of the DataObject attributes we applied to our code earlier on binding this to a GridView is a codeless procedure. We don’t get away with it quite that easily though because there is still an ObjectDataSource that needs to be configured. You shouldn’t see anything new here, its a simple ObjectDataSource, with a control parameter set up so that it pulls the url in the textbox into the Select() statement. There isn’t even any code in the button click event – its only there to trigger a postback and then the ObjectDataSource does the rest.&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;asp:GridView ID=&amp;quot;ResultsGrid&amp;quot; runat=&amp;quot;server&amp;quot; DataSourceID=&amp;quot;ObjectDataSource1&amp;quot;&amp;gt;
&amp;lt;/asp:GridView&amp;gt;
&amp;lt;asp:ObjectDataSource ID=&amp;quot;ObjectDataSource1&amp;quot; runat=&amp;quot;server&amp;quot; 
    OldValuesParameterFormatString=&amp;quot;original_{0}&amp;quot; SelectMethod=&amp;quot;Select&amp;quot; 
    TypeName=&amp;quot;SyndicationFeedsDataObject&amp;quot;&amp;gt;
    &amp;lt;SelectParameters&amp;gt;
        &amp;lt;asp:ControlParameter ControlID=&amp;quot;Url&amp;quot; Name=&amp;quot;WebsiteUrl&amp;quot; PropertyName=&amp;quot;Text&amp;quot; 
            Type=&amp;quot;String&amp;quot; /&amp;gt;
    &amp;lt;/SelectParameters&amp;gt;
&amp;lt;/asp:ObjectDataSource&amp;gt;&lt;/pre&gt;

&lt;p&gt;If anything went wrong in the code we simply returned null. The GridView’s default behaviour in this case is to simply hide itself. &lt;/p&gt;

&lt;p&gt;So congratulations, if you have diligently copied each of these snippets into their correct locations you will now have a working app! Press F5 to start up and lets see. If you don’t get any compile time errors then you will see something like the screenshots below. If you do get errors then don’t worry, try to fix them or just &lt;a href="#downloadthesampleapplication"&gt;jump to the download instructions&lt;/a&gt; to get the working files.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-VQrxCnhKKFU/UAiAFCyspaI/AAAAAAAAAnc/9zzFgE1Ah20/s1600-h/image%25255B5%25255D.png"&gt;&lt;img style="display: inline" title="image" alt="image" src="http://lh3.ggpht.com/-gHAyglauOG8/UAiAGLTiFnI/AAAAAAAAAnk/HB3ueRWPKtk/image_thumb%25255B3%25255D.png?imgmax=800" width="620" height="287" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;The final code &lt;/h4&gt;

&lt;p&gt;Despite the epic length of this article you might be surprised to find that the final application weighs in at only 102 lines of code and a simple aspx file to drive it. The work we put in early on meant that the rest of the asp.net ecosystem knew how to play well together. This coupled with the easy retrieval and manipulation of html that HtmlAgililtyPack provides has been a recipe for success.&lt;/p&gt;

&lt;p&gt;Another big benefit to packaging up the code in a DataObject class is that in a few months time when you want to reuse this in another project you can rip out out easily without having to untangle dependencies or spend time trying to figure out how it all fits together. It uses standard development patterns and is decoupled. This is the kind of code you could take home to meet your mother!&lt;/p&gt;

&lt;h4&gt;What can I do with this data once I have found it?&lt;/h4&gt;

&lt;p&gt;Now that you’ve learned this new technique you have to be asking yourself what can you do with it? An obvious next step is to pull the feeds in and display them. I’m not going to start a second tutorial here but I will introduce you to a man who has already swum in these waters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://dotnetslackers.com/articles/aspnet/How-to-create-a-syndication-feed-for-your-website.aspx#consuming-a-syndication-feed" target="_blank"&gt;Scott Mitchell teaches you how to consume a syndication feed&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its the tutorial I read when I first needed to display feed headlines in a site.&lt;/p&gt;

&lt;h4 id="downloadthesampleapplication"&gt;Download the sample application&lt;/h4&gt;

&lt;p&gt;I gave the listings and the explanations for everything you need to build the sample app but if you didn’t follow along at the time then you can download or fork this at GitHub:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://github.com/rtpHarry/HtmlAgilityPackExample-DetectSyndicationFeeds/zipball/master" target="_blank"&gt;Download sample app in a zip file&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="https://github.com/rtpHarry/HtmlAgilityPackExample-DetectSyndicationFeeds" target="_blank"&gt;Fork me on GitHub&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;We have covered a very large spectrum of asp.net development in this article. You should have learned a lot because we have covered:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Learned about syndication feeds &lt;/li&gt;

  &lt;li&gt;Learned about feed autodiscovery &lt;/li&gt;

  &lt;li&gt;Using HtmlAgilityPack to check a remote website for feeds &lt;/li&gt;

  &lt;li&gt;Public properties &lt;/li&gt;

  &lt;li&gt;Shortcut to creating Automatic Properties &lt;/li&gt;

  &lt;li&gt;Creating a bindable Data Object &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also hope you picked up a few good book recommendations and some programming techniques that will keep your code clean and professional.&lt;/p&gt;

&lt;h4&gt;More in this series&lt;/h4&gt;

&lt;p&gt;This article is part of a series. You can find more posts in this series here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a title="http://runtingsproper.blogspot.com/2009/09/htmlagilitypack-article-series.html" href="http://runtingsproper.blogspot.com/2009/09/htmlagilitypack-article-series.html"&gt;http://runtingsproper.blogspot.com/2009/09/htmlagilitypack-article-series.html&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/LgengKlvgh4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8624087217328673675/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8624087217328673675" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8624087217328673675?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8624087217328673675?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/LgengKlvgh4/a-straightforward-method-to-detecting.html" title="A straightforward method to detecting RSS and Atom feeds in websites with HtmlAgilityPack" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-gHAyglauOG8/UAiAGLTiFnI/AAAAAAAAAnk/HB3ueRWPKtk/s72-c/image_thumb%25255B3%25255D.png?imgmax=800" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2012/07/a-straightforward-method-to-detecting.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AHQ307fyp7ImA9WhZaEkw.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-3073786809991106816</id><published>2011-06-27T22:55:00.001+01:00</published><updated>2011-06-27T22:55:32.307+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-27T22:55:32.307+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>SOLVED: JavaScript error .reset is not a function</title><content type="html">&lt;p&gt;Read this article if you are trying to call reset() on a &amp;lt;form&amp;gt; DOM element but you're getting an error stating .reset is not a function.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;PROBLEM&lt;/h4&gt;  &lt;p&gt;I was working on some jquery UI code and I wanted to reset the form when the dialog was closed. I found a simple snippet explaining how to do this:&lt;/p&gt;  &lt;pre class="brush: js;"&gt;$(this).find(&amp;quot;form&amp;quot;)[0].reset();&lt;/pre&gt;

&lt;p&gt;If you aren’t familiar with this notation the [0] gets the underlying DOM object rather than the jQuery object – reset() is a built in JavaScript feature.&lt;/p&gt;

&lt;p&gt;Other developers seemed happy with this function, reporting that it solved their problem but in my testing all I was seeing was Firefox's error console filling up with “.reset is not a function” errors.&lt;/p&gt;

&lt;p&gt;After wrestling with this problem for a few minutes I tracked this down to a simple solution.&lt;/p&gt;

&lt;h4&gt;SOLUTION&lt;/h4&gt;

&lt;p&gt;If you are seeing this error in your code then it’s more than likely due to the fact that you have an element in your form with an id of “reset”.&amp;#160; If you do then the .reset() is masked by this element.&lt;/p&gt;

&lt;p&gt;For me the offending code was this:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;input name=&amp;quot;reset&amp;quot; type=&amp;quot;reset&amp;quot; id=&amp;quot;reset&amp;quot; value=&amp;quot;Reset&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;A simple change of the ID fixed my problem and I was on my way:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;input name=&amp;quot;resetform&amp;quot; type=&amp;quot;reset&amp;quot; id=&amp;quot;resetform&amp;quot; value=&amp;quot;Reset&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;And then I successfully used the following close handler in my jquery ui dialog:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;var dialogSettings = {
  close: function(event, ui) {
    $(this).find('form').get(0).reset();
  }                       
};&lt;/pre&gt;

&lt;p&gt;You might not be in the same situation as me though. If you want to simple grab the form then just do a normal jQuery search for the id of the form. So to reset the following form:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;form id=&amp;quot;more_information&amp;quot;&amp;gt;&lt;/pre&gt;

&lt;p&gt;You would use the either of the following code snippets, depending on personal taste:&lt;/p&gt;



&lt;pre class="brush: js;"&gt;$(&amp;quot;#more_information&amp;quot;).get(0).reset();
$(&amp;quot;#more_information&amp;quot;)[0].reset();
&lt;br /&gt;&lt;/pre&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-javascript-error-reset-is-not.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-javascript-error-reset-is-not.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-javascript-error-reset-is-not.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-javascript-error-reset-is-not.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/EjC1Ud9MSbE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/3073786809991106816/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=3073786809991106816" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/3073786809991106816?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/3073786809991106816?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/EjC1Ud9MSbE/solved-javascript-error-reset-is-not.html" title="SOLVED: JavaScript error .reset is not a function" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>5</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/06/solved-javascript-error-reset-is-not.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIMR3k7fSp7ImA9WhZUFU8.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8095880666050111541</id><published>2011-06-08T11:23:00.001+01:00</published><updated>2011-06-08T11:23:06.705+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-08T11:23:06.705+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="visual studio" /><category scheme="http://www.blogger.com/atom/ns#" term="EntityFramework" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="visual studio 2010" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: Visual Studio inserts a text snippet instead of an EntityDataSource</title><content type="html">&lt;p&gt;I had finally gotten around to following the tutorials for an introduction to Entity Framework 4 and when got to the stage that required me to insert an EntityDataSource I hit a stumbling block: The EntityDataSource was being inserted as a long text snippet instead. Read on for a simple fix to this issue.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Problem&lt;/h4&gt;  &lt;p&gt;When looking at EntityDataSource (and some Dynamic Data controls as well) they have the following text snippet icon:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-WqqZ9qyFnqU/Te9NYAUxnVI/AAAAAAAAAkg/qxCDtHllZZg/s1600-h/entityframework-error-1%25255B3%25255D.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="entityframework-error-1" border="0" alt="entityframework-error-1" src="http://lh6.ggpht.com/-KOf15YJdvik/Te9NaZm9SjI/AAAAAAAAAkk/MDlPWb-HqmI/entityframework-error-1_thumb%25255B1%25255D.jpg?imgmax=800" width="215" height="122" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;When you double click on the icon to insert it into your document you are presented with some internal &amp;lt;soap-env&amp;gt; tags and a whole lot of other meta data:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-ZPMWuGv1uIE/Te9Nd3eFlYI/AAAAAAAAAko/VsRZJeT0t0o/s1600-h/entityframework-error-2%25255B4%25255D.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="entityframework-error-2" border="0" alt="entityframework-error-2" src="http://lh3.ggpht.com/-GSu_ndn6hjA/Te9Ng4egDFI/AAAAAAAAAks/ja1ZaN7LAQk/entityframework-error-2_thumb%25255B2%25255D.jpg?imgmax=800" width="461" height="313" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Searching for the problem didn't give me any immediate solutions. I did find this Microsoft Connect issue which had a suggested fix but it had ultimately been closed as non-reproducible:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="https://connect.microsoft.com/VisualStudio/feedback/details/622189/entitydatasource-control-is-missing-from-my-visual-studio-2010-ultimate-toolbox"&gt;https://connect.microsoft.com/VisualStudio/feedback/details/622189/entitydatasource-control-is-missing-from-my-visual-studio-2010-ultimate-toolbox&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;After putting off looking into this seriously for about a month I finally gave up and reached out to the StackOverflow.com community.&lt;/p&gt;  &lt;p&gt;Its well known phenomenon that when you ask a question out loud you can sometimes answer it yourself. In this case I solved the problem about 5 minutes after posting on SO.&lt;/p&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;The solution is very straightforward. I had initially tried to re-install Visual Studio 2010 SP1 thinking it might overwrite the error. No luck. I had followed the suggested solution in the Microsoft Connect issue in the link above with no success. I had also installed the latest out of band release of Entity Framework, the 4.1 standalone installer which brought the new code-first development model but nothing worked.&lt;/p&gt;  &lt;p&gt;I was reluctant to re-install Visual Studio 2010 as it would take about an hour and a half of my time but it was starting to look like my only move.&lt;/p&gt;  &lt;p&gt;Then I hit upon a simple solution - just reset the toolbox! To do this you simply have to:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Right click on the toolbox window&lt;/li&gt;    &lt;li&gt;Choose Reset Toolbox&lt;/li&gt;    &lt;li&gt;Wait about 25 seconds while Visual Studio resets the toolbox&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;And you can now continue with your favourite Entity Framework tutorial!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-visual-studio-inserts-text.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-visual-studio-inserts-text.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-visual-studio-inserts-text.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-visual-studio-inserts-text.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/vX65zpLT-UY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8095880666050111541/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8095880666050111541" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8095880666050111541?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8095880666050111541?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/vX65zpLT-UY/solved-visual-studio-inserts-text.html" title="SOLVED: Visual Studio inserts a text snippet instead of an EntityDataSource" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-KOf15YJdvik/Te9NaZm9SjI/AAAAAAAAAkk/MDlPWb-HqmI/s72-c/entityframework-error-1_thumb%25255B1%25255D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/06/solved-visual-studio-inserts-text.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YFSXgyfSp7ImA9WhZUEU4.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-5872354132630098243</id><published>2011-06-03T22:05:00.001+01:00</published><updated>2011-06-03T22:05:18.695+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-03T22:05:18.695+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="basics" /><category scheme="http://www.blogger.com/atom/ns#" term="Firefox" /><title>SOLVED: Firebug Inspect Element Keyboard Shortcut Clash</title><content type="html">&lt;p&gt;If you want to use the Ctrl-Shift-C shortcut to Inspect Element in Firebug but you also have the Web Developer plugin installed then read on to to find out how to stop them clashing!&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;   &lt;h4&gt;     &lt;p&gt;Background&lt;/p&gt;   &lt;/h4&gt; &lt;/p&gt;  &lt;p&gt;Its been a long running thought in the back of my mind that I must be wasting time having to press F12, then click the inspect button to use the invaluable Inspect Element feature of the Firebug toolbar. I remember having a casual look in the past for a keyboard shortcut and finding none. &lt;/p&gt;  &lt;p&gt;I have always assumed that there wasn't one for it and thought it strange that it had never occurred to the developers to implement this feature.&lt;/p&gt;  &lt;p&gt;I don't know how I missed this for so long but today as the auto-updater installed the latest version I had a poke around in the release notes and still not seeing a shortcut I made a mental note to pursue this later. &lt;/p&gt;  &lt;p&gt;And lo and behold I found the elusive inspect element keyboard shortcut, pressed those holy keys that were destined to save my so much time and immediately hit by a keyboard shortcut clash between the Firebug and Web Developer plugins.&lt;/p&gt;  &lt;p&gt;I turned to Google first and found nothing reporting this. I assume that is how you have arrived here today and you are expecting the solution which is forthcoming!&lt;/p&gt;  &lt;h4&gt;Problem&lt;/h4&gt;  &lt;p&gt;The problem is that when you have Firebug by Mozilla Corporation and Web Developer by Chris Pederick installed they both hog the Ctrl-Shift-C keyboard shortcut. Web Developer wins which breaks functionality in the Firebug plugin.&lt;/p&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;Now Web Developer toolbar has some amazing features and I rely on both of these plugins daily to do my job but the View CSS one is not an important feature for me. I voted to remove the keyboard shortcut all together giving free reign to the Firebug plugin to handle the Ctrl-Shift-C combination.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Click the Options button in the Web Developer toolbar.&lt;/li&gt;    &lt;li&gt;Click Options…&lt;/li&gt;    &lt;li&gt;Click the Keys entry from the list down the left hand side&lt;/li&gt;    &lt;li&gt;Delete the letter C from the View CSS box leaving it blank &lt;/li&gt;    &lt;li&gt;Restart Firefox&lt;/li&gt;    &lt;li&gt;Press Ctrl-Shift-C and bask in the glory of your Firebug Inspect Element feature being initiated.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;You also have the option of assigning it a different keyboard shortcut in step 4. As I never use this feature I didn't think it was worth potentially creating another shortcut clash so I just disabled it. If you do ever want to use this feature you just click the CSS toolbar item and then choose View CSS…&lt;/p&gt;  &lt;h4&gt;Summary&lt;/h4&gt;  &lt;p&gt;This may be obvious to a lot of readers and but then if you read this far then perhaps not. Either way this is a simple fix to the problem and I am very much looking forward to Ctrl-Shift-C becoming a staple of my daily diet.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-firebug-inspect-element-keyboard.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-firebug-inspect-element-keyboard.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-firebug-inspect-element-keyboard.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f06%2fsolved-firebug-inspect-element-keyboard.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/5vrv5g6OEnM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/5872354132630098243/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=5872354132630098243" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/5872354132630098243?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/5872354132630098243?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/5vrv5g6OEnM/solved-firebug-inspect-element-keyboard.html" title="SOLVED: Firebug Inspect Element Keyboard Shortcut Clash" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/06/solved-firebug-inspect-element-keyboard.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QDRnk7eSp7ImA9WhZRE0k.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8828134160124810515</id><published>2011-04-09T11:36:00.001+01:00</published><updated>2011-04-09T11:36:17.701+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-09T11:36:17.701+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>Did I help? Gauge if your articles are solving real world problems with Google Analytics and jQuery</title><content type="html">&lt;p&gt;Its is easy to keep churning out articles and watch your hit count steadily increase but how do you know if you've really helped a developer solve a real world problem? In this article we explore how to create a client-side solution using Google Analytics and jQuery to track if the visitors problem has been solved.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;&lt;/h4&gt;  &lt;h4&gt;Introduction&lt;/h4&gt;  &lt;p&gt;So you have published some articles on your blog, added Google Analytics, even implemented &lt;a href="http://runtingsproper.blogspot.com/2011/04/tracking-scroll-depth-to-reveal-content.html"&gt;depth tracking&lt;/a&gt; to see if your readers are scrolling all the way down through your article but how do you know if your advice has solved the readers problem?&lt;/p&gt;  &lt;p&gt;In this article we are going to implement a simple widget style application which will ask the users a simple yes / no question: &amp;quot;Did this article solve your problem?&amp;quot;.&lt;/p&gt;  &lt;p&gt;Its UI will look like the screenshot below, but you can easily amend the code for this to suit your particular blog theme:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_-p-n_FbMReM/TaA2mzOR1bI/AAAAAAAAAkU/BbNFUP3G0_E/s1600-h/was-your-problem-solved-by-this-arti%5B1%5D.jpg"&gt;&lt;img style="display: inline" title="was-your-problem-solved-by-this-article-ui" alt="was-your-problem-solved-by-this-article-ui" src="http://lh3.ggpht.com/_-p-n_FbMReM/TaA2nyGDCyI/AAAAAAAAAkY/kfdU0uernOU/was-your-problem-solved-by-this-arti%5B2%5D.jpg?imgmax=800" width="353" height="124" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I say &amp;quot;widget style&amp;quot; because we aren't going to program against any particular widget API - in fact this feature could be implemented with the same technique on any blogging or CMS platform which runs on any language. All of the code lives on the client-side: HTML, CSS, and JavaScript.&lt;/p&gt;  &lt;p&gt;Clicking either yes or no will simply show a thank you message and invite further feedback via the existing comments form on the blog.&lt;/p&gt;  &lt;p&gt;While the comments form already allows this kind of feedback to be collected it normally involves registration / logging in and is more effort to type out than simply clicking this form. If your article hasn't solved the persons problem then you might find they are even less inclined to go through this process.&lt;/p&gt;  &lt;p&gt;Also from your point of view you cannot integrate your comments form into your Google Analytics reports. &lt;/p&gt;  &lt;p&gt;So to summarise, providing a simple Yes / No form gives an easy way to collect a valuable indicator of whether your article is actually helping anyone without:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Requiring the user to login / register &lt;/li&gt;    &lt;li&gt;Appearing to be aggressive or negative &lt;/li&gt;    &lt;li&gt;Being a target of spammers attention &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The UI itself is very simple, comprising only of html and css markup. This is so that you can implement this on your own hosted blog solution without needing extra hosting space to store image files.&lt;/p&gt;  &lt;h4&gt;Implementation Overview&lt;/h4&gt;  &lt;p&gt;The &lt;a href="http://runtingsproper.blogspot.com/search/label/analytics"&gt;other articles in this series&lt;/a&gt; have built upon a simple framework which I have continued with here. The first method, SetupGoogleAnalyticsTrackEvents, is simply a placeholder method which separates your Analytics code from the rest of your JavaScript code.&lt;/p&gt;  &lt;p&gt;If you want to integrate this into a real world website, using other Google Analytics enhancements such as &lt;a href="http://runtingsproper.blogspot.com/2011/04/tracking-scroll-depth-to-reveal-content.html"&gt;scroll depth tracking&lt;/a&gt;, &lt;a href="http://runtingsproper.blogspot.com/2011/03/how-to-automatically-track-events-with.html"&gt;pdf downloads&lt;/a&gt;, &lt;a href="http://runtingsproper.blogspot.com/2011/03/how-to-automatically-track-events-with.html"&gt;image enlargement tracking&lt;/a&gt; and other non-analytics JavaScript code then you will soon see that partitioning your methods in this way keeps things clean.&lt;/p&gt;  &lt;p&gt;The HTML mark-up simply sets up two links with some CSS styling and an extra div to say thank you. We then use jQuery to attach a click handler to each of the yes/no links and pass that response on to Google Analytics using the _trackEvent feature. The users response (problem solved / not solved) and the current url are both recorded so you can monitor which of your articles are really helping people and which are falling short.&lt;/p&gt;  &lt;h4&gt;Markup and Styling&lt;/h4&gt;  &lt;p&gt;As I have already mentioned the UI consists of a container div, a yes link, a no link and a panel which is displayed afterwards to thank the user for their feedback. I have written it like this:&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;div id=&amp;quot;WasProblemSolvedPanel&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Was your problem solved by this article?&amp;lt;/h2&amp;gt;
  &amp;lt;div id=&amp;quot;WasProblemSolvedLinkPanel&amp;quot;&amp;gt;
     &amp;lt;a id=&amp;quot;ProblemSolved&amp;quot; href=&amp;quot;#&amp;quot; class=&amp;quot;ButtonPane Yes&amp;quot;&amp;gt;Yes&amp;lt;/a&amp;gt;
     &amp;lt;a id=&amp;quot;ProblemNotSolved&amp;quot; href=&amp;quot;#&amp;quot; class=&amp;quot;ButtonPane No&amp;quot;&amp;gt;No&amp;lt;/a&amp;gt;
     &amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div style=&amp;quot;display: none;&amp;quot; id=&amp;quot;WasProblemSolvedThanksPanel&amp;quot;&amp;gt;
     &amp;lt;p&amp;gt;Thank you for clicking!&amp;lt;/p&amp;gt;
     &amp;lt;p&amp;gt;If you have additional feedback please use the &amp;lt;a href=&amp;quot;#comments&amp;quot;&amp;gt;comment form&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;p&gt;The main container div has an inline &amp;quot;display: none&amp;quot; style on it. This is because the entire feature depends on JavaScript for it to work. To make sure this isn't displayed on browsers that don't have JavaScript enabled it's hidden by default. When the jQuery code is run to set this feature up it will unhide this panel. If the user has JavaScript disabled it will stay hidden. &lt;/p&gt;

&lt;p&gt;The thanks panel is also hidden at the start, showing only the Yes / No buttons to the user. You should customise the message in the WasProblemSolvedThanksPanel panel to your own liking. The link to #comments is specific to Blogger so if you're implementing this on a different blog you might have to change this link.&lt;/p&gt;

&lt;p&gt;The styling is straightforward:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;style type='text/css'&amp;gt;
    #WasProblemSolvedLinkPanel .ButtonPane
    {
        float: left;
        display: block;
        width: 49%;
        text-align: center;
        line-height: 3em;
    }
        
    #WasProblemSolvedLinkPanel #ProblemSolved
    {
        font-size: 2em;
        margin-right: 3px;
    }
        
    #WasProblemSolvedPanel .Yes
    {
        background-color: #ccff99;
        border: 1px solid #336600;            
    }
        
    #WasProblemSolvedPanel .No
    {
        background-color: #ffcccc;
        border: 1px solid #ff0000;
    }
        
    #WasProblemSolvedLinkPanel #ProblemNotSolved
    {
        font-size: 2em;            
    }
        
    #WasProblemSolvedThanksPanel
    {
        height: 4em;
        text-align: center;
    }
&amp;lt;/style&amp;gt;&lt;/pre&gt;

&lt;p&gt;Again, as I stated at the start of this article the CSS has been kept simple and doesn't rely on any external graphics files for its UI. This means that it can be easily implemented on any hosted blogging platform without needing additional hosting. You can easily change the mark-up and styling in this section if you want to add some additional flair for your own implementation of this feature.&lt;/p&gt;

&lt;h4&gt;jQuery code&lt;/h4&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;script type='text/javascript'&amp;gt;
/* &amp;lt;![CDATA[ */
    $(document).ready(function () {
        SetupGoogleAnalyticsTrackEvents();
    });

    function SetupGoogleAnalyticsTrackEvents()
    {
        TrackEventsForWasProblemSolved();
    }

    function TrackEventsForWasProblemSolved()
    {
        $(&amp;quot;#WasProblemSolvedPanel&amp;quot;).show();

        $(&amp;quot;#ProblemSolved&amp;quot;).click(function(e){
            e.preventDefault();
            WasProblemSolvedClick(&amp;quot;Yes&amp;quot;);
        });

        $(&amp;quot;#ProblemNotSolved&amp;quot;).click(function(e){
            e.preventDefault();
            WasProblemSolvedClick(&amp;quot;No&amp;quot;);
        });
    }

    function WasProblemSolvedClick(answer)
    {
        TrackEvent(&amp;quot;Was Problem Solved?&amp;quot;, answer, document.location.href);
        $(&amp;quot;#WasProblemSolvedLinkPanel&amp;quot;).hide(&amp;quot;fast&amp;quot;);
        $(&amp;quot;#WasProblemSolvedThanksPanel&amp;quot;).addClass(answer);
        $(&amp;quot;#WasProblemSolvedThanksPanel&amp;quot;).show(&amp;quot;fast&amp;quot;);
    }

    function TrackEvent(Category, Action, Label)
    {
        _gaq.push([&amp;quot;_trackEvent&amp;quot;, Category, Action, Label]);
    }     
/* ]]&amp;gt; */
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;This code follows a simple framework so that if you want to implement all of the analytics tutorials on this blog then they will all naturally fit together inside the SetupGoogleAnalyticsTrackEvents() function. &lt;/p&gt;

&lt;p&gt;For example, my real method currently looks like this (&lt;em&gt;don't copy and paste this if you are just following this tutorial, its just to show how they all fit together&lt;/em&gt;):&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function SetupGoogleAnalyticsTrackEvents()
{
    TrackEventsForCodeSampleDownloads();
    TrackEventsForImageClicks();
    TrackEventsForMinimumPageScroll();
    TrackEventsForWasProblemSolved();
}&lt;/pre&gt;

&lt;p&gt;The first thing this code does is to find the WasProblemSolvedPanel and .show() it. This is how the feature is hidden to non-JavaScript visitors.&lt;/p&gt;

&lt;p&gt;After that we hang click() events off of each of the Yes / No links:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$(&amp;quot;#ProblemSolved&amp;quot;).click(function(e){
    e.preventDefault();
    WasProblemSolvedClick(&amp;quot;Yes&amp;quot;);
});&lt;/pre&gt;

&lt;p&gt;You will notice that rather than passing an empty function I have added the e parameter. Then in the first line I call e.preventDefault(); This is a way to stop the browser from actually trying to visit the href in the &amp;lt;a&amp;gt; tag. In this case the &amp;lt;a&amp;gt; tag simply points to a #. We don't want the browser to try to visit that because the visitor would be jumped up to the top of the page and would miss the &amp;quot;thank you&amp;quot; feedback panel.&lt;/p&gt;

&lt;p&gt;Both the Yes and No links basically perform the same task, they just pass a different value back to Google Analytics. When I had initially completed this code I went back and applied the DRY principle - Don't Repeat Yourself - and combined the duplicated code into a function called WasProblemSolvedClick(answer).&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function WasProblemSolvedClick(answer)
{
    TrackEvent(&amp;quot;Was Problem Solved?&amp;quot;, answer, document.location.href);
    $(&amp;quot;#WasProblemSolvedLinkPanel&amp;quot;).hide(&amp;quot;fast&amp;quot;);
    $(&amp;quot;#WasProblemSolvedThanksPanel&amp;quot;).addClass(answer);
    $(&amp;quot;#WasProblemSolvedThanksPanel&amp;quot;).show(&amp;quot;fast&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;This method passes the feedback to Google Analytics and then swaps out the UI to hide the button and show the thank you message.&lt;/p&gt;

&lt;h4&gt;Google Analytics Seam&lt;/h4&gt;

&lt;p&gt;One thing you should try to do when implementing third party libraries into your own code is to keep them isolated as much as possible. A particularly effective technique for this is to create a seam; a wrapper around any code that calls the library. Then when you need to use that 3rd party library throughout your code you call your own methods which you have control over.&lt;/p&gt;

&lt;p&gt;The Google Analytics tutorials on this site are all relatively simple and comprise only about 100 lines of code combined but real world apps are much larger than this. However, having said that, we have already seen the benefit of this technique pay dividends. The Google Analytics team have released new versions of their API several times now and have completely changed the way their API works more than once. &lt;/p&gt;

&lt;p&gt;This has happened since I started writing the articles on this site and when it was time to update my blog to support this new API I had to change 1 single line of code rather than picking through every line and updating it.&lt;/p&gt;

&lt;p&gt;There are other benefits to putting the extra effort in to isolate your 3rd party code with seams. If you use Test Driven Development techniques then you will already see that it would be easier to write tests against code like this. It also reduces your dependency on one specific vendor. Should the 3rd party vendor raise prices too high, go out of business or discontinue the product you are protected against your dependency on their code.&lt;/p&gt;

&lt;p&gt;Our Google Analytics seam now uses the new _gaq object instead of the pageTracker object in the previous version and looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function TrackEvent(Category, Action, Label)
{
    _gaq.push([&amp;quot;_trackEvent&amp;quot;, Category, Action, Label]);
} &lt;/pre&gt;

&lt;h4&gt;Old Google Analytics Code&lt;/h4&gt;

&lt;p&gt;The new Google Analytics code sits just before the &amp;lt;/head&amp;gt; tag and uses the _gaq object.&lt;/p&gt;

&lt;p&gt;The previous Google Analytics code sits just before the &amp;lt;/body&amp;gt; tag and uses the pageTracker object.&lt;/p&gt;

&lt;p&gt;If your Google Analytics is still using the older version and you don't have control over upgrading you can use the following TrackEvent function instead:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function TrackEvent(Category, Action, Label)
{
   pageTracker._trackEvent(Category, Action, Label);
}&lt;/pre&gt;

&lt;h4&gt;Blogger Widget&lt;/h4&gt;

&lt;p&gt;As I have mentioned throughout this article I am currently using Blogger as my platform. Setting this up in the blogger template was a bit more tricky than I expected so I'm going to cover it briefly in this section.&lt;/p&gt;

&lt;p&gt;This doesn't mean however that you have to use Blogger for this code to work. You can put this into any platform you like, the only challenge that faces you is adding into the relevant platforms article template. Despite this primarily being an asp.net blog you could even integrate this into a php powered blog.&lt;/p&gt;

&lt;p&gt;I implemented this into Blogger by going to the admin panel of my blog, clicking the Design tab, then Edit HTML. I added all of the JavaScript and CSS styles into the &amp;lt;head&amp;gt; tag and pressed save.&lt;/p&gt;

&lt;p&gt;I then clicked on the Page Elements and selected &amp;quot;Add a Gadget&amp;quot; in the main Blog Posts column of the design. I chose the type HTML/JavaScript and pasted the html mark up into the content field of this section. Leave the Title field empty and press save.&lt;/p&gt;

&lt;p&gt;The tricky part is that now your &amp;quot;Was Problem Solved&amp;quot; panel is displayed on EVERY page of the blog - the main index page, search results, tag indexes, the works. Blogger supports a special language called GML which you can use to modify the template. You can use some GML mark-up to insert a conditional that only shows the widget on article pages.&lt;/p&gt;

&lt;p&gt;Click the Design tab. Click Edit HTML menu option. Tick &amp;quot;Expand Widget Templates&amp;quot; checkbox. This will reveal all of the various GML tags that are mostly hidden from you during normal use. I cannot tell you exactly where to add this code because it will depend on your template. &lt;/p&gt;

&lt;p&gt;Basically each of your HTML/JavaScript widgets are automatically given a numbered ID such as HTML1, HTML2, HTML3 etc. You will have to scroll down the code until you spot the main blog post template code (it will have things like posted by, timestamp, comments, backlinks etc). Right after that you should find the template for your HTML/JavaScript widget. In my case my widget was the fourth one that I had added to the template so it was called HTML4. It looked like this:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;b:widget id='HTML4' locked='false' title='' type='HTML'&amp;gt;
&amp;lt;b:includable id='main'&amp;gt;
  &amp;lt;!-- only display title if it's non-empty --&amp;gt;
  &amp;lt;b:if cond='data:title != &amp;amp;quot;&amp;amp;quot;'&amp;gt;
    &amp;lt;h2 class='title'&amp;gt;&amp;lt;data:title/&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/b:if&amp;gt;
  &amp;lt;div class='widget-content'&amp;gt;
    &amp;lt;data:content/&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;b:include name='quickedit'/&amp;gt;
&amp;lt;/b:includable&amp;gt;
&amp;lt;/b:widget&amp;gt;&lt;/pre&gt;

&lt;p&gt;The trick is to check if the current page the widget is being displayed is of type &amp;quot;item&amp;quot; (a blog post). To do that you need to wrap a &amp;lt;b:if&amp;gt; &amp;lt;/b:if&amp;gt; block around the title and contents of your widget. The code should look like this:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;b:widget id='HTML4' locked='false' title='' type='HTML'&amp;gt;
&amp;lt;b:includable id='main'&amp;gt;
&amp;lt;b:if cond='data:blog.pageType == &amp;amp;quot;item&amp;amp;quot;'&amp;gt;
  &amp;lt;b:if cond='data:title != &amp;amp;quot;&amp;amp;quot;'&amp;gt;
    &amp;lt;h2 class='title'&amp;gt;&amp;lt;data:title/&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;/b:if&amp;gt;
  &amp;lt;div class='widget-content'&amp;gt;
    &amp;lt;data:content/&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;b:include name='quickedit'/&amp;gt;
&amp;lt;/b:if&amp;gt;
&amp;lt;/b:includable&amp;gt;
&amp;lt;/b:widget&amp;gt;&lt;/pre&gt;

&lt;p&gt;Click Save Template and you're all done. As a final check I would visit the blog in Firefox and then check the page to see if any JavaScript errors are being thrown at all.&lt;/p&gt;

&lt;p&gt;Your visitors can start using the feature right away but don't forget that Google Analytics is not a real-time reporting system. It will be up 24 hours before you start seeing events appear in your Google Analytics account.&lt;/p&gt;

&lt;h4&gt;Seeing Your Feedback Levels&lt;/h4&gt;

&lt;p&gt;I know that the Google Analytics team are currently working on a brand new user interface so the exact step by step process below might not work by the time you read this. If should be pretty intuitive to find the Event Tracking section but if not you can always consult Google Analytics help.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Log in to Google Analytics and click into your report so you see the dashboard&lt;/li&gt;

  &lt;li&gt;Click the Content menu option down the left hand side&lt;/li&gt;

  &lt;li&gt;Click Event Tracking&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of your custom events will be shown in here.&lt;/p&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;In this article we have looked at a lightweight solution to asking your readers if a particular article has helped them solve their problem. It is a low-friction interface that does not require the user to type anything out or log-in to use it. The user is invited to use the comments form if they want to provide additional feedback.&lt;/p&gt;

&lt;p&gt;The entire feature is implemented client-side in HTML, JavaScript and CSS which means that it is platform agnostic. You could easily implement this in any blogging platform, help desk software, product description pages, faq's, in fact any page that you would like your visitors to easily indicate a yes / no response.&lt;/p&gt;

&lt;p&gt;This may have been the first time you have seen the technique of passing a parameter to the click handler in jQuery and using it to prevent the href being visited after the handler code has run.&lt;/p&gt;

&lt;p&gt;We have also looked at the technique of using seams in your code to protect you from changes to third party libraries and shown how easy it is to change the seam to support both new and older Google Analytics tracking codes.&lt;/p&gt;

&lt;p&gt;This article has added another technique to your arsenal of ways to use the event tracking mechanism of the Google Analytics API. If this is your first Google Analytics article on this site then check out the Further Reading section below to see more Google Analytics API tutorials.&lt;/p&gt;

&lt;h4&gt;Further Reading &lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://runtingsproper.blogspot.com/2011/03/how-to-automatically-track-events-with.html"&gt;How to automatically track events with Google Analytics async snippet and jQuery&lt;/a&gt;&lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;&lt;a href="http://runtingsproper.blogspot.com/2011/04/tracking-scroll-depth-to-reveal-content.html"&gt;Tracking scroll depth to reveal content engagement in Google Analytics async snippet&lt;/a&gt;&lt;/div&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;div align="left"&gt;&lt;a href="http://runtingsproper.blogspot.com/search/label/Google%20Analytics"&gt;All Google Analytics articles&lt;/a&gt;&lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fdid-i-help-gauge-if-your-articles-are.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fdid-i-help-gauge-if-your-articles-are.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fdid-i-help-gauge-if-your-articles-are.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fdid-i-help-gauge-if-your-articles-are.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/F9QSJyWqWPc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8828134160124810515/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8828134160124810515" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8828134160124810515?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8828134160124810515?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/F9QSJyWqWPc/did-i-help-gauge-if-your-articles-are.html" title="Did I help? Gauge if your articles are solving real world problems with Google Analytics and jQuery" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_-p-n_FbMReM/TaA2nyGDCyI/AAAAAAAAAkY/kfdU0uernOU/s72-c/was-your-problem-solved-by-this-arti%5B2%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/04/did-i-help-gauge-if-your-articles-are.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcEQHYzcSp7ImA9WhZREEs.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-7625219751007095911</id><published>2011-04-06T06:00:00.000+01:00</published><updated>2011-04-06T06:00:01.889+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-06T06:00:01.889+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>Tracking scroll depth to reveal content engagement in Google Analytics async snippet</title><content type="html">&lt;p&gt;This article investigates a way to track content engagement on your site. By monitoring how far down the page a visitor to your site travels and then recording the data in Google Analytics you can discover how many of your visitors are reading your content all the way to the end.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Updated article - async snippet version&lt;/h4&gt;  &lt;p&gt;This article was re-written for what is currently the latest tracking code style, known as the async snippet. If your code looks like the snippet below then this article is for you. If you're still using the old pageTracker code and you're not in a position to upgrade at the moment then you can read the &lt;a href="http://runtingsproper.blogspot.com/2010/03/google-analytics-tracking-content.html"&gt;old version of this article here&lt;/a&gt;.&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXX-X']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Don't forget that this snippet now goes right before the &amp;lt;/head&amp;gt; tag instead of the &amp;lt;/body&amp;gt; tag that it used to go in.&lt;/p&gt;

&lt;p&gt;I'm going to leave the rest of this article as is, except for tweaking the facts. Its good to see that this article actually only needed one line changing in its code to support the new format. You will read about how I refactored the jQuery code to keep the Google Analytics separate in a related article: &amp;quot;&lt;a href="http://runtingsproper.blogspot.com/2011/03/how-to-automatically-track-events-with.html"&gt;How to automatically track events with Google Analytics async snippet and jQuery&lt;/a&gt;&amp;quot;.&lt;/p&gt;

&lt;h4&gt;&amp;#160;&lt;/h4&gt;

&lt;h4&gt;Introduction&lt;/h4&gt;

&lt;p&gt;When browsing through your Google Analytics reports you will find a massive selection of data at your fingertips. You can find how many people visited a page, how long they were there, what country they were from, if it was their first visit, if they bought something from your site and so much more. If you're reading an article like this then I doubt that I need to sell you on what a great piece of kit it is. &lt;/p&gt;

&lt;p&gt;Part of what makes Google Analytics a great package is that it provides a JavaScript API which lets you mould the functionality to your requirements. &lt;/p&gt;

&lt;p&gt;It occurred to me that I would be interested to know if visitors to my site were reading all of my articles or if they were just bouncing in &amp;amp; out registering page views for content that didn't fit their needs.&lt;/p&gt;

&lt;p&gt;I decided that a good metric to decide if the visitor has read my content is that they scroll past 90% of the total height of the page. When this scroll depth is detected I will use _trackEvent to record the information in Google Analytics.&lt;/p&gt;

&lt;h4&gt;What is Event Tracking?&lt;/h4&gt;

&lt;p&gt;Event tracking is an alternative way of tracking user activity on your site. The normal way is by registering page views. Not every activity on your website results in a fresh page view though. &lt;/p&gt;

&lt;p&gt;What if the user downloads a PDF, watches a video or scrolls to 90%? This is where the event tracking comes in. It allows you to register an event, put it in a category and even associate a monetary value with it.&lt;/p&gt;

&lt;p&gt;Another approach that you might see to tracking these kinds of events is to use virtual page views. This is where you track a page view but provide Google with a non-existent url so that you can identify the event. &lt;/p&gt;

&lt;p&gt;While this technique will let you track your on page activities it also clutters up your visitor statistics and is no longer a recommended approach. If you find an article suggesting this kind of technique then check how old it is and consider using event tracking instead.&lt;/p&gt;

&lt;h4&gt;_trackEvent&lt;/h4&gt;

&lt;p&gt;The way to track an event within Google Analytics is to call the _trackEvent() method on the _gaq object. &lt;/p&gt;

&lt;p&gt;The _gaq object is part of the tracking code snippet that you will have pasted into your site (if you haven't setup a Google Analytics account yet then you should review this screencast which explains &lt;a href="http://services.google.com/analytics/breeze/en/installing_ga_code/index.html"&gt;how to install your tracking code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The method takes several parameters - category, action, label and value. &lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;category&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The category is a general category (in my code I have used &amp;quot;Sample Application&amp;quot; and &amp;quot;Image Enlargement&amp;quot; as my categories).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;action&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The action is a specific action for the event (such as &amp;quot;Download&amp;quot;, &amp;quot;Click&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Vote&amp;quot;, etc).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;label&lt;/td&gt;

      &lt;td valign="top"&gt;string (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;If you want to record something specific like the filename of the video being played then you can put this in the label parameter.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;value&lt;/td&gt;

      &lt;td valign="top"&gt;integer (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;This last type is if you want to assign a specific value to the event such as somebody you can make £5 in advertising each time somebody watches one of your videos.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;A simple page tracker event might look like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;_gaq.push(['_trackEvent', &amp;quot;Videos&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Cat falls off table.avi&amp;quot;, 5]);&lt;/pre&gt;

&lt;p&gt;This would assign a value of 5 dollars (or whichever currency your analytics is configured to work with) and attribute it to a play of a video called &amp;quot;Cat falls off table.avi&amp;quot;.&lt;/p&gt;

&lt;h4&gt;Planning your events&lt;/h4&gt;

&lt;p&gt;I just want to pass on a bit of advice that I picked up while learning in the Conversion University. You should create a planning document which outlines the general structure of what events you intend to capture. Using a straightforward naming convention and make sure you stick to it. Otherwise you will find it unmanageable when it comes to trying to make sense of the data collected. If you are a web developer on a team then it would be a good idea to consult with the person who will be using this data before you implement your event tracking.&lt;/p&gt;

&lt;h4&gt;Taking the first swing&lt;/h4&gt;

&lt;p&gt;To start off with we simply want to be sure that the page scroll tracking is actually working. We are going to use jQuery to track the page scrolling. If you haven't every used jQuery before then you would benefit from reading some introductory tutorials but for the sake of this article please just take my word that the .ready() allows you to run a piece of code when the page has finished loading and window.scroll() allows you to run a piece of code each time a scroll is detected.&lt;/p&gt;

&lt;p&gt;Here is the first draft:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;    &amp;lt;script src='http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt; 
    &amp;lt;script type='text/javascript'&amp;gt;
    /* &amp;lt;![CDATA[ */
        $(document).ready(function () {
            SetupGoogleAnalyticsTrackEvents();
        });

        function SetupGoogleAnalyticsTrackEvents()
        {
            TrackEventsForMinimumPageScroll();
        }

        function TrackEventsForMinimumPageScroll()
        {
           $(window).scroll(function(){
             var bottom = $(window).height() + $(window).scrollTop();
             var height = $(document).height();
             var percentage = Math.round(100*bottom/height);
           
             if(percentage &amp;gt; 90)
             {
                 alert(&amp;quot;Page Scrolled to 90% in &amp;quot; + document.location.href);
             }
           }); 
        }
    /* ]]&amp;gt; */
    &amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;You might wonder why I have used some seemingly redundant function names in this sample. This is simply to make sure the code we are writing fits in with the layout of code using in other Google Analytics integration articles on this site. To read them you can click the Google Analytics tag at the end of this article.&lt;/p&gt;

&lt;p&gt;So from reading through the code you will see that the following occurs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Some code is attached to the scroll event of the page &lt;/li&gt;

  &lt;li&gt;Each time the page is scrolled the percentage variable is updated to calculate how for down the page in total the user has scrolled. &lt;/li&gt;

  &lt;li&gt;This is calculated by comparing how far down the user has scrolled against the height of the page. &lt;/li&gt;

  &lt;li&gt;The page then checks if the scrolled percentage has exceeded a certain threshold (90% in this case) and alerts the user. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it out. Copy the code into a page and fill it with some bogus text. An easy way to get your hands on filler text is to use lorem ipsum. Just visit this site and generate a few paragraphs of text, enough to give you a scrollbar to test with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.lipsum.com/"&gt;http://www.lipsum.com/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to put the html / JavaScript snippet above into the &amp;lt;head&amp;gt; tag in your sample page.&lt;/p&gt;

&lt;p&gt;Back? Did it work? Great! So now we have a mechanism to detect when the user has scrolled to a certain threshold percentage. &lt;/p&gt;

&lt;h4&gt;Duplicate events&lt;/h4&gt;

&lt;p&gt;Did you notice any problems while playing with your new toy? It seems that after you continue scrolling down the page past 90% that the page keeps notifying you, again and again. If we were tracking this by sending and Event Tracking message to Google Analytics every time then our statistics wouldn't be very accurate at all!&lt;/p&gt;

&lt;p&gt;The solution is pretty straightforward. We need a simple Boolean variable which is set to 0 when the page loads but after the first time the threshold met event fires the Boolean is change to 1 and any subsequent events are ignored.&lt;/p&gt;

&lt;p&gt;The code would look something like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;var IsDuplicateEvent = 0;

function ScrollingEvent()
{
   if(ScrollThreshold &amp;gt; 90%)
   {
      if(IsDuplicateEvent == 0)
      {
         IsDuplicateEvent = 1;
         TrackEventInGoogleAnalytics();
      }
   }
}&lt;/pre&gt;

&lt;p&gt;This code wont compile because it's not much more than pseudo code but hopefully it does illustrate the idea. &lt;/p&gt;

&lt;p&gt;While writing this code I originally had the IsDuplicateEvent = 1; line at the end of the method. I figured that if the Event Tracking portion caused a problem then I didn't want to count it as a tracked event. When testing this code (by scrolling down the page really fast) I still managed to get duplicate alert boxes. Moving this variable to the start of the function stopped the duplicate events.&lt;/p&gt;

&lt;h4&gt;FINAL CODE - Tracking the event and wrapping up&lt;/h4&gt;

&lt;p&gt;At this point we can take our original code sample, fold the duplicate event blocker in and replace the alert() with a genuine call to the Google Analytics API. We would end up with some code that looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;    &amp;lt;script src='http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt; 
    &amp;lt;script type='text/javascript'&amp;gt;
    /* &amp;lt;![CDATA[ */
        var IsDuplicateScrollEvent = 0;

        $(document).ready(function () {
            SetupGoogleAnalyticsTrackEvents();
        });

        function SetupGoogleAnalyticsTrackEvents()
        {
            TrackEventsForMinimumPageScroll();
        }

        function TrackEventsForMinimumPageScroll()
        {
           $(window).scroll(function(){
             var scrollPercent = GetScrollPercent();
           
             if(scrollPercent &amp;gt; 90)
             {
               if(IsDuplicateScrollEvent == 0)
               { 
                 IsDuplicateScrollEvent = 1;
//                 alert(&amp;quot;Page Scrolled to 90% in &amp;quot; + document.location.href);
                 TrackEvent(&amp;quot;Content Engagement&amp;quot;, &amp;quot;Scrolled To 90%&amp;quot;, document.location.href);
               }
             }
           }); 
        }

        function GetScrollPercent()
        {
             var bottom = $(window).height() + $(window).scrollTop();
             var height = $(document).height();

             return Math.round(100*bottom/height);
        }
                                
        function TrackEvent(Category, Action, Label)
        {
           _gaq(['_trackEvent', Category, Action, Label]);
        }     
    /* ]]&amp;gt; */
    &amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;As you can see I have refactored the scroll percentage out into its own method just to make the code a bit cleaner to read. &lt;/p&gt;

&lt;p&gt;I have also left the alert() code in there but just commented it out. This is because it can take up to 24 hours to see tracked events actually appear in Google Analytics so it's handy to use it for one final check as you put the code into your site.&lt;/p&gt;

&lt;h4&gt;Further reading&lt;/h4&gt;

&lt;p&gt;For further reading on Google Analytics integration techniques you can browse the Google Analytics tag on this site:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://runtingsproper.blogspot.com/search/label/Google%20Analytics"&gt;http://runtingsproper.blogspot.com/search/label/Google%20Analytics&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official documentation page for event tracking is available at here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://code.google.com/apis/analytics/docs/tracking/eventTrackerOverview.html"&gt;http://code.google.com/apis/analytics/docs/tracking/eventTrackerOverview.html&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/d3f539Pq0uc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/7625219751007095911/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=7625219751007095911" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7625219751007095911?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7625219751007095911?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/d3f539Pq0uc/tracking-scroll-depth-to-reveal-content.html" title="Tracking scroll depth to reveal content engagement in Google Analytics async snippet" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/04/tracking-scroll-depth-to-reveal-content.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQFSX0yeSp7ImA9WhZREU8.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8659185989188550099</id><published>2011-04-05T22:36:00.001+01:00</published><updated>2011-04-06T23:18:38.391+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-06T23:18:38.391+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="theory" /><category scheme="http://www.blogger.com/atom/ns#" term="cross-browser" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="html" /><title>My Website Design Doesn't Look The Same In All Browsers!</title><content type="html">&lt;p&gt;“I created a website but now when I look at it in different browsers there are display glitches! What can I do?”&lt;/p&gt;  &lt;p&gt;This is a common issue that developers face. Web browsers have a long history of having their own interpretations of standards compliance and they also have different defaults such as font sizes and margins. If you find that your website is not looking the same in all of the major browsers then this guide will help you figure which steps you need to take to fix it.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Valid Doctype&lt;/h4&gt;  &lt;p&gt;Before you start you need to make sure that your HTML template has a valid doctype. The doctype tells the browser which set of rules it should be following internally. It’s really easy to set up a doctype:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.alistapart.com/articles/doctype/"&gt;http://www.alistapart.com/articles/doctype/&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;W3C Validation&lt;/h4&gt;  &lt;p&gt;The W3C are the standards body that make the official guidelines for web page technologies such as HTML and CSS. To have a fighting chance at getting your site to look the same in all browsers you should make sure that your pages have valid HTML and CSS. Run them through these two validators and fix any errors that come up:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://validator.w3.org/"&gt;http://validator.w3.org/&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://jigsaw.w3.org/css-validator/"&gt;http://jigsaw.w3.org/css-validator/&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;CSS Reset&lt;/h4&gt;  &lt;p&gt;Now that we have a technically valid design it’s time to level the playing field between each of the browsers defaults. Even a normal page will have different defaults for margins, font sizes, link borders and such. A CSS reset stylesheet explicitly sets rules for all of the tags rather than relying on the defaults set in the browser. You can use any CSS reset stylesheet; there are several out there in the wild, but if you don’t have a preference I would suggest using Yahoo CSS Reset 3. This is because it’s made by a large corporation, has quality and is up to date with modern browser inconsistencies:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://developer.yahoo.com/yui/3/cssreset/"&gt;http://developer.yahoo.com/yui/3/cssreset/&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;When you first apply the CSS reset stylesheet you might find that your design breaks slightly in the browsers that were looking ok before. This is because you built the rules based on their defaults and now that they have been reset you are finding that your rules aren’t quite right. Don’t give up on the CSS reset stylesheet though, it is worth the time to fix these issues and then go back to working on fixing your original problems.&lt;/p&gt;  &lt;h4&gt;Don’t Use Hacks&lt;/h4&gt;  &lt;p&gt;There are a lot of tricks that you can use to achieve different effects in different browsers. I’m not talking about rounded corners or other css3 techniques that aren’t supported yet in a standards compliant way, I’m talking about using intentionally invalid mark-up to confuse certain browsers into applying different rules than others. &lt;/p&gt;  &lt;p&gt;If you’re working on a commercial website then this is an irresponsible way to develop a site and will almost guarantee problems for your client in the future. You can’t be sure that these tricks will work in future browsers and there is always a better solution to solve your problems without relying on these hacks. Using hacks will result in unhappy clients and extra work down the line.&lt;/p&gt;  &lt;h4&gt;Conditional Comments&lt;/h4&gt;  &lt;p&gt;Let’s face it, if you're reading this article then in all likelihood you have a website that looks very similar in most browsers such as Firefox, Safari, Opera, etc. and wrong in Internet Explorer. If you built the site for Internet Explorer then you might have the site looking great in IE and poor in all the others. Either way there are times when you actually do need to treat Internet Explorer as a special case. Conditional comments allow you to target various versions of Internet Explorer with their own CSS rules and the idea is implemented in a way that doesn’t affect other standards compliant browsers.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.google.co.uk/search?q=conditional+comments"&gt;http://www.google.co.uk/search?q=conditional+comments&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;DOM Inspection Addons&lt;/h4&gt;  &lt;p&gt;If you’ve made it this far down the document then you are getting down to the nitty gritty technical details of browser inconsistencies. An indispensible tool to have in your arsenal at this point is a DOM inspection toolbar. For Firefox it has to be the industry standard Firebug. Microsoft have released their own tool called Web Developers Toolbar and this is actually bundled with the recently release IE9. Safari and Chrome both include a DOM inspector out of the box called Web Inspector and Chrome Inspector respectively.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://getfirebug.com/"&gt;http://getfirebug.com/&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=95e06cbe-4940-4218-b75d-b8856fced535&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=95e06cbe-4940-4218-b75d-b8856fced535&amp;amp;displaylang=en&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;These tools all have the same purpose. You can fire them up and then click on any element of your design to inspect the underlying HTML mark-up and CSS rules being applied to that mark-up. The majority of these tools let you prototype possible design fixes by letting you change any CSS rule or add new ones on the fly. Trying to figure out how wide that div can be before it pops your delicate floats and ruins the design? Test out if a well-placed clear: both; will fix your design? Change font sizes and colours to perfect the design? This is all made easy with a valuable tool such as this.&lt;/p&gt;  &lt;h4&gt;Testing Older Versions&lt;/h4&gt;  &lt;p&gt;Hopefully by this point you will have tuned your website up using the techniques above and your site is looking great in all of the modern browsers. Unfortunately we don’t live in a world where all of our users are running the latest versions of their web browser of choice. Unfortunately we don’t even live in a world where a developer can have more than one version of a browser installed side by side.&lt;/p&gt;  &lt;p&gt;The most common issue is testing your site in IE6. You cannot have both installed officially. There is a way to hack the browser and force it to install two versions of IE but this has its own issues and if you aren’t testing against a genuine install it is largely pointless. &lt;/p&gt;  &lt;p&gt;Microsoft acknowledge this issue and they release Virtual PC images every few months. They have copies of Windows XP &amp;amp; IE6, amongst other configurations, pre-installed on them. The latest version at the time of writing is available for download below. Unfortunately they don’t seem to have a standard hub page so you might have to search for the latest version if you are reading this article sometime in the future.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef&amp;amp;displaylang=en&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Cross Browser Testing Tools&lt;/h4&gt;  &lt;p&gt;There are two services out there by the big players Microsoft and Adobe which will let you generate screenshots of browsers and test against them:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://expression.microsoft.com/en-us/cc136529.aspx"&gt;http://expression.microsoft.com/en-us/cc136529.aspx&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="https://browserlab.adobe.com/en-us/"&gt;https://browserlab.adobe.com/en-us/&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;There are also some other services which offer these kinds of features. Smashing Magazine has a good round up of them here:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.smashingmagazine.com/2010/06/04/cross-browser-testing-a-detailed-review-of-tools-and-services/"&gt;http://www.smashingmagazine.com/2010/06/04/cross-browser-testing-a-detailed-review-of-tools-and-services/&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Check Your Analytics&lt;/h4&gt;  &lt;p&gt;This one is a bit of a cop out but it’s worth mentioning. If you are having problems with a fringe browser then you should check your analytics to see if your visitors actually use this browser. &lt;/p&gt;  &lt;p&gt;It doesn’t make commercial sense to work on a problem for hours on end if its only occurring in IE5.5 and it accounts for 5 visitors a month. &lt;/p&gt;  &lt;p&gt;Similarly depending on your audience you might find that you have a particularly tech savvy user base. Readers of this blog for example are obviously technical people and have made sensible choices with their primary browsers…. Right?&lt;/p&gt;  &lt;h4&gt;Ask In Forums&lt;/h4&gt;  &lt;p&gt;If you have put in the work and really tried to solve the problem yourself then it’s now reasonable to post your problem on a website and ask the world to help you out. &lt;/p&gt;  &lt;p&gt;A few popular forums for this kind of thing are below but if you dig a little you will find many communities that are willing to review your site. &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://doctype.com/"&gt;http://doctype.com/&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://stackoverflow.com/"&gt;http://stackoverflow.com/&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://forums.asp.net/"&gt;http://forums.asp.net/&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;When posting on sites like this you should remember to tackle one specific issue at a time. Explain that you have already made a valiant effort of your own to solve the problem. Mention what you have already tried, perhaps even link to this article and say you have tried these techniques.&lt;/p&gt;  &lt;h4&gt;Conclusion&lt;/h4&gt;  &lt;p&gt;Creating a design can take additional work to get things looking the way that you want them in all browsers. This may mean taking extra consideration with your design next time to only include features that are available in all browsers. &lt;/p&gt;  &lt;p&gt;Create web designs that suit the medium. This isn't desktop publishing and we don't have you have full per-pixel positioning. The web is more of a flow design tool. Trying to design sites that work against the intentions of HTML and CSS will leave your designs brittle and inconsistent.&lt;/p&gt;  &lt;p&gt;The best technique that I have found is to develop in Firefox, using clean coding techniques, testing semi-regularly in your installed copy of Internet Explorer and then at major milestones check your design is working in Internet Explorer 6.&lt;/p&gt;  &lt;p&gt;Following the tips and techniques in this guide should help reduce your problems with future website development.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fmy-website-design-doesn-look-same-in.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fmy-website-design-doesn-look-same-in.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fmy-website-design-doesn-look-same-in.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f04%2fmy-website-design-doesn-look-same-in.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/8t6vQgr3Fx0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8659185989188550099/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8659185989188550099" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8659185989188550099?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8659185989188550099?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/8t6vQgr3Fx0/my-website-design-doesn-look-same-in.html" title="My Website Design Doesn&amp;#39;t Look The Same In All Browsers!" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>6</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/04/my-website-design-doesn-look-same-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8DRH86eSp7ImA9WhZSEkk.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-1636969317600404767</id><published>2011-03-17T22:39:00.001Z</published><updated>2011-03-27T18:27:55.111+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-27T18:27:55.111+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>How to automatically track events with Google Analytics async snippet and jQuery</title><content type="html">&lt;p&gt;This article examines a way to use a feature of Google Analytics called Event Tracking. By using jQuery and the Google Analytics JavaScript API we will automatically track events on your site not seen by a standard analytics installation.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Updated article - async snippet version&lt;/h4&gt;  &lt;p&gt;This article was re-written for what is currently the latest tracking code style, known as the async snippet. If your code looks like the snippet below then this article is for you. If you're still using the old pageTracker code and you're not in a position to upgrade at the moment then you can read the &lt;a href="http://runtingsproper.blogspot.com/2009/12/how-to-automatically-track-events-with.html"&gt;old version of this article here&lt;/a&gt;.&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXX-X']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Don't forget that this snippet now goes right before the &amp;lt;/head&amp;gt; tag instead of the &amp;lt;/body&amp;gt; tag that it used to go in.&lt;/p&gt;

&lt;p&gt;I'm going to leave the rest of this article as is, except for tweaking the facts. Its good to see that this article actually only needed one line changing in its code to support the new format. You will read about how I refactored the jQuery code to keep the Google Analytics separate later in Refactoring section of this article.&lt;/p&gt;

&lt;h4&gt;Introduction&lt;/h4&gt;

&lt;p&gt;I have invested some time over the past week in getting to know Google Analytics a lot better. After working through the &amp;quot;in-depth analysis&amp;quot; section over on Google Analytics training ground (called &lt;a href="http://www.conversionuniversity.com/"&gt;Conversion University&lt;/a&gt;) I decided to implement events to track some items that are not tracked by the basic out-of-the-box Analytics implementation. &lt;/p&gt;

&lt;p&gt;When I woke up this morning I barely knew anything about jQuery having only used it once or twice before (each time with just enough of a gap for me to forget all the details when it came to using it again). Because writing the jQuery code was as much of a journey for me as the GA event tracking was, I will also cover a couple of tricks I learned along the way.&lt;/p&gt;

&lt;p&gt;Just in case it hasn't occurred to you - GA is an abbreviation for Google Analytics.&lt;/p&gt;

&lt;h4&gt;What does the Event Tracking do that normal Analytics doesn't?&lt;/h4&gt;

&lt;p&gt;A good place to start this off is to justify what this piece of technology does and why we would want to use it. By tracking an event we can record visitor activities that don't equate to a page visit but are still valuable to us. For example, you might want to know stats on your PDF downloads or other downloadable assets.&lt;/p&gt;

&lt;p&gt;A more advanced use would be to track a video player such as those embedded in the YouTube site. You could easily think of some usage patterns that you might want to track such as when the user presses play on the video. You could also track abandonment and make a new event if they watch over 90% of the video. Another example would be clicking on one of the recommended video links that are displayed after the main video has completed playing.&lt;/p&gt;

&lt;p&gt;It is worth remembering that a maximum of 500 events can be tracked per user per visit so you shouldn't try to track events that happen very frequently.&lt;/p&gt;

&lt;p&gt;You should now see that this is a potentially valuable feature to master.&lt;/p&gt;

&lt;h4&gt;_trackEvent&lt;/h4&gt;

&lt;p&gt;The way to track an event within Google Analytics is to call the _trackEvent() method on the _gaq object. &lt;/p&gt;

&lt;p&gt;The _gaq object is part of the tracking code snippet that you will have pasted into your site (if you haven't setup a Google Analytics account yet then you should review this screencast which explains &lt;a href="http://services.google.com/analytics/breeze/en/installing_ga_code/index.html"&gt;how to install your tracking code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The method takes several parameters - category, action, label and value. &lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;category&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The category is a general category (in my code I have used &amp;quot;Sample Application&amp;quot; and &amp;quot;Image Enlargement&amp;quot; as my categories).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;action&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The action is a specific action for the event (such as &amp;quot;Download&amp;quot;, &amp;quot;Click&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Vote&amp;quot;, etc).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;label&lt;/td&gt;

      &lt;td valign="top"&gt;string (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;If you want to record something specific like the filename of the video being played then you can put this in the label parameter.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;value&lt;/td&gt;

      &lt;td valign="top"&gt;integer (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;This last type is if you want to assign a specific value to the event such as somebody you can make £5 in advertising each time somebody watches one of your videos.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;A simple page tracker event might look like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;_gaq.push(['_trackEvent', &amp;quot;Videos&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Cat falls off table.avi&amp;quot;, 5]);&lt;/pre&gt;

&lt;p&gt;This would assign a value of 5 dollars and attribute it to a play of a video called &amp;quot;Cat falls off table.avi&amp;quot;.&lt;/p&gt;

&lt;h4&gt;Planning your events&lt;/h4&gt;

&lt;p&gt;I just want to pass on a bit of advice that I picked up while learning in the Conversion University. You should create a planning document which outlines the general structure of what events you intend to capture. Using a straightforward naming convention and make sure you stick to it. Otherwise you will find it unmanageable when it comes to trying to make sense of the data collected.&lt;/p&gt;

&lt;h4&gt;Look at the code&lt;/h4&gt;

&lt;p&gt;Now that you understand the background, lets take a look at the code I have implemented in my blog to track these items and then afterwards I will go over the code highlighting the major features.&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;script src='http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt; 
&amp;lt;script type='text/javascript'&amp;gt;
/* &amp;lt;![CDATA[ */
$(document).ready(function () {
    SetupGoogleAnalyticsTrackEvents();
});

function SetupGoogleAnalyticsTrackEvents()
{
    TrackEventsForCodeSampleDownloads();
    TrackEventsForImageClicks();
}

function TrackEventsForCodeSampleDownloads()
{
    var FilterByBlogSampleHref = &amp;quot;href^='http://cid-15f731b049c8a797.skydrive.live.com/self.aspx/BlogExamples/'&amp;quot;;
    var FilterByRarFileExtension = &amp;quot;href$='.rar'&amp;quot;;
    
    $(&amp;quot;a[&amp;quot; + FilterByBlogSampleHref + &amp;quot;][&amp;quot; + FilterByRarFileExtension + &amp;quot;]&amp;quot;).click(function() {
        var SampleFileName = ExtractFileNameFromUrl($(this).attr(&amp;quot;href&amp;quot;));
        TrackEvent(&amp;quot;Sample Application&amp;quot;, &amp;quot;Download&amp;quot;, SampleFileName);
    });
}

function TrackEventsForImageClicks()
{
    TrackEventByFileExtension(&amp;quot;.gif&amp;quot;);
    TrackEventByFileExtension(&amp;quot;.jpg&amp;quot;);
    TrackEventByFileExtension(&amp;quot;.jpeg&amp;quot;);
    TrackEventByFileExtension(&amp;quot;.png&amp;quot;);
}

function TrackEventByFileExtension(FileExtension)
{
    $(&amp;quot;a[href$='&amp;quot; + FileExtension + &amp;quot;']&amp;quot;).click(function() {
        var ImageFileName = ExtractFileNameFromUrl($(this).attr(&amp;quot;href&amp;quot;));
        TrackEvent(&amp;quot;Image Enlargement&amp;quot;, &amp;quot;Click&amp;quot;, ImageFileName);
    });
}

function ExtractFileNameFromUrl(Url)
{
    // Note this code assumes
    //   - that the url doesnt contain a query string
    //   - that a real url has been passed in
    //   - that the url has a filename and isnt a folder
    var SplitUrl = Url.split('/');
    
    var FileName = SplitUrl[SplitUrl.length-1];
    
    return FileName;
}
        
function TrackEvent(Category, Action, Label)
{
   _gaq.push(['_trackEvent', Category, Action, Label]);
}
/* ]]&amp;gt; */
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;h4&gt;Pseudo code theory&lt;/h4&gt;

&lt;p&gt;Lets take a quick run through the concept behind this script so you can see why I have structured it the way I have. The main method is called from a jQuery ready event so if you have put your analytics tag just before a &amp;lt;/head&amp;gt; tag then _gaq will be setup by the time this executes.&lt;/p&gt;

&lt;p align="left"&gt;I have changed this from the original article so that it uses the Google CDN to download jQuery instead of the Microsoft CDN because of &lt;a href="http://encosia.com/2010/09/15/6953-reasons-why-i-still-let-google-host-jquery-for-me/"&gt;Dave Ward's article&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I have split it into two algorithms. The first one finds all the links on the page pointing to rar files on my Windows Live SkyDrive account which is where I keep all my sample applications. The second one plucks out links which are pointing to images.&lt;/p&gt;

&lt;p&gt;The code registers click events with all of the links it finds matching these criteria. Then when you click on one of these links the click handler fires and calls the track event method.&lt;/p&gt;

&lt;h4&gt;Double where clauses&lt;/h4&gt;

&lt;p&gt;I needed to filter the links to my sample applications by two criteria. First it needed to start with my Sky Drive url and secondly it should end with a .rar extension.&lt;/p&gt;

&lt;p&gt;While researching how to do this I found that you can chain up multiple [] where clauses. The code that uses this technique looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$(&amp;quot;a[&amp;quot; + FilterByBlogSampleHref + &amp;quot;][&amp;quot; + FilterByRarFileExtension + &amp;quot;]&amp;quot;);&lt;/pre&gt;

&lt;p&gt;After I had written the initial code I refactored out the specific filters into two variables. This was so that it was clear at a glance what I was trying to filter. This is important because when I come back to this code after a few months I don't want to have to decode what the filters mean.&lt;/p&gt;

&lt;h4&gt;Ends with operator&lt;/h4&gt;

&lt;p&gt;The other cool trick I found which shows the power of jQuery was the ends with operator. This looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$(&amp;quot;a[href$='&amp;quot; + FileExtension + &amp;quot;']&amp;quot;);&lt;/pre&gt;

&lt;p&gt;The $= means that the href attribute must end with the value of FileExtension. I didn't refactor this filter out because I felt that the name of the method made it clear we are looking at the end of a url.&lt;/p&gt;

&lt;h4&gt;Layout of the code (Refactored)&lt;/h4&gt;

&lt;p&gt;After I had finished the code this looked quite a lot different than it does now. I made a series of small changes to the code to ensure that the code was as clean as possible. For example, I put the _trackEvent call in a wrapper so that I didn't have third party library calls throughout my code. If it turns out in the future that I need to switch my analytics provider then I will only have to change this code in one place.&lt;/p&gt;

&lt;p&gt;I extracted the code in TrackEventByFileExtension() so that I could reduce duplication in my code.&lt;/p&gt;

&lt;p&gt;I put the ExtractFileNameFromUrl() code in its own function to improve the readability of its calling function by reducing the complexity of the parent method. The name of the method in the code also serves as a form of human readable documentation which explains what the code is doing in natural language.&lt;/p&gt;

&lt;h4&gt;How to use this in your projects&lt;/h4&gt;

&lt;p&gt;The sample code that I have presented above is really tailored to my specific event tracking requirements (which I completely fabricated so that I had something to track). &lt;/p&gt;

&lt;p&gt;Even if you have only a limited understanding of javascript I think this should provide you with enough information to pull out the bits you need to track your own custom events automatically.&lt;/p&gt;

&lt;p&gt;If you are putting this on your own website then you should also consider putting this in an external file. The only reason I have put the code inline in the head tag is because my blog is a hosted solution and I don't have file space setup to store it in.&lt;/p&gt;

&lt;h4&gt;More information&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a title="http://www.conversionuniversity.com/" href="http://www.conversionuniversity.com/"&gt;http://www.conversionuniversity.com/&lt;/a&gt; - Conversion University &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEventTracking.html"&gt;http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEventTracking.html&lt;/a&gt; - Event Tracking API documentation &lt;/li&gt;
&lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f03%2fhow-to-automatically-track-events-with.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f03%2fhow-to-automatically-track-events-with.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f03%2fhow-to-automatically-track-events-with.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2011%2f03%2fhow-to-automatically-track-events-with.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/93Gatcnmdfg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/1636969317600404767/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=1636969317600404767" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/1636969317600404767?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/1636969317600404767?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/93Gatcnmdfg/how-to-automatically-track-events-with.html" title="How to automatically track events with Google Analytics async snippet and jQuery" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2011/03/how-to-automatically-track-events-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQCRH09cSp7ImA9WxFSFU0.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8038880382149398911</id><published>2010-04-17T13:28:00.001+01:00</published><updated>2010-04-17T13:29:25.369+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-17T13:29:25.369+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb" /><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="compile error" /><title>SOLVED - 'srcDomainMulti' is not declared. It may be inaccessible due to its protection level</title><content type="html">&lt;p&gt;When converting a project from C# to VB I ran into this compiler error which stopped me in my tracks for about 15 minutes. Just when I gave up and decided to rebuild the page by hand inspiration hit and I found my solution...&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;h4&gt;The scenario&lt;/h4&gt;  &lt;p&gt;I had just put the finishing touches to a domain whois tool and I was ready to convert it over to a VB project. I'm not a very strong VB.net coder but the project required the final deliverable in VB so I opted to make it all in C# first and then convert it over using one of the &lt;a href="http://www.developerfusion.com/tools/convert/csharp-to-vb/"&gt;great free tools for converting code online&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;After creating my new solution, adding the website and the class library, creating the stub pages and running all of the code files through the online code converter I was almost ready to go.&lt;/p&gt;  &lt;p&gt;The last step was to convert the aspx ui page. I was vaguely aware that in some situations there are differences between the syntax in these pages but I kept my fingers crossed that I wouldn't have to remember these little nuances so I could ship it quickly.&lt;/p&gt;  &lt;h4&gt;The problem&lt;/h4&gt;  &lt;p&gt;Hitting compile I was hit with the an error which confused me:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Error 1 'srcDomainMulti' is not declared. It may be inaccessible due to its protection level.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Double clicking it took me to a line in my code behind where I was tweaking a parameter of an ObjectDataSource just before it bound. The code couldn't see the ObjectDataSource on my page!&lt;/p&gt;  &lt;p&gt;I played around for a few minutes, even rolling up my sleeves and writing some code to FindControl it just in case it was a naming container issue I was unaware of:&lt;/p&gt;  &lt;pre class="brush: vb;"&gt;Dim srcMulti As ObjectDataSource = DirectCast(Me.FindControl(&amp;quot;srcDomainMulti&amp;quot;), ObjectDataSource)
srcMulti.SelectParameters(&amp;quot;PopularOnly&amp;quot;).DefaultValue = &amp;quot;False&amp;quot;&lt;/pre&gt;

&lt;p&gt;But the page still didn't work. In the end I gave up and started recreating the page by dropping controls onto a new VB page and setting them up item by item. When it came to binding the first drop down list I noticed something odd. The namespace of my DataObject was listed as:&lt;/p&gt;

&lt;pre class="brush: vb;"&gt;WhoisLibrary.WhoisLibrary.TldCollection&lt;/pre&gt;

&lt;h4&gt;The solution&lt;/h4&gt;

&lt;p&gt;The solution was really straightforward in the end, as nearly all problems turn out. Without looking into this too deeply it seems that VB holds your hand when it comes to namespaces and automatically wraps the class libraries files in a namespace.&lt;/p&gt;

&lt;p&gt;Each of the .vb files I had run through the converter &lt;em&gt;also &lt;/em&gt;had a namespace declaration wrapped around them which was doubling up on my code and making everything invisible.&lt;/p&gt;

&lt;p&gt;I whipped through the project removing all my namespace wrappers which removed the middle namespace layer, pressed compile and the project worked without any further grumbles!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-is-not-declared-it-may-be.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-is-not-declared-it-may-be.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-is-not-declared-it-may-be.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-is-not-declared-it-may-be.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-is-not-declared-it-may-be.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-is-not-declared-it-may-be.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/wKNcwJUPAd8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8038880382149398911/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8038880382149398911" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8038880382149398911?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8038880382149398911?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/wKNcwJUPAd8/solved-is-not-declared-it-may-be.html" title="SOLVED - &amp;#39;srcDomainMulti&amp;#39; is not declared. It may be inaccessible due to its protection level" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/04/solved-is-not-declared-it-may-be.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08AQXw9eSp7ImA9WxFSEEQ.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-2710110519382389993</id><published>2010-04-12T18:04:00.000+01:00</published><updated>2010-04-12T18:04:00.261+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-12T18:04:00.261+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="compile error" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: The type or namespace name 'Linq' does not exist in the namespace 'System' - are you missing an assembly reference?</title><content type="html">&lt;p&gt;This problem has been cropping up a lot recently - projects will complain of missing namespace's when I open them up and attempt to compile the first time. If this has happened to you then read on for a simple fix.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;I don't know if this one is a bug in Visual Studio 2010 (Beta 2 and RC1) or something else but recently I have noticed this error cropping up more and more. When I open an existing project it might fail to compile. I have also noticed it happen when I have downloaded a fresh project. Its not something I have pinned down but whenever I see this error:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Error 1 The type or namespace name 'Linq' does not exist in the namespace 'System' (are you missing an assembly reference?)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I know that the solution is quick and simple.&lt;/p&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;To get your compiler back on its feet you simply need to add a reference to System.Core.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Right click on the Bin folder in the Solution Explorer &lt;/li&gt;    &lt;li&gt;Choose Add Reference… &lt;/li&gt;    &lt;li&gt;Click the .NET tab and scroll down to System.Core      &lt;ul&gt;       &lt;li&gt;If you wait a few moments for the entire list to load you can simply click once on the list and start type System.Core. This will select the right item without you having to scroll and search for it. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Click OK to accept the new reference &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Once you have completed this cycle once you will be able to quickly select it by complete Step 1, 2 and then clicking the Recent tab and quickly selecting it from the short list.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/iUcXHVzsmZE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/2710110519382389993/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=2710110519382389993" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/2710110519382389993?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/2710110519382389993?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/iUcXHVzsmZE/solved-type-or-namespace-name-does-not.html" title="SOLVED: The type or namespace name &amp;#39;Linq&amp;#39; does not exist in the namespace &amp;#39;System&amp;#39; - are you missing an assembly reference?" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>10</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/04/solved-type-or-namespace-name-does-not.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIASX45fSp7ImA9WxFTGEs.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-3169728660019601117</id><published>2010-04-09T18:15:00.000+01:00</published><updated>2010-04-10T02:39:08.025+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-10T02:39:08.025+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="compile error" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: The located assembly’s manifest definition does not match the assembly reference</title><content type="html">&lt;p&gt;When working on a project recently I got an error that complained the assembly's manifest definition did not match the assembly reference. Read on to discover my simple fix.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;When I opened up a project the other day and simply tried to compile it I was struck with the following error:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Could not load file or assembly 'Intelligencia.UrlRewriter, Version=2.0.0.6, Culture=neutral, PublicKeyToken=0573f3650687980d' or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. HRESULT: 0x80131040&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The assembly in question could be any assembly. It is &lt;/p&gt;  &lt;p&gt;I have a central repository of 3rd party libraries on my development computer. Normally I keep them all in a central location so that I don't have to waste time downloading them again when I need them in a new project.&lt;/p&gt;  &lt;p&gt;This time I learned a quick lesson in keeping newer versions partioned away from older versions. Part of my original theory was that I could just drop the latest version of an assembly into that libraries folder and the next time I compiled the project it would use the refresh file and automatically update it to use the latest version.&lt;/p&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;It turns out that this plan didn't work so well for me. The refresh or maybe the web.config had an older version number embedded in it somewhere. So when it tried to refresh it got confused and gave the error above.&lt;/p&gt;  &lt;p&gt;The solution was pretty simple. Just delete the assembly and associated files from my projects bin folder and then choose Add Reference to add the latest version back in.&lt;/p&gt;  &lt;p&gt;A quick recompile later and I was on my way.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-located-assemblys-manifest.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-located-assemblys-manifest.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-located-assemblys-manifest.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-located-assemblys-manifest.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-located-assemblys-manifest.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f04%2fsolved-located-assemblys-manifest.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/43TJtBT2Nvk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/3169728660019601117/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=3169728660019601117" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/3169728660019601117?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/3169728660019601117?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/43TJtBT2Nvk/solved-located-assemblys-manifest.html" title="SOLVED: The located assembly’s manifest definition does not match the assembly reference" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>8</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/04/solved-located-assemblys-manifest.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEEQX06eip7ImA9WxFTF0k.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-7856694551817631944</id><published>2010-04-08T18:10:00.000+01:00</published><updated>2010-04-08T18:10:00.312+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-08T18:10:00.312+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="runtime error" /><category scheme="http://www.blogger.com/atom/ns#" term="IIS" /><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="IIS7" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: Breaking parent web.config dependencies in sub applications</title><content type="html">&lt;p&gt;This article explains how to implement a sub application such as a blog in your website without experiencing dependency issues. A common problem that developers experience is when their sub applications accidentally inherit requirements of the parent website. This is actually by design but read on if this is causing problems in your site.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;This problem has caught me out a couple of times so far but usually with enough of a gap between occurrences that it had become just a fuzzy memory. Hopefully by writing this article it will solidify it in my head and also help out other developers experiencing this for the first time.&lt;/p&gt;  &lt;p&gt;&lt;font face="verdana"&gt;Unfortunately this problem doesn't have a specific phrase or keyword that will make it easy for developers to find this solution in search engines. I want to rephrase this a couple of ways to hopefully capture the terms a developer might use when trying to solve this problem:&lt;/font&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font face="verdana"&gt;My blog, forum, gallery is requiring dlls from my parent website&lt;/font&gt; &lt;/li&gt;    &lt;li&gt;&lt;font face="verdana"&gt;When I install [software] in my site it tries to load assemblies from the main website&lt;/font&gt; &lt;/li&gt;    &lt;li&gt;&lt;font face="verdana"&gt;How do I stop my sub websites from needing the main sites bin folder&lt;/font&gt; &lt;/li&gt;    &lt;li&gt;Co&lt;font face="verdana"&gt;uld not load file or assembly 'assembly name' or one of its dependencies. The system cannot find the file specified.&lt;/font&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;font face="verdana"&gt;That should do it but any further phrasings (such as the search term you arrived here through) are welcome in the comments section.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="verdana"&gt;The problem occurs when you install a third party application as an application within an existing web site. I have had this occur when I have done the installation manually and also when I have used the &lt;a href="http://www.microsoft.com/web/Downloads/platform.aspx"&gt;Web PI&lt;/a&gt;.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="verdana"&gt;This could encompass any of the applications out there such as forums, blogs, galleries, shopping carts or anything that runs as its own application.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="verdana"&gt;The actual error message will most likely take the format of:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font face="verdana"&gt;&amp;quot;Could not load file or assembly 'assembly name' or one of its dependencies. The system cannot find the file specified.&amp;quot;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;The reason this is occurring is actually by design. The settings inside the main web.config will cascade downwards and all other config files will inherit the settings. If they have settings of their own they will override the parent. In fact even the root web.config is being merged with a server wide file called machine.config. &lt;/p&gt;  &lt;p&gt;So what's happening is the references to the assemblies in your main \bin\ folder are being passed down to the sub application and when it looks in its own bin folder it finds they aren't their and throws an error.&lt;/p&gt;  &lt;p&gt;The obvious solution is to block these settings being inherited by a lower config file. This is achieved by wrapping the &amp;lt;system.web&amp;gt; section in the following tag:&lt;/p&gt;  &lt;pre class="brush: xml;"&gt; &amp;lt;location path=&amp;quot;.&amp;quot; inheritInChildApplications=&amp;quot;false&amp;quot;&amp;gt;
   &amp;lt;system.web&amp;gt;
     &amp;lt;!-- ... --&amp;gt;
   &amp;lt;/system.web&amp;gt;
 &amp;lt;/location&amp;gt;&lt;/pre&gt;

&lt;p&gt;If you have used DOS or FTP then you will probably realise that in the path=&amp;quot;.&amp;quot; the dot means current folder. This applies the inheritChildApplications=&amp;quot;false&amp;quot; to all applications below the current folder. If you have a virtual folder setup in IIS that is at different physical location this is still counted as below the current application if its virtual url is below the current one.&lt;/p&gt;

&lt;h4&gt;Running IIS7 or above?&lt;/h4&gt;

&lt;p&gt;The newer versions of IIS have moved their configuration settings to a new section. If you have a web.config that is for IIS7 then you will need to also wrap &amp;lt;system.webServer&amp;gt; which is further down.&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;location path=&amp;quot;.&amp;quot; inheritInChildApplications=&amp;quot;false&amp;quot;&amp;gt; 
  &amp;lt;system.webServer&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
  &amp;lt;/system.webServer&amp;gt;
&amp;lt;/location&amp;gt;&lt;/pre&gt;

&lt;p&gt;You can have more than one &amp;lt;location&amp;gt; block in a web.config so it would be fine to do this to wrap around both sections.&lt;/p&gt;

&lt;h4&gt;IIS7 and validateIntegratedModeConfiguration&lt;/h4&gt;

&lt;p&gt;If you were previously relying on the &amp;lt;validation validateIntegratedModeConfiguration=&amp;quot;false&amp;quot; /&amp;gt; tag for the correct functioning of your site you might need to &lt;a href="http://runtingsproper.blogspot.com/2010/04/solved-iis7-validateintegratedmodeconfi.html"&gt;follow this technique to avoid a 502.22 Internal Server Error&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Only available in 2.0&lt;/h4&gt;

&lt;p&gt;Please note that if you're working with an asp.net 1.1 application you will not be able to put this tag in to block child applications as it was only introduced in 2.0. In this case your only real option as far as I know is to add &amp;lt;remove&amp;gt; elements into the child applications to cancel out each of the assemblies loaded in the asp.net 1.1 app. This is not a pretty solution because it tightly couples the two projects together however if you are in this situation and cannot upgrade the 1.1 app to 2.0 then it might be your only way out.&lt;/p&gt;

&lt;h4&gt;Restrictions with this technique&lt;/h4&gt;

&lt;p&gt;Please note that you cannot simply wrap the ENTIRE web.config in this tag as the root node must be the &amp;lt;configuration&amp;gt; tag.&lt;/p&gt;

&lt;p&gt;There are also certain sections you cannot wrap the &amp;lt;location&amp;gt; tag around such as the &amp;lt;configSections&amp;gt; tag.&lt;/p&gt;

&lt;p&gt;You can use more than one &amp;lt;location&amp;gt; tag to exclude various sections. Alternatively you can reorder portions of the web.config so that a single &amp;lt;location&amp;gt; can span multiple sections.&lt;/p&gt;

&lt;h4&gt;Incompatibilities with the WSAT&lt;/h4&gt;

&lt;p&gt;If you use the Web Site Administration Tool to configure your directory security you may have problems with the web.configs that the tool places in subdirectories. If this is the case then you can move the contents of the lower web.configs up into the main config and wrap them in a &amp;lt;location path=&amp;quot;path to file or folder&amp;quot;&amp;gt; tag.&lt;/p&gt;

&lt;h4&gt;Breaks local debugging&lt;/h4&gt;

&lt;p&gt;I have noticed that while this works great for allowing an application and a sub application to work in harmony on the server it can cause confusion when you try to use it on your local dev server. In doing research into this issue it turns out that this is a known bug which has been in the official to do list for quite a while but as it doesn't affect many users hasn't been resolved yet. You can read about and vote for this bug on Microsoft Connect at:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://connect.microsoft.com/VisualStudio/feedback/details/293526/web-debugging-fails-if-compilation-element-is-defined-inside-of-location-element"&gt;https://connect.microsoft.com/VisualStudio/feedback/details/293526/web-debugging-fails-if-compilation-element-is-defined-inside-of-location-element&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scenario is that if you place a &amp;lt;compilation debug=&amp;quot;true&amp;quot;&amp;gt; element within a &amp;lt;location path=&amp;quot;.&amp;quot; inheritInChildApplications=&amp;quot;false&amp;quot;&amp;gt; element the debug=&amp;quot;true&amp;quot; will not be understood. &lt;/p&gt;

&lt;p&gt;This means that when you press the play button to start debugging it will compile, launch the site and then immediately close the debug session. Your website will load up and you will be able to use it as normal but if you look at it in visual studio you will see the debug play button is available and the app is not considered to be currently being debugged.&lt;/p&gt;

&lt;p&gt;It may also mean that your app will simply fail to compile locally (but works fine on the server).&lt;/p&gt;

&lt;p&gt;There is a work around for this; by commenting the &amp;lt;location&amp;gt; element out and restarting the debug process local debugging will being working correctly again.&lt;/p&gt;

&lt;p&gt;As of the current version there is no way to automate setting this tag between local and production environments although it may be possible with the new web.config transformations in the upcoming .net 4 release.&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/_TiFI2bC2Jw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/7856694551817631944/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=7856694551817631944" title="16 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7856694551817631944?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7856694551817631944?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/_TiFI2bC2Jw/solved-breaking-parent-webconfig.html" title="SOLVED: Breaking parent web.config dependencies in sub applications" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>16</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/04/solved-breaking-parent-webconfig.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQDRHgyeSp7ImA9WhJXGEQ.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-3949682809351997748</id><published>2010-04-07T19:47:00.000+01:00</published><updated>2012-08-13T22:46:15.691+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-13T22:46:15.691+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="runtime error" /><category scheme="http://www.blogger.com/atom/ns#" term="IIS" /><category scheme="http://www.blogger.com/atom/ns#" term="bug" /><category scheme="http://www.blogger.com/atom/ns#" term="IIS7" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: IIS7, validateIntegratedModeConfiguration and inheritInChildApplications clash</title><content type="html">&lt;p&gt;This article covers an edge case you might have encountered when using the inheritInChildApplications attribute with a web site hosted on IIS7 and provides two possible solutions to your problem.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;You are trying to set up a sub application in your website and you wrap the &lt;a href="http://runtingsproper.blogspot.com/2010/04/solved-breaking-parent-webconfig.html"&gt;&amp;lt;location path=&amp;quot;.&amp;quot; inheritInChildApplications=&amp;quot;false&amp;quot;&amp;gt; element around your &amp;lt;system.webServer&amp;gt; element to break dependencies between apps&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Despite having followed the correct instructions you still see an error message the next time you try to load the parent site. The error looks something like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;HTTP Error 500.22 - Internal Server Error      &lt;br /&gt;An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This error occurs when you end up with the following configuration elements:&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;system.web&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
    &amp;lt;httpModules&amp;gt;
      &amp;lt;!-- ... --&amp;gt;
    &amp;lt;/httpModules&amp;gt;
    &amp;lt;httpHandlers&amp;gt;
      &amp;lt;!-- ... --&amp;gt;
    &amp;lt;/httpHandlers&amp;gt;
  &amp;lt;/system.web&amp;gt;
  &amp;lt;!-- ... --&amp;gt;
  &amp;lt;location path=&amp;quot;.&amp;quot; inheritInChildApplications=&amp;quot;false&amp;quot;&amp;gt;
    &amp;lt;system.webServer&amp;gt;
      &amp;lt;validation validateIntegratedModeConfiguration=&amp;quot;false&amp;quot; /&amp;gt;
      &amp;lt;!-- ... --&amp;gt;
    &amp;lt;/system.webServer&amp;gt;
  &amp;lt;/location&amp;gt;
  &amp;lt;!-- ... --&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;

&lt;p&gt;The important part here is that you have wrapped your &amp;lt;system.webServer&amp;gt; in a &amp;lt;location&amp;gt; tag to prevent inheritance. If that &amp;lt;system.webServer&amp;gt; tag contained a &amp;lt;validation&amp;gt; tag and there are still &amp;lt;httpModules&amp;gt; or &amp;lt;httpHandlers&amp;gt; further up the web.config then your validateIntegratedModeConfiguration attribute is going to cause this error.&lt;/p&gt;

&lt;h4&gt;What is validateIntegratedModeConfiguration?&lt;/h4&gt;

&lt;p&gt;The official documentation is here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb422433.aspx"&gt;http://msdn.microsoft.com/en-us/library/bb422433.aspx&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a simple housekeeping mechanism which stops you from accidentally using the old IIS6 httpHandler / httpModule registration mechanism in IIS7.&lt;/p&gt;

&lt;p&gt;In the old IIS6 days you would have registered these elements under the &amp;lt;system.web&amp;gt; tag as described in the snippet above. IIS7 registers these under the &amp;lt;system.webServer&amp;gt; tag.&lt;/p&gt;

&lt;p&gt;The reason that you would have put this &amp;lt;validate&amp;gt; tag into your web.config in the first place is because like many developers you are using Cassini. This is the dev server built in to Visual Studio and its based off IIS6.&lt;/p&gt;

&lt;p&gt;This means that if your site is hosted on IIS7 you need both sets of tags and adding the &amp;lt;validation&amp;gt; snippet allowed this scenario without throwing the error. &lt;/p&gt;

&lt;p&gt;The reason that its now showing up is that the &amp;lt;location&amp;gt; snippet does some funny things to the visibility of tags. It basically hides the &amp;lt;validation&amp;gt; setting from view and then complains because it has found both sets of registration tags.&lt;/p&gt;

&lt;p&gt;Luckily there are two simple solutions to this problem.&lt;/p&gt;

&lt;h4&gt;Solution 1: remove the old registration mechanisms&lt;/h4&gt;

&lt;p&gt;If the scenario fits for you now then the simples solution is to simply remove the &amp;lt;httpHandler&amp;gt; and &amp;lt;httpModule&amp;gt; tags from &amp;lt;system.web&amp;gt;. This would mean that you have since changed over from using Cassini to using a local installation of IIS7. If you have then you no longer need the old tags and you can remove them.&lt;/p&gt;

&lt;p&gt;However, its likely that you haven't changed over to this development setup and what you really need is to keep both sets of tags and still be able to stop inheritance with the &amp;lt;location&amp;gt; tag.&lt;/p&gt;

&lt;h4&gt;Solution 2: move the validation tag outside of the location tag&lt;/h4&gt;

&lt;p&gt;Something I discovered when tackling this problem was that the web.config was happy to have more than one &amp;lt;system.webServer&amp;gt; inside a single .config file.&lt;/p&gt;

&lt;p&gt;This means that you can simply move the &amp;lt;validation&amp;gt; tag outside of the &amp;lt;location&amp;gt; tag and put it inside a second &amp;lt;system.webServer&amp;gt; tag that's visible to all.&lt;/p&gt;

&lt;p&gt;This means that the setting will be inherited into sub applications but for my purposes this was not a problem.&lt;/p&gt;

&lt;p&gt;Following this technique you would end up with a web.config that had an outline roughly like the following:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;system.web&amp;gt;
    &amp;lt;!-- keep httpModules and httpHandlers tags in here --&amp;gt;
  &amp;lt;/system.web&amp;gt;
  &amp;lt;system.webServer&amp;gt;
    &amp;lt;validation validateIntegratedModeConfiguration=&amp;quot;false&amp;quot; /&amp;gt;
  &amp;lt;/system.webServer&amp;gt;
  &amp;lt;location path=&amp;quot;.&amp;quot; inheritInChildApplications=&amp;quot;false&amp;quot;&amp;gt;
    &amp;lt;system.webServer&amp;gt;
      &amp;lt;!-- your original system.webServer tags stay in here --&amp;gt;
    &amp;lt;/system.webServer&amp;gt;
  &amp;lt;/location&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;

&lt;p&gt;As you can see there are now two &amp;lt;system.webServer&amp;gt; tags in the snippet and the second one has the &amp;lt;location&amp;gt; tag wrapped around it. In a real situation you would probably want to wrap the &amp;lt;system.web&amp;gt; tag in a &amp;lt;location&amp;gt; as well - or just wrap the two in one big &amp;lt;location&amp;gt; and move your new &amp;lt;system.webServer&amp;gt; outside of it.&lt;/p&gt;

&lt;h4&gt;Impersonation&lt;/h4&gt;

&lt;p&gt;One parting note is that if you read the official MSDN documentation that I link to above you will see there is actually a third tag that will trigger the validation error:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;identity impersonate=&amp;quot;true&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;I didn't include this in the article because I have never used it and I didn't want to give out bad advice. If my solutions above don't solve your problems then perhaps checking if you are using this third tag might help!&lt;/p&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/Lwh19Efl9rQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/3949682809351997748/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=3949682809351997748" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/3949682809351997748?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/3949682809351997748?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/Lwh19Efl9rQ/solved-iis7-validateintegratedmodeconfi.html" title="SOLVED: IIS7, validateIntegratedModeConfiguration and inheritInChildApplications clash" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>8</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/04/solved-iis7-validateintegratedmodeconfi.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8DRXk5eip7ImA9WhZREU4.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-4138993999296099630</id><published>2010-03-20T19:45:00.001Z</published><updated>2011-04-07T00:01:14.722+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-07T00:01:14.722+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>Tracking scroll depth to reveal content engagement in Google Analytics</title><content type="html">&lt;p&gt;This article investigates a way to track content engagement on your site. By monitoring how far down the page a visitor to your site travels and then recording the data in Google Analytics you can discover how many of your visitors are reading your content all the way to the end.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Update&lt;/h4&gt;  &lt;p&gt;This article was written for what is now the old style tracking code. If your code looks like the snippet below then this article is for you, although you should really upgrade to the async tracking code snippet and then read the &lt;a href="http://runtingsproper.blogspot.com/2011/04/tracking-scroll-depth-to-reveal-content.html"&gt;updated version of this article here&lt;/a&gt;.&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;script type='text/javascript'&amp;gt;
var gaJsHost = ((&amp;quot;https:&amp;quot; == document.location.protocol) ? &amp;quot;https://ssl.&amp;quot; : &amp;quot;http://www.&amp;quot;);
document.write(unescape(&amp;quot;%3Cscript src='&amp;quot; + gaJsHost + &amp;quot;google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E&amp;quot;));
&amp;lt;/script&amp;gt;
&amp;lt;script type='text/javascript'&amp;gt;
try {
var pageTracker = _gat._getTracker(&amp;quot;UA-XXXXXXX-X&amp;quot;);
pageTracker._trackPageview();
} catch(err) {}&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;h4&gt;Introduction&lt;/h4&gt;

&lt;p&gt;When browsing through your Google Analytics reports you will find a massive selection of data at your fingertips. You can find how many people visited a page, how long they were there, what country they were from, if it was their first visit, if they bought something from your site and so much more. If you're reading an article like this then I doubt that I need to sell you on what a great piece of kit it is. &lt;/p&gt;

&lt;p&gt;Part of what makes Google Analytics a great package is that it provides a JavaScript API which lets you mould the functionality to your requirements. &lt;/p&gt;

&lt;p&gt;It occurred to me that I would be interested to know if visitors to my site were reading all of my articles or if they were just bouncing in &amp;amp; out registering page views for content that didn't fit their needs.&lt;/p&gt;

&lt;p&gt;I decided that a good metric to decide if the visitor has read my content is that they scroll past 90% of the total height of the page. When this scroll depth is detected I will use _trackEvent() to record the information in Google Analytics.&lt;/p&gt;

&lt;h4&gt;What is Event Tracking?&lt;/h4&gt;

&lt;p&gt;Event tracking is an alternative way of tracking user activity on your site. The normal way is by registering page views. Not every activity on your website results in a fresh page view though. &lt;/p&gt;

&lt;p&gt;What if the user downloads a PDF, watches a video or scrolls to 90%? This is where the event tracking comes in. It allows you to register an event, put it in a category and even associate a monetary value with it.&lt;/p&gt;

&lt;p&gt;Another approach that you might see to tracking these kinds of events is to use virtual page views. This is where you track a page view but provide Google with a non-existent url so that you can identify the event. &lt;/p&gt;

&lt;p&gt;While this technique will let you track your on page activities it also clutters up your visitor statistics and is no longer a recommended approach. If you find an article suggesting this kind of technique then check how old it is and consider using event tracking instead.&lt;/p&gt;

&lt;h4&gt;_trackEvent&lt;/h4&gt;

&lt;p&gt;The way to track an event within Google Analytics is to call the _trackEvent() method on the pageTracker object. &lt;/p&gt;

&lt;p&gt;The pageTracker object is part of the tracking code snippet that you will have pasted into your site (if you haven't setup a Google Analytics account yet then you should review this screencast which explains &lt;a href="http://services.google.com/analytics/breeze/en/installing_ga_code/index.html"&gt;how to install your tracking code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The method takes several parameters - category, action, label and value. &lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;category&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The category is a general category (in my code I have used &amp;quot;Sample Application&amp;quot; and &amp;quot;Image Enlargement&amp;quot; as my categories).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;action&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The action is a specific action for the event (such as &amp;quot;Download&amp;quot;, &amp;quot;Click&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Vote&amp;quot;, etc).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;label&lt;/td&gt;

      &lt;td valign="top"&gt;string (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;If you want to record something specific like the filename of the video being played then you can put this in the label parameter.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;value&lt;/td&gt;

      &lt;td valign="top"&gt;integer (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;This last type is if you want to assign a specific value to the event such as somebody you can make £5 in advertising each time somebody watches one of your videos.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;A simple page tracker event might look like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;pageTracker._trackEvent(&amp;quot;Videos&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Cat falls off table.avi&amp;quot;, 5);&lt;/pre&gt;

&lt;p&gt;This would assign a value of 5 dollars (or whichever currency your analytics is configured to work with) and attribute it to a play of a video called &amp;quot;Cat falls off table.avi&amp;quot;.&lt;/p&gt;

&lt;h4&gt;Planning your events&lt;/h4&gt;

&lt;p&gt;I just want to pass on a bit of advice that I picked up while learning in the Conversion University. You should create a planning document which outlines the general structure of what events you intend to capture. Using a straightforward naming convention and make sure you stick to it. Otherwise you will find it unmanageable when it comes to trying to make sense of the data collected. If you are a web developer on a team then it would be a good idea to consult with the person who will be using this data before you implement your event tracking.&lt;/p&gt;

&lt;h4&gt;Taking the first swing&lt;/h4&gt;

&lt;p&gt;To start off with we simply want to be sure that the page scroll tracking is actually working. We are going to use jQuery to track the page scrolling. If you haven't every used jQuery before then you would benefit from reading some introductory tutorials but for the sake of this article please just take my word that the .ready() allows you to run a piece of code when the page has finished loading and window.scroll() allows you to run a piece of code each time a scroll is detected.&lt;/p&gt;

&lt;p&gt;Here is the first draft:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;    &amp;lt;script src='http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt; 
    &amp;lt;script type='text/javascript'&amp;gt;
    /* &amp;lt;![CDATA[ */
        $(document).ready(function () {
            SetupGoogleAnalyticsTrackEvents();
        });

        function SetupGoogleAnalyticsTrackEvents()
        {
            TrackEventsForMinimumPageScroll();
        }

        function TrackEventsForMinimumPageScroll()
        {
           $(window).scroll(function(){
             var bottom = $(window).height() + $(window).scrollTop();
             var height = $(document).height();
             var percentage = Math.round(100*bottom/height);
           
             if(percentage &amp;gt; 90)
             {
                 alert(&amp;quot;Page Scrolled to 90% in &amp;quot; + document.location.href);
             }
           }); 
        }
    /* ]]&amp;gt; */
    &amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;You might wonder why I have used some seemingly redundant function names in this sample. This is simply to make sure the code we are writing fits in with the layout of code using in other Google Analytics integration articles on this site. To read them you can click the Google Analytics tag at the end of this article.&lt;/p&gt;

&lt;p&gt;So from reading through the code you will see that the following occurs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Some code is attached to the scroll event of the page &lt;/li&gt;

  &lt;li&gt;Each time the page is scrolled the percentage variable is updated to calculate how for down the page in total the user has scrolled. &lt;/li&gt;

  &lt;li&gt;This is calculated by comparing how far down the user has scrolled against the height of the page. &lt;/li&gt;

  &lt;li&gt;The page then checks if the scrolled percentage has exceeded a certain threshold (90% in this case) and alerts the user. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it out. Copy the code into a page and fill it with some bogus text. An easy way to get your hands on filler text is to use lorem ipsum. Just visit this site and generate a few paragraphs of text, enough to give you a scrollbar to test with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.lipsum.com/"&gt;http://www.lipsum.com/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to put the html / JavaScript snippet above into the &amp;lt;head&amp;gt; tag in your sample page.&lt;/p&gt;

&lt;p&gt;Back? Did it work? Great! So now we have a mechanism to detect when the user has scrolled to a certain threshold percentage. &lt;/p&gt;

&lt;h4&gt;Duplicate events&lt;/h4&gt;

&lt;p&gt;Did you notice any problems while playing with your new toy? It seems that after you continue scrolling down the page past 90% that the page keeps notifying you, again and again. If we were tracking this by sending and Event Tracking message to Google Analytics every time then our statistics wouldn't be very accurate at all!&lt;/p&gt;

&lt;p&gt;The solution is pretty straightforward. We need a simple Boolean variable which is set to 0 when the page loads but after the first time the threshold met event fires the Boolean is change to 1 and any subsequent events are ignored.&lt;/p&gt;

&lt;p&gt;The code would look something like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;var IsDuplicateEvent = 0;

function ScrollingEvent()
{
   if(ScrollThreshold &amp;gt; 90%)
   {
      if(IsDuplicateEvent == 0)
      {
         IsDuplicateEvent = 1;
         TrackEventInGoogleAnalytics();
      }
   }
}&lt;/pre&gt;

&lt;p&gt;This code wont compile because it's not much more than pseudo code but hopefully it does illustrate the idea. &lt;/p&gt;

&lt;p&gt;While writing this code I originally had the IsDuplicateEvent = 1; line at the end of the method. I figured that if the Event Tracking portion caused a problem then I didn't want to count it as a tracked event. When testing this code (by scrolling down the page really fast) I still managed to get duplicate alert boxes. Moving this variable to the start of the function stopped the duplicate events.&lt;/p&gt;

&lt;h4&gt;FINAL CODE - Tracking the event and wrapping up&lt;/h4&gt;

&lt;p&gt;At this point we can take our original code sample, fold the duplicate event blocker in and replace the alert() with a genuine call to the Google Analytics API. We would end up with some code that looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;    &amp;lt;script src='http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt; 
    &amp;lt;script type='text/javascript'&amp;gt;
    /* &amp;lt;![CDATA[ */
        var IsDuplicateScrollEvent = 0;

        $(document).ready(function () {
            SetupGoogleAnalyticsTrackEvents();
        });

        function SetupGoogleAnalyticsTrackEvents()
        {
            TrackEventsForMinimumPageScroll();
        }

        function TrackEventsForMinimumPageScroll()
        {
           $(window).scroll(function(){
             var scrollPercent = GetScrollPercent();
           
             if(scrollPercent &amp;gt; 90)
             {
               if(IsDuplicateScrollEvent == 0)
               { 
                 IsDuplicateScrollEvent = 1;
//                 alert(&amp;quot;Page Scrolled to 90% in &amp;quot; + document.location.href);
                 TrackEvent(&amp;quot;Content Engagement&amp;quot;, &amp;quot;Scrolled To 90%&amp;quot;, document.location.href);
               }
             }
           }); 
        }

        function GetScrollPercent()
        {
             var bottom = $(window).height() + $(window).scrollTop();
             var height = $(document).height();

             return Math.round(100*bottom/height);
        }
                                
        function TrackEvent(Category, Action, Label)
        {
           pageTracker._trackEvent(Category, Action, Label);
        }     
    /* ]]&amp;gt; */
    &amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;As you can see I have refactored the scroll percentage out into its own method just to make the code a bit cleaner to read. &lt;/p&gt;

&lt;p&gt;I have also left the alert() code in there but just commented it out. This is because it can take up to 24 hours to see tracked events actually appear in Google Analytics so it's handy to use it for one final check as you put the code into your site.&lt;/p&gt;

&lt;h4&gt;Further reading&lt;/h4&gt;

&lt;p&gt;For further reading on Google Analytics integration techniques you can browse the Google Analytics tag on this site:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://runtingsproper.blogspot.com/search/label/Google%20Analytics"&gt;http://runtingsproper.blogspot.com/search/label/Google%20Analytics&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official documentation page for event tracking is available at here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://code.google.com/apis/analytics/docs/tracking/eventTrackerOverview.html"&gt;http://code.google.com/apis/analytics/docs/tracking/eventTrackerOverview.html&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fgoogle-analytics-tracking-content.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fgoogle-analytics-tracking-content.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fgoogle-analytics-tracking-content.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fgoogle-analytics-tracking-content.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/CIWix5xAgDk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/4138993999296099630/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=4138993999296099630" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/4138993999296099630?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/4138993999296099630?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/CIWix5xAgDk/google-analytics-tracking-content.html" title="Tracking scroll depth to reveal content engagement in Google Analytics" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>8</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/03/google-analytics-tracking-content.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMEQ387eCp7ImA9WxBaEUw.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8769295723930799312</id><published>2010-03-11T00:30:00.001Z</published><updated>2010-03-20T19:46:42.100Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-20T19:46:42.100Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="compile error" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: Error 1 Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks</title><content type="html">&lt;p&gt;This is a simple looking error message that is deceptively hard to track down. Thankfully if you're having this problem then this article should get you back on track without spending hours scratching your head.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;It was time to update an existing website so after synchronising my copy of the site with the server I was ready to make my changes. The only problem was that every time I tried to compile the site I was getting an error:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Error 1 Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. Parameter name ticks&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This was a hard error to deal with because doing a project wide search for &amp;quot;Ticks&amp;quot; revealed no results. Searching for the DateTime object was similarly unproductive - only a handful of references and mostly within auto-generated code inside my linq to sql data context. &lt;/p&gt;  &lt;p&gt;The most difficult element of this puzzle was that the error listed in the Errors tab wasn't linked to a line of code in the project - double clicking it did nothing!&lt;/p&gt;  &lt;h4&gt;How I Solved It&lt;/h4&gt;  &lt;p&gt;After getting pretty annoyed because I was on the clock I made a backup of the site and decided to delete files until the dodgy file showed its face.&lt;/p&gt;  &lt;p&gt;I used the following heuristic to do this:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Switch to the Output tab and see what the last folder was which was compiled before it borked. &lt;/li&gt;    &lt;li&gt;Delete that folder. &lt;/li&gt;    &lt;li&gt;Recompile&lt;/li&gt;    &lt;li&gt;Keep repeating steps 1 to 3 until the site compiles&lt;/li&gt;    &lt;li&gt;When it compiles start bringing back individual files in the last batch you deleted until you find the offending file&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For me it turned out to be a single .jpg which when viewed in explorer with View Details had an empty &amp;quot;Date Modified&amp;quot;.&lt;/p&gt;  &lt;p&gt;I opened it up in Photoshop and saved it out again and this fixed the problem.&lt;/p&gt;  &lt;h4&gt;Will this work for you?&lt;/h4&gt;  &lt;p&gt;I was lucky that the files I deleted were all in supporting folders and didn't contain class files which would have broken the compilation of the site. If it turns out that step 1 leads you to a folder such as this I would take a look at the files and check that there aren't any obviously dodgy files. If there aren't then try deleting all of the non essential files in the site and see if the compiler is really getting hung up on that folder or not.&lt;/p&gt;  &lt;p&gt;Also when I first had this problem I went to Google and found that I had visited pages on sites that mentioned this error code before. I don't know how I solved i the first time but I am pretty sure this wasn't the solution so you might find your problem remains unsolved even after following this guide!&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fsolved-error-1-ticks-must-be-between.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fsolved-error-1-ticks-must-be-between.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fsolved-error-1-ticks-must-be-between.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fsolved-error-1-ticks-must-be-between.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fsolved-error-1-ticks-must-be-between.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fsolved-error-1-ticks-must-be-between.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/dGLEELqPidY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8769295723930799312/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8769295723930799312" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8769295723930799312?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8769295723930799312?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/dGLEELqPidY/solved-error-1-ticks-must-be-between.html" title="SOLVED: Error 1 Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/03/solved-error-1-ticks-must-be-between.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UCRXs7eSp7ImA9WxBbEUs.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-298617373253941254</id><published>2010-03-03T20:23:00.001Z</published><updated>2010-03-09T19:01:04.501Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-09T19:01:04.501Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="runtime error" /><category scheme="http://www.blogger.com/atom/ns#" term="AjaxControlToolkit" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: Could not load type 'System.Web.UI.ScriptReferenceBase'</title><content type="html">&lt;p&gt;Getting problems when you upload your Ajax Control Toolkit powered website up to your server? Read on for a quick and easy solution! &lt;/p&gt;  &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;If you have added some of the Ajax Control Toolkit extenders into your website you will have probably tested them out on your local dev computer and marvelled at how easy it was to add some impressive eye candy to your site. Then, just when you think your work is done for the day and its time to put your new creation online you are hit with an error: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Could not load type 'System.Web.UI.ScriptReferenceBase' from assembly 'System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Well you don't need to worry too much because this time it is a really simple fix. &lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Quick Fix &lt;/h4&gt;  &lt;p&gt;If your site has just broken and you want to get it running quickly then the simplest solution is to change your &amp;lt;cc1:ToolkitScriptManager&amp;gt; tag to be just a plain &amp;lt;asp:ScriptManager&amp;gt; tag. &lt;/p&gt;  &lt;p&gt;The ToolkitScriptManager is a wrapper control which provides the features of ScriptManager but also has a script combining feature to reduce the number of external javascript references generated by the toolkit. &lt;/p&gt;  &lt;p&gt;So its as simple as taking your code &lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7729dd7a-cd3b-4abc-8543-4efd6ab6b891" class="wlWriterSmartContent"&gt;   &lt;pre class="xml" name="code"&gt;&amp;lt;cc1:ToolkitScriptManager runat=&amp;quot;server&amp;quot; ... /&amp;gt; &lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;and changing it to &lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d5bfd66f-838b-4581-b5e3-99f58c8f7445" class="wlWriterSmartContent"&gt;
  &lt;pre class="xml" name="code"&gt;&amp;lt;asp:ScriptManager runat=&amp;quot;server&amp;quot; ... /&amp;gt; &lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;(You might have a different prefix than cc1 but it doesn't matter). &lt;/p&gt;

&lt;h4&gt;The Real Fix &lt;/h4&gt;

&lt;p&gt;The real reason that your site is throwing the error is that the latest version of Ajax Control Toolkit expects to have a .net 3.5 SP1 runtime environment. The key bit here is the SP1 which means Service Pack 1. &lt;/p&gt;

&lt;p&gt;To fix it you simply need to install the SP1 release which can be downloaded from here: &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=ab99342f-5d1a-413d-8319-81da479ab0d7&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?familyid=ab99342f-5d1a-413d-8319-81da479ab0d7&amp;amp;displaylang=en&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This needs to be run on your server so you will need remote desktop access to do this. This kind of control over your server is typically only available with dedicated servers or VPS virtual servers. &lt;/p&gt;

&lt;p&gt;If you have a simple shared hosting package then you need to contact your web host and find out why they haven't upgraded yet. The SP1 release was a major upgrade which not only has many bug fixes included in it but also some great new features such as ASP.NET Dynamic Data. You can read all about the new features on the download link above. &lt;/p&gt;

&lt;p&gt;In the worst case scenario where you cant get your host to upgrade and you cant move hosts because you are locked into a contract with them then you can at least fall back on the quick fix listed in the middle of this article to get your site running again.&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fcould-not-load-type.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fcould-not-load-type.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fcould-not-load-type.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fcould-not-load-type.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fcould-not-load-type.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f03%2fcould-not-load-type.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/fUxnVFW9_ko" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/298617373253941254/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=298617373253941254" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/298617373253941254?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/298617373253941254?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/fUxnVFW9_ko/could-not-load-type.html" title="SOLVED: Could not load type &amp;#39;System.Web.UI.ScriptReferenceBase&amp;#39;" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>12</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/03/could-not-load-type.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIHRnk-eyp7ImA9WxBVFUQ.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-5180964186252241758</id><published>2010-02-19T16:21:00.001Z</published><updated>2010-02-19T16:22:17.753Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-19T16:22:17.753Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="install error" /><category scheme="http://www.blogger.com/atom/ns#" term="visual studio 2010" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: "Visual Studio setup cannot run in compatibility mode." error when attempting to uninstall Visual Studio 2010 Beta 2</title><content type="html">&lt;p&gt;If you are having problems upgrading from Visual Studio 2010 Beta 2 to Release Candidate (RC1) then hopefully this will get you back on your way.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;When trying to get rid of Visual Studio 2010 Beta 2 so I could update it to the RC1 release on my home computer I ended up getting some annoying errors.&lt;/p&gt;  &lt;p&gt;The following error message was being displayed every time I tried to click uninstall:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;---------------------------      &lt;br /&gt;setup.exe       &lt;br /&gt;---------------------------       &lt;br /&gt;Visual Studio setup cannot run in compatibility mode. For more information see the 'Installing' section in the &lt;/p&gt;    &lt;p&gt;Visual Studio Readme at &amp;quot;&lt;a href="http://go.microsoft.com/fwlink/?LinkId=143397&amp;quot;"&gt;http://go.microsoft.com/fwlink/?LinkId=143397&amp;quot;&lt;/a&gt;.       &lt;br /&gt;---------------------------       &lt;br /&gt;OK&amp;#160;&amp;#160; &lt;br /&gt;---------------------------&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_-p-n_FbMReM/S366jkazrlI/AAAAAAAAAjg/SLfVhIsYldE/s1600-h/uninstallvisualstudio2010beta27.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="uninstall-visual-studio-2010-beta-2" border="0" alt="uninstall-visual-studio-2010-beta-2" src="http://lh3.ggpht.com/_-p-n_FbMReM/S366kDdIh6I/AAAAAAAAAjk/goZE7FJ-TZc/uninstallvisualstudio2010beta2_thumb.gif?imgmax=800" width="455" height="212" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This error cropped up for me because I tried to uninstall Visual Studio before I uninstalled Team Foundation Server. This caused the uninstall to abort which made Windows think that the uninstaller had problems. It tries to be helpful by setting the setup.exe to run in compatibility mode but as the error message above indicates - you cant run the Visual Studio setup application in compatibility mode.&lt;/p&gt;  &lt;p&gt;So I turned to the documentation suggested in the link above but it didn't make it clear where I was supposed to find the setup.exe or how exactly I could change it. This article aims to fill that gap.&lt;/p&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;The setup.exe application can be found in the following location:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Microsoft Visual Studio 2010 {EDITION} Beta 2 - ENU&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The edition will be whichever edition you installed. I had the following folders on my computer as I upgraded to the ultimate edition after first trialling professional:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Microsoft Visual Studio 2010 Professional Beta 2 - ENU     &lt;br /&gt;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Microsoft Visual Studio 2010 Ultimate Beta 2 - ENU&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;To change the compatibility mode take the following steps:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Right click on setup.exe and click Properties&lt;/li&gt;    &lt;li&gt;Switch to the Compatibility tab&lt;/li&gt;    &lt;li&gt;Untick the &amp;quot;Run this program in compatibility mode for&amp;quot; checkbox&lt;/li&gt;    &lt;li&gt;If you have a button at the bottom of the dialog entitled &amp;quot;Show settings for all users&amp;quot; click this and repeat step 3 in this window.&lt;/li&gt;    &lt;li&gt;Click OK until you have dismissed all dialog windows&lt;/li&gt;    &lt;li&gt;Go back to the uninstall entry and uninstall as normal.&lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;Power User Bonus Tip&lt;/h4&gt;  &lt;p&gt;I love little tips like this but usually I forget them by the time I get around to being able to use them again. To get the uninstall window open you can enter the following command in Start | Run:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;control appwiz.cpl&lt;/font&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-studio-setup-cannot-run-in.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-studio-setup-cannot-run-in.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-studio-setup-cannot-run-in.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-studio-setup-cannot-run-in.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-studio-setup-cannot-run-in.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-studio-setup-cannot-run-in.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/K6Y-yCjO7ZI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/5180964186252241758/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=5180964186252241758" title="39 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/5180964186252241758?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/5180964186252241758?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/K6Y-yCjO7ZI/solved-studio-setup-cannot-run-in.html" title="SOLVED: &amp;quot;Visual Studio setup cannot run in compatibility mode.&amp;quot; error when attempting to uninstall Visual Studio 2010 Beta 2" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_-p-n_FbMReM/S366kDdIh6I/AAAAAAAAAjk/goZE7FJ-TZc/s72-c/uninstallvisualstudio2010beta2_thumb.gif?imgmax=800" height="72" width="72" /><thr:total>39</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/02/solved-studio-setup-cannot-run-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UDSH47eSp7ImA9WxBWFEU.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8053835247776044913</id><published>2010-02-06T20:43:00.001Z</published><updated>2010-02-06T20:47:59.001Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-06T20:47:59.001Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="runtime error" /><category scheme="http://www.blogger.com/atom/ns#" term="Windows Service" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: Error 1053 / EventType clr20r3 when trying to start a Windows Service</title><content type="html">&lt;p&gt;If you have seen errors when trying to deploy your Windows Service that have error 1053 and cryptic codes starting with EventType clr20r3 in your Event Log then this is your solution!&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;I have recently been writing my first Windows Service which I tested and successfully used on my local development rig. Then when it came to deploying it I got cryptic error codes appearing which had me totally stumped.&lt;/p&gt;  &lt;p&gt;When I tried to start the service it would time out after 30 seconds and give me the following error message:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;The Sample Web Service service failed to start due to the following error:      &lt;br /&gt;The service did not respond to the start or control request in a timely fashion.&lt;/p&gt;    &lt;p&gt;Error 1053&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I tried to test the service on Windows Server 2003 and Windows Server 2008 servers but it wouldn't work on either.&lt;/p&gt;  &lt;p&gt;Because the Windows Service was installed on the remote server it was out of reach of my debugger so I started blindly editing parts of the code, compiling, uploading, reinstalling the service and then attempting to start it. Needless to say this was a time consuming and frustrating process.&lt;/p&gt;  &lt;p&gt;During each test I would get the same error message popup but a slightly varying error message in the Application Event Log. The three unique errors that I noted down looked like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;EventType clr20r3, P1 windowsservice.exe, P2 1.0.0.0, P3 4b69efe0, P4 mscorlib, P5 2.0.0.0, P6 4a7cd8f7, P7 35f9, P8 40b, P9 system.argumentexception, P10 NIL. &lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt;    &lt;p&gt;EventType clr20r3, P1 windowsservice.exe, P2 1.0.0.0, P3 4b69e583, P4 windowsservice, P5 1.0.0.0, P6 4b69e583, P7 17, P8 1a, P9 system.nullreferenceexception, P10 NIL. &lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt;    &lt;p&gt;EventType clr20r3, P1 windowsservice.exe, P2 1.0.0.0, P3 4b68be72, P4 system, P5 2.0.0.0, P6 4889de7a, P7 36dc, P8 7f, P9 system.argumentexception, P10 NIL.&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;After dropping all of the error messages I could into Google and discovering that a lot of other developers were having the same problems I thought it would be an easy fix. Unfortunately for most users their cries for help went unanswered or unresolved.&lt;/p&gt;  &lt;p&gt;I did find several threads with people saying that I should put the service in a try catch block and then log the error to the Event Log but the problem was that nobody posted any code to go along with the suggestion. At the time I was stressed and wanted a copy paste answer!&lt;/p&gt;  &lt;p&gt;So in the end I caved, wrote the code, went through the test cycle one more time and then checked my event log.&lt;/p&gt;  &lt;p&gt;I should have done that the first time.&lt;/p&gt;  &lt;p&gt;In my event log was the actual exception that was being raised plus the full stack trace pointing right at the line of code that was causing the problem.&lt;/p&gt;  &lt;p&gt;It turned out that my problem was a FileSystemWatcher I had dropped on the design canvas. I had set a default path which was incorrect when placed on the server. At run time I manually set the path in my main code which I had checked and double checked but when the FileSystemWatcher was initialised at design time it was using the settings in the hidden .designer.cs file first - and crashing the service!&lt;/p&gt;  &lt;p&gt;The only silver lining I can see in this experience is that I am not going to forget it any time soon. If this -ever- happens to me again I am sure that I wont have any trouble instantly recalling the exact steps to solve this.&lt;/p&gt;  &lt;p&gt;Your specific error will probably not be the same one as mine, however by using the code in the next section you will be able to track down your offending error with ease.&lt;/p&gt;  &lt;h4&gt;Implementation&lt;/h4&gt;  &lt;p&gt;If you created a bog standard Windows Service project you should have a file called Program.cs. This file contains your Main() which is the entry point for the application. You should have some code that looks like this:&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] 
{ 
    new SampleWindowsService() 
};
ServiceBase.Run(ServicesToRun);&lt;/pre&gt;

&lt;p&gt;To trap the error you will need to wrap the whole block inside a try catch:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;try
{
    ServiceBase[] ServicesToRun;
    ServicesToRun = new ServiceBase[] 
{ 
    new SampleWindowsService() 
};
    ServiceBase.Run(ServicesToRun);
}
catch (Exception ex)
{
}&lt;/pre&gt;

&lt;p&gt;In the catch() block we will need to write out the details of the Exception into the Application Event Log. Here is the minimum code you need to log an error to the Windows Event Log.&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;string SourceName = &amp;quot;WindowsService.ExceptionLog&amp;quot;;
if (!EventLog.SourceExists(SourceName))
{
    EventLog.CreateEventSource(SourceName, &amp;quot;Application&amp;quot;);
}

EventLog eventLog = new EventLog();
eventLog.Source = SourceName;
string message = string.Format(&amp;quot;Exception: {0} \n\nStack: {1}&amp;quot;, ex.Message, ex.StackTrace);
eventLog.WriteEntry(message, EventLogEntryType.Error);&lt;/pre&gt;

&lt;p&gt;I am not going to go through this code as it is reasonably self explanatory and not the focus of this article. When you drop that code in to the catch block you will also need to add in a reference to the System.Diagnostics namespace so that you can use EventLog.&lt;/p&gt;

&lt;p&gt;Putting all of this together our Program.cs should now look something like this:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Diagnostics;

namespace SampleWindowsService
{
    static class Program
    {
        /// &amp;lt;summary&amp;gt;
        /// The main entry point for the application.
        /// &amp;lt;/summary&amp;gt;
        static void Main()
        {
            try
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[] 
                { 
                    new SampleWindowsService() 
                };
                ServiceBase.Run(ServicesToRun);
            }
            catch (Exception ex)
            {
                string SourceName = &amp;quot;WindowsService.ExceptionLog&amp;quot;;
                if (!EventLog.SourceExists(SourceName))
                {
                    EventLog.CreateEventSource(SourceName, &amp;quot;Application&amp;quot;);
                }

                EventLog eventLog = new EventLog();
                eventLog.Source = SourceName;
                string message = string.Format(&amp;quot;Exception: {0} \n\nStack: {1}&amp;quot;, ex.Message, ex.StackTrace);
                eventLog.WriteEntry(message, EventLogEntryType.Error);
            }
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Install your Windows Service on the server and attempt to start it up. You will still get your error 1053 message. Now you can go to Event Viewer (Look for it under Administrative Tools in the Start menu or type eventvwr into Run). Click through to the Application log and you will see an error logged under &amp;quot;WindowsService.ExceptionLog&amp;quot;. Open it up and read the details to find a full stack trace of whatever exception it was that has been stopping you all this time!&lt;/p&gt;

&lt;p&gt;You should now be able to solve the problem pretty quickly…&lt;/p&gt;

&lt;h4&gt;Final note&lt;/h4&gt;

&lt;p&gt;When I was working on this solution I was building my Windows Service in Release mode. This was one of the things that I tried early on thinking it might not work in Debug mode on the server. Each time I tested out my service I would delete all files from the ftp folder and then upload the whole Release folder. This meant that the .pdb files were uploaded next to the Windows Service executable.&lt;/p&gt;

&lt;p&gt;I haven't tested it both ways but as far as I know the pdb file has to be there for the application to emit the line numbers in the stack trace. It can't hurt to include them while your doing this debugging.&lt;/p&gt;

&lt;p&gt;Hopefully once you get over this hurdle you will start seeing Windows Services as a fun application&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-error-1053-eventtype-clr20r3.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-error-1053-eventtype-clr20r3.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-error-1053-eventtype-clr20r3.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-error-1053-eventtype-clr20r3.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-error-1053-eventtype-clr20r3.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2010%2f02%2fsolved-error-1053-eventtype-clr20r3.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/2mmhR64la7A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8053835247776044913/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8053835247776044913" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8053835247776044913?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8053835247776044913?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/2mmhR64la7A/solved-error-1053-eventtype-clr20r3.html" title="SOLVED: Error 1053 / EventType clr20r3 when trying to start a Windows Service" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>8</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2010/02/solved-error-1053-eventtype-clr20r3.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAHSHc6eCp7ImA9WxBSFUU.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-7807221242199276799</id><published>2009-12-23T17:00:00.001Z</published><updated>2009-12-23T17:02:19.910Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-23T17:02:19.910Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="compile error" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: Compiler error CS1519: Invalid token 'void' in class, struct, or interface member declaration</title><content type="html">&lt;p&gt;This one has cropped up a couple of times in my development activities recently, but with just enough of a gap for me to have forgotten the solution and I had to figure it out again.&lt;/p&gt;  &lt;p&gt;It happens in situations where the project worked fine a minute ago and then all of a sudden the project wont run. It has also happened in situations where I have made a small update and then some seemingly unrelated part of the site has broken.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt; &lt;p&gt;From researching the problem it seems to hint at the server not having the LINQ libraries installed or missing references but from investigation of the projects I found they were both installed and referenced correctly.&lt;/p&gt;  &lt;p&gt;It turns out that, for me at least, it was a very simple fix. All you have to do is:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Find the file that is now complaining&lt;/li&gt;    &lt;li&gt;Open it up in Visual Studio&lt;/li&gt;    &lt;li&gt;Press the space bar and then delete the character you typed&lt;/li&gt;    &lt;li&gt;Save the file&lt;/li&gt;    &lt;li&gt;Upload the file to the website&lt;/li&gt;    &lt;li&gt;Revisit the website&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;These steps simply &amp;quot;dirty&amp;quot; the file in the eyes of the asp.net compiler and forces it to recompile the website again the next time a visitor requests a page.&lt;/p&gt;  &lt;p&gt;My theory as to what is going wrong is that when the previous update caused a recompile the old assemblies are locked and in use / not deleted / forgot about somehow so the next time it tries to run it has two many conflicting assemblies and crashes. That is about as much detail as I can go into though because I am just guessing.&lt;/p&gt;  &lt;p&gt;If this article has not solved your problem then the following link could be useful which describes an alternative fix for the problem. It revolves around the fact that you might not have referenced the LINQ libraries correctly:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="http://forums.asp.net/t/1222718.aspx" href="http://forums.asp.net/t/1222718.aspx"&gt;http://forums.asp.net/t/1222718.aspx&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-compiler-error-cs1519-invalid.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-compiler-error-cs1519-invalid.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-compiler-error-cs1519-invalid.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-compiler-error-cs1519-invalid.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-compiler-error-cs1519-invalid.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-compiler-error-cs1519-invalid.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/M3X_93PybuE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/7807221242199276799/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=7807221242199276799" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7807221242199276799?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7807221242199276799?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/M3X_93PybuE/solved-compiler-error-cs1519-invalid.html" title="SOLVED: Compiler error CS1519: Invalid token &amp;#39;void&amp;#39; in class, struct, or interface member declaration" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2009/12/solved-compiler-error-cs1519-invalid.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAGR3Y_fCp7ImA9WxBSFU8.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-2561204559926314644</id><published>2009-12-22T19:07:00.001Z</published><updated>2009-12-22T22:25:26.844Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-22T22:25:26.844Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="Firefox" /><title>Firefox - Clear Recent History</title><content type="html">&lt;p&gt;I just accidentally stumbled upon a new feature / keyboard shortcut that I didn't know about in Mozilla Firefox. Its called Clear Recent History and it is a way for you to clear only a short range of your recent browser history.&lt;/p&gt;  &lt;p&gt;If you press ctrl-shift-del then the following window is displayed:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_-p-n_FbMReM/SzEZCkay_AI/AAAAAAAAAjY/NL9eNRK9ySI/s1600-h/firefox-clear-recent-history%5B5%5D.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="firefox-clear-recent-history" border="0" alt="firefox-clear-recent-history" src="http://lh6.ggpht.com/_-p-n_FbMReM/SzEZCxCNaYI/AAAAAAAAAjc/Fm796HytdLQ/firefox-clear-recent-history_thumb%5B3%5D.gif?imgmax=800" width="419" height="298" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;The selections give you the option to delete the last one, two or four hours. Or for a more drastic approach you can also delete the whole of today or everything.&lt;/p&gt;  &lt;p&gt;From looking at the official documentation it looks like it is a new feature added in to Firefox 3.5.&lt;/p&gt;  &lt;p&gt;At this time of year it could come in pretty handy to clean up your tracks after you have spent the last hour shopping online and it would also log you out of Amazon which can be a big surprise spoiler if you're not careful!&lt;/p&gt;  &lt;h4&gt;Further Reading&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://support.mozilla.com/en-US/kb/Clear+Recent+History"&gt;http://support.mozilla.com/en-US/kb/Clear+Recent+History&lt;/a&gt; - Official documentation &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Firefox Extension&lt;/h4&gt;  &lt;p&gt;If you're a Firefox user then please consider checking out my Firefox extension called &amp;quot;Good Deeds&amp;quot;. &lt;/p&gt;  &lt;p&gt;Its a simple extension which loads up a website called TheRainforestSite.com once a day so that you can click the button on that page. Every time you click that button the advertising money which is earned on the following page is contributed towards saving the rainforest.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://addons.mozilla.org/en-US/firefox/addon/4875"&gt;&lt;font color="#0066cc"&gt;http://addons.mozilla.org/en-US/firefox/addon/4875&lt;/font&gt;&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2ffirefox-clear-recent-history.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2ffirefox-clear-recent-history.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2ffirefox-clear-recent-history.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2ffirefox-clear-recent-history.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2ffirefox-clear-recent-history.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2ffirefox-clear-recent-history.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/LWGnXVhcRUo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/2561204559926314644/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=2561204559926314644" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/2561204559926314644?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/2561204559926314644?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/LWGnXVhcRUo/firefox-clear-recent-history.html" title="Firefox - Clear Recent History" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_-p-n_FbMReM/SzEZCxCNaYI/AAAAAAAAAjc/Fm796HytdLQ/s72-c/firefox-clear-recent-history_thumb%5B3%5D.gif?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2009/12/firefox-clear-recent-history.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIBQ308fip7ImA9WxBSFE4.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8923775247766127075</id><published>2009-12-21T21:55:00.001Z</published><updated>2009-12-21T23:02:32.376Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-21T23:02:32.376Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="asp.net" /><category scheme="http://www.blogger.com/atom/ns#" term="MSDN" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="membership" /><title>Reading the ProviderUserKey when using the SqlMembershipProvider</title><content type="html">&lt;p&gt;The ProviderUserKey gives access to a unique identifier for each of the members in your membership data store. If you're doing a large amount of lookup's or want to cross link to another table you will find this technique will give you better performance than using the UserName property.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;If you are using the SqlMembershipProvider as your membership provider (which is the most common setup) you might find that you want to get at this unique user id. This is available via the ProviderUserKey property. &lt;/p&gt;  &lt;p&gt;Because of the nature of the provider pattern this is implemented in a generic fashion as an Object data type and its not immediately obvious how you can get at the data.&lt;/p&gt;  &lt;h4&gt;A brief introduction to the provider pattern&lt;/h4&gt;  &lt;p&gt;The provider pattern is used in several areas of the .net library. The basic concept behind it is that a common interface is defined that all the different implementations have to follow. It doesn't matter how they implement it behind the scenes but you have to promise to implement all of the methods and properties defined in the provider. &lt;/p&gt;  &lt;p&gt;This provides a consistent model to program against and has several benefits:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The same code can be used in your programs without spreading provider specific code throughout your project &lt;/li&gt;    &lt;li&gt;The provider can be swapped out without having to change any client code &lt;/li&gt;    &lt;li&gt;Developers have skills that can be easily transferred between projects despite using different data stores &lt;/li&gt;    &lt;li&gt;New developers on the team can get up to speed with the code base very quickly &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;To get a clearer idea, some examples of membership provider implementations could be powered by a sql server database, oracle database, web service or even xml files. The code to implement all of these providers would look very different but the code to use it from the front end would all be the same. Microsoft asp.net ships with two providers by default, a SQL powered one and one that runs on top of an Active Directory.&lt;/p&gt;  &lt;h4&gt;The SqlMembershipProvider implementation&lt;/h4&gt;  &lt;p&gt;As you will see in the MSDN documentation the official data type is the .net base class Object. The individual provider is then free to implement their ProviderUserKey in any format which inherits from Object. &lt;/p&gt;  &lt;p&gt;So as long at you know the data type being used by your provider you can simply cast the ProviderUserKey into the correct data type and read the information.&lt;/p&gt;  &lt;p&gt;There is one final catch with the SqlMembershipProvider; it uses a GUID data type. The GUID doesn't have a parameterless constructor which means you cannot cast it directly, you have to new up an instance of the class. This is demonstrated in the code sample below:&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;MembershipUser currentUser = Membership.GetUser();
GUID userKey = null;

if(currentUser != null)
{
   userKey = new GUID(currentUser.ProviderUserKey);
}&lt;/pre&gt;

&lt;h4&gt;Why would you use this information?&lt;/h4&gt;

&lt;p&gt;The ProviderUserKey is a unique identifier and is quicker to match than the UserName column. The ProviderUserKey is a uniqueidentifier sql datatype and the UserName is an nvarchar[255]. &lt;/p&gt;

&lt;p&gt;Also consider the situation where a user signs up to your website, contributes some content to the community and then closes their account. The username is available again which could mean that you end up attributing data from another users contributions to the wrong account. The ProviderUserKey is guaranteed to be a unique identifier.&lt;/p&gt;

&lt;h4&gt;Membership.GetUser()&lt;/h4&gt;

&lt;p&gt;Once you have a membership ProviderUserKey you can use it with the Membership.GetUser() method. An overload is provided which accepts this; Membership.GetUser(Object providerUserKey).&lt;/p&gt;

&lt;p&gt;One possible scenario is that you store the retrieved GUID in a session variable at the start of a page and then each reload you have a quicker way of looking up the users details.&lt;/p&gt;

&lt;h4&gt;Further Reading&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms152019.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms152019.aspx&lt;/a&gt; - GetUser() overload that accepts a ProviderUserKey. &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.web.security.membershipuser.provideruserkey.aspx"&gt;http://msdn.microsoft.com/en-us/library/system.web.security.membershipuser.provideruserkey.aspx&lt;/a&gt; - Membership.ProviderUserKey reference. &lt;/li&gt;
&lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2freading-provideruserkey-when-using.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2freading-provideruserkey-when-using.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2freading-provideruserkey-when-using.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2freading-provideruserkey-when-using.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2freading-provideruserkey-when-using.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2freading-provideruserkey-when-using.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/Zf1QiyzZpK0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8923775247766127075/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8923775247766127075" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8923775247766127075?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8923775247766127075?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/Zf1QiyzZpK0/reading-provideruserkey-when-using.html" title="Reading the ProviderUserKey when using the SqlMembershipProvider" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2009/12/reading-provideruserkey-when-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUICQHg9cCp7ImA9WxBTFEo.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-7545329996292741652</id><published>2009-12-05T00:53:00.001Z</published><updated>2009-12-10T19:32:41.668Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-10T19:32:41.668Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tfs" /><category scheme="http://www.blogger.com/atom/ns#" term="install error" /><category scheme="http://www.blogger.com/atom/ns#" term="tfs2010" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>SOLVED: TF31003 error when trying to connect to Team Foundation Server 2010 Beta 2</title><content type="html">&lt;p&gt;Welcome searchers! This post is not exactly light reading for the casual .net enthusiast so I will presume that if you're reading this you have probably landed here via a search engine after having a TF31003 problem crop up.&lt;/p&gt;  &lt;h4&gt;Installed software / background&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;Vista 64 bit &lt;/li&gt;    &lt;li&gt;VS 2010 beta 2 &lt;/li&gt;    &lt;li&gt;TFS 2010 beta 2 &lt;/li&gt;    &lt;li&gt;Single server / basic installation &lt;/li&gt;    &lt;li&gt;No errors on install &lt;/li&gt;    &lt;li&gt;Cannot log in to the TFS system at all - no combination of user accounts will be accepted &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Scenario&lt;/h4&gt;  &lt;p&gt;At any login point within TFS (such as in the add server dialog, or the Team Foundation Server Administration Console &amp;gt; Application Tier &amp;gt; Administer Group Membership link) you get an error pop up that contains the following message:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;TF31003: Your user account does not have permission to connect to the Team Foundation Server at http://yourcomputer:8080/tfs. Ask your server administrator to add the appropriate permissions to your account.&lt;/p&gt; &lt;/blockquote&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Cause of the problem&lt;/h4&gt;  &lt;p&gt;It turned out that issue was that the account I installed my TFS server in didn't have a password in it and the installer silently failed to add the required permissions to the account.&lt;/p&gt;  &lt;h4&gt;Solution&lt;/h4&gt;  &lt;p&gt;The solution is to create a new administrator account on your computer and then use a command line tool called tfsconfig.exe to add the required permissions to this account post-install.&lt;/p&gt;  &lt;p&gt;Firstly you need to open up a command window in:&lt;/p&gt;  &lt;p&gt;C:\Program Files\Microsoft Team Foundation Server 2010\Tools\&lt;/p&gt;  &lt;p&gt;Read my tip which explains &lt;a href="http://runtingsproper.blogspot.com/2009/10/sneaky-open-command-window-here-feature.html"&gt;an easy way to open a command window here in Windows Vista&lt;/a&gt; if you aren't sure how to do this.&lt;/p&gt;  &lt;p&gt;You then need to execute the following command:&lt;/p&gt;  &lt;p&gt;tfsconfig.exe accounts /add /account:&amp;quot;&lt;em&gt;yourAccount&lt;/em&gt;&amp;quot; /accountType:applicationTier /password:&lt;em&gt;yourPassword&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Replace yourAccount with your account name that you created. If you have spaces in your account name you &lt;strong&gt;must &lt;/strong&gt;put speech marks around the account name as demonstrated above. If you are on a domain (such as a corporate network) you might have to enter your domain such as &amp;quot;someDomain\yourUsername&amp;quot;. You should be able to figure this out based on the username and password you use to login to windows. I guess its not very likely that you will have a computer on a domain without a password so this probably was a wasted sentence for everyone who reads this.&lt;/p&gt;  &lt;p&gt;Replace yourPassword with the password you assigned to the account.&lt;/p&gt;  &lt;p&gt;Press enter and you will see a page or two of text coming up while it reports all the places it is changing the configurations to.&lt;/p&gt;  &lt;h4&gt;m_requiredInputs&lt;/h4&gt;  &lt;p&gt;If you see only a few lines of text after you issue the command in the last section and it ends with m_requiredInputs in red text then you have mistyped.&lt;/p&gt;  &lt;p&gt;In my case it turned out that I was typing add instead of /add - it let me get away without a forward slash at the start of accounts though.&lt;/p&gt;  &lt;p&gt;Ok well I hope this problem matches your problem and you are solved and on the way to starting out on your TFS journey. I am very excited to play with all the features I have read about so lets both go and make a start now!&lt;/p&gt;  &lt;h4&gt;Alternative version of this post&lt;/h4&gt;  &lt;p&gt;I wrote an abbreviated version of this post as soon as I solved the problem so that a) I wouldn't forget and b) it would be sure to catch the eye of the TFS2010 developers. You can read it over on the official forums at:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://social.msdn.microsoft.com/Forums/en/tfssetup/thread/8e103318-4ce3-49be-9602-09d65ae72889"&gt;http://social.msdn.microsoft.com/Forums/en/tfssetup/thread/8e103318-4ce3-49be-9602-09d65ae72889&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-tf31003-error-when-trying-to.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-tf31003-error-when-trying-to.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-tf31003-error-when-trying-to.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-tf31003-error-when-trying-to.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-tf31003-error-when-trying-to.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fsolved-tf31003-error-when-trying-to.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/U9jcve2McVg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/7545329996292741652/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=7545329996292741652" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7545329996292741652?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/7545329996292741652?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/U9jcve2McVg/solved-tf31003-error-when-trying-to.html" title="SOLVED: TF31003 error when trying to connect to Team Foundation Server 2010 Beta 2" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2009/12/solved-tf31003-error-when-trying-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04BSHc-cSp7ImA9WhZSEkk.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-8482323232513300996</id><published>2009-12-02T23:04:00.001Z</published><updated>2011-03-27T18:12:39.959+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-27T18:12:39.959+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="Google Analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="article" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>How to automatically track events with Google Analytics and jQuery</title><content type="html">&lt;p&gt;This article examines a way to use a feature of Google Analytics called Event Tracking. By using jQuery and the Google Analytics JavaScript API we will automatically track events on your site not seen by a standard analytics installation.&lt;/p&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h4&gt;Update&lt;/h4&gt;  &lt;p&gt;This article was written for what is now the old style tracking code. If your code looks like the snippet below then this article is for you, although you should really upgrade to the async tracking code snippet and then read the &lt;a href="http://runtingsproper.blogspot.com/2011/03/how-to-automatically-track-events-with.html"&gt;updated version of this article here&lt;/a&gt;.&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;script type='text/javascript'&amp;gt;
var gaJsHost = ((&amp;quot;https:&amp;quot; == document.location.protocol) ? &amp;quot;https://ssl.&amp;quot; : &amp;quot;http://www.&amp;quot;);
document.write(unescape(&amp;quot;%3Cscript src='&amp;quot; + gaJsHost + &amp;quot;google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E&amp;quot;));
&amp;lt;/script&amp;gt;
&amp;lt;script type='text/javascript'&amp;gt;
try {
var pageTracker = _gat._getTracker(&amp;quot;UA-XXXXXXX-X&amp;quot;);
pageTracker._trackPageview();
} catch(err) {}&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;h4&gt;Introduction&lt;/h4&gt;

&lt;p&gt;I have invested some time over the past week in getting to know Google Analytics a lot better. After working through the &amp;quot;in-depth analysis&amp;quot; section over on Google Analytics training ground (called &lt;a href="http://www.conversionuniversity.com/"&gt;Conversion University&lt;/a&gt;) I decided to implement events to track some items that are not tracked by the basic out-of-the-box Analytics implementation. &lt;/p&gt;

&lt;p&gt;When I woke up this morning I barely knew anything about jQuery having only used it once or twice before (each time with just enough of a gap for me to forget all the details when it came to using it again). Because writing the jQuery code was as much of a journey for me as the GA event tracking was, I will also cover a couple of tricks I learned along the way.&lt;/p&gt;

&lt;p&gt;Just in case it hasn't occurred to you - GA is an abbreviation for Google Analytics.&lt;/p&gt;

&lt;h4&gt;What does the Event Tracking do that normal Analytics doesn't?&lt;/h4&gt;

&lt;p&gt;A good place to start this off is to justify what this piece of technology does and why we would want to use it. By tracking an event we can record visitor activities that don't equate to a page visit but are still valuable to us. For example, you might want to know stats on your PDF downloads or other downloadable assets.&lt;/p&gt;

&lt;p&gt;A more advanced use would be to track a video player such as those embedded in the YouTube site. You could easily think of some usage patterns that you might want to track such as when the user presses play on the video. You could also track abandonment and make a new event if they watch over 90% of the video. Another example would be clicking on one of the recommended video links that are displayed after the main video has completed playing.&lt;/p&gt;

&lt;p&gt;It is worth remembering that a maximum of 500 events can be tracked per user per visit so you shouldn't try to track events that happen very frequently.&lt;/p&gt;

&lt;p&gt;You should now see that this is a potentially valuable feature to master.&lt;/p&gt;

&lt;h4&gt;_trackEvent&lt;/h4&gt;

&lt;p&gt;The way to track an event within Google Analytics is to call the _trackEvent() method on the pageTracker object. &lt;/p&gt;

&lt;p&gt;The pageTracker object is part of the tracking code snippet that you will have pasted into your site (if you haven't setup a Google Analytics account yet then you should review this screencast which explains &lt;a href="http://services.google.com/analytics/breeze/en/installing_ga_code/index.html"&gt;how to install your tracking code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The method takes several parameters - category, action, label and value. &lt;/p&gt;

&lt;table border="1" cellspacing="0" cellpadding="2"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;category&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The category is a general category (in my code I have used &amp;quot;Sample Application&amp;quot; and &amp;quot;Image Enlargement&amp;quot; as my categories).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;action&lt;/td&gt;

      &lt;td valign="top"&gt;string&lt;/td&gt;

      &lt;td valign="top"&gt;The action is a specific action for the event (such as &amp;quot;Download&amp;quot;, &amp;quot;Click&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Vote&amp;quot;, etc).&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;label&lt;/td&gt;

      &lt;td valign="top"&gt;string (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;If you want to record something specific like the filename of the video being played then you can put this in the label parameter.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;value&lt;/td&gt;

      &lt;td valign="top"&gt;integer (optional)&lt;/td&gt;

      &lt;td valign="top"&gt;This last type is if you want to assign a specific value to the event such as somebody you can make £5 in advertising each time somebody watches one of your videos.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;A simple page tracker event might look like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;pageTracker._trackEvent(&amp;quot;Videos&amp;quot;, &amp;quot;Play&amp;quot;, &amp;quot;Cat falls off table.avi&amp;quot;, 5);&lt;/pre&gt;

&lt;p&gt;This would assign a value of 5 dollars and attribute it to a play of a video called &amp;quot;Cat falls off table.avi&amp;quot;.&lt;/p&gt;

&lt;h4&gt;Planning your events&lt;/h4&gt;

&lt;p&gt;I just want to pass on a bit of advice that I picked up while learning in the Conversion University. You should create a planning document which outlines the general structure of what events you intend to capture. Using a straightforward naming convention and make sure you stick to it. Otherwise you will find it unmanageable when it comes to trying to make sense of the data collected.&lt;/p&gt;

&lt;h4&gt;Look at the code&lt;/h4&gt;

&lt;p&gt;Now that you understand the background, lets take a look at the code I have implemented in my blog to track these items and then afterwards I will go over the code highlighting the major features.&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;script src='http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js' type='text/javascript'&amp;gt;&amp;lt;/script&amp;gt; 
&amp;lt;script type='text/javascript'&amp;gt;
/* &amp;lt;![CDATA[ */
$(document).ready(function () {
    SetupGoogleAnalyticsTrackEvents();
});

function SetupGoogleAnalyticsTrackEvents()
{
    TrackEventsForCodeSampleDownloads();
    TrackEventsForImageClicks();
}

function TrackEventsForCodeSampleDownloads()
{
    var FilterByBlogSampleHref = &amp;quot;href^='http://cid-15f731b049c8a797.skydrive.live.com/self.aspx/BlogExamples/'&amp;quot;;
    var FilterByRarFileExtension = &amp;quot;href$='.rar'&amp;quot;;
    
    $(&amp;quot;a[&amp;quot; + FilterByBlogSampleHref + &amp;quot;][&amp;quot; + FilterByRarFileExtension + &amp;quot;]&amp;quot;).click(function() {
        var SampleFileName = ExtractFileNameFromUrl($(this).attr(&amp;quot;href&amp;quot;));
        TrackEvent(&amp;quot;Sample Application&amp;quot;, &amp;quot;Download&amp;quot;, SampleFileName);
    });
}

function TrackEventsForImageClicks()
{
    TrackEventByFileExtension(&amp;quot;.gif&amp;quot;);
    TrackEventByFileExtension(&amp;quot;.jpg&amp;quot;);
    TrackEventByFileExtension(&amp;quot;.jpeg&amp;quot;);
    TrackEventByFileExtension(&amp;quot;.png&amp;quot;);
}

function TrackEventByFileExtension(FileExtension)
{
    $(&amp;quot;a[href$='&amp;quot; + FileExtension + &amp;quot;']&amp;quot;).click(function() {
        var ImageFileName = ExtractFileNameFromUrl($(this).attr(&amp;quot;href&amp;quot;));
        TrackEvent(&amp;quot;Image Enlargement&amp;quot;, &amp;quot;Click&amp;quot;, ImageFileName);
    });
}

function ExtractFileNameFromUrl(Url)
{
    // Note this code assumes
    //   - that the url doesnt contain a query string
    //   - that a real url has been passed in
    //   - that the url has a filename and isnt a folder
    var SplitUrl = Url.split('/');
    
    var FileName = SplitUrl[SplitUrl.length-1];
    
    return FileName;
}
        
function TrackEvent(Category, Action, Label)
{
   pageTracker._trackEvent(Category, Action, Label);
}
/* ]]&amp;gt; */
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;h4&gt;Pseudo code theory&lt;/h4&gt;

&lt;p&gt;Lets take a quick run through the concept behind this script so you can see why I have structured it the way I have. The main method is called from a jQuery ready event so if you have put your analytics tag just before a &amp;lt;/body&amp;gt; tag then pageTracker will be setup by the time this executes.&lt;/p&gt;

&lt;p&gt;I have split it into two algorithms. The first one finds all the links on the page pointing to rar files on my Windows Live SkyDrive account which is where I keep all my sample applications. The second one plucks out links which are pointing to images.&lt;/p&gt;

&lt;p&gt;The code registers click events with all of the links it finds matching these criteria. Then when you click on one of these links the click handler fires and calls the track event method.&lt;/p&gt;

&lt;h4&gt;Double where clauses&lt;/h4&gt;

&lt;p&gt;I needed to filter the links to my sample applications by two criteria. First it needed to start with my Sky Drive url and secondly it should end with a .rar extension.&lt;/p&gt;

&lt;p&gt;While researching how to do this I found that you can chain up multiple [] where clauses. The code that uses this technique looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$(&amp;quot;a[&amp;quot; + FilterByBlogSampleHref + &amp;quot;][&amp;quot; + FilterByRarFileExtension + &amp;quot;]&amp;quot;);&lt;/pre&gt;

&lt;p&gt;After I had written the initial code I refactored out the specific filters into two variables. This was so that it was clear at a glance what I was trying to filter. This is important because when I come back to this code after a few months I don't want to have to decode what the filters mean.&lt;/p&gt;

&lt;h4&gt;Ends with operator&lt;/h4&gt;

&lt;p&gt;The other cool trick I found which shows the power of jQuery was the ends with operator. This looks like this:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$(&amp;quot;a[href$='&amp;quot; + FileExtension + &amp;quot;']&amp;quot;);&lt;/pre&gt;

&lt;p&gt;The $= means that the href attribute must end with the value of FileExtension. I didn't refactor this filter out because I felt that the name of the method made it clear we are looking at the end of a url.&lt;/p&gt;

&lt;h4&gt;Layout of the code (Refactored)&lt;/h4&gt;

&lt;p&gt;After I had finished the code this looked quite a lot different than it does now. I made a series of small changes to the code to ensure that the code was as clean as possible. For example, I put the _trackEvent call in a wrapper so that I didn't have third party library calls throughout my code. If it turns out in the future that I need to switch my analytics provider then I will only have to change this code in one place.&lt;/p&gt;

&lt;p&gt;I extracted the code in TrackEventByFileExtension() so that I could reduce duplication in my code.&lt;/p&gt;

&lt;p&gt;I put the ExtractFileNameFromUrl() code in its own function to improve the readability of its calling function by reducing the complexity of the parent method. The name of the method in the code also serves as a form of human readable documentation which explains what the code is doing in natural language.&lt;/p&gt;

&lt;h4&gt;How to use this in your projects&lt;/h4&gt;

&lt;p&gt;The sample code that I have presented above is really tailored to my specific event tracking requirements (which I completely fabricated so that I had something to track). &lt;/p&gt;

&lt;p&gt;Even if you have only a limited understanding of javascript I think this should provide you with enough information to pull out the bits you need to track your own custom events automatically.&lt;/p&gt;

&lt;p&gt;If you are putting this on your own website then you should also consider putting this in an external file. The only reason I have put the code inline in the head tag is because my blog is a hosted solution and I don't have file space setup to store it in.&lt;/p&gt;

&lt;h4&gt;More information&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a title="http://www.conversionuniversity.com/" href="http://www.conversionuniversity.com/"&gt;http://www.conversionuniversity.com/&lt;/a&gt; - Conversion University &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEventTracking.html"&gt;http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEventTracking.html&lt;/a&gt; - Event Tracking API documentation &lt;/li&gt;
&lt;/ul&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fhow-to-automatically-track-events-with.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fhow-to-automatically-track-events-with.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fhow-to-automatically-track-events-with.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f12%2fhow-to-automatically-track-events-with.html" style="border:0px" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/HU59Pa5-Tps" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/8482323232513300996/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=8482323232513300996" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8482323232513300996?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/8482323232513300996?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/HU59Pa5-Tps/how-to-automatically-track-events-with.html" title="How to automatically track events with Google Analytics and jQuery" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2009/12/how-to-automatically-track-events-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8ASXg4cSp7ImA9WxNaFE0.&quot;"><id>tag:blogger.com,1999:blog-5519904556829079674.post-9070541671659329154</id><published>2009-11-28T11:30:00.001Z</published><updated>2009-11-28T11:30:48.639Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-28T11:30:48.639Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="visual studio" /><category scheme="http://www.blogger.com/atom/ns#" term="bug" /><category scheme="http://www.blogger.com/atom/ns#" term="visual studio 2010" /><category scheme="http://www.blogger.com/atom/ns#" term="bugfix" /><title>Update - VS2010 Beta 2 – Validation ($SCHEMA$): Element is not supported</title><content type="html">&lt;p&gt;&lt;em&gt;Note: This is an update to an &lt;/em&gt;&lt;a href="http://runtingsproper.blogspot.com/2009/11/vs2010-beta-2-validation-schema-element.html"&gt;&lt;em&gt;earlier post&lt;/em&gt;&lt;/a&gt;&lt;em&gt; based on feedback that I have received from various commenter's.&lt;/em&gt; &lt;/p&gt;  &lt;p&gt;If you have adopted beta 2 of Visual Studio 2010 then you might have spotted a large amount of green squigglies underneath the tags in your markup. When you have over them you see a message like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_-p-n_FbMReM/SxEJ4fXv7hI/AAAAAAAAAjI/cNt3Tn3EgOg/s1600-h/validation-schema-not-supported%5B3%5D.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="validation-schema-not-supported" border="0" alt="validation-schema-not-supported" src="http://lh3.ggpht.com/_-p-n_FbMReM/SxEJ4ze-6MI/AAAAAAAAAjM/YSBHRILUrmc/validation-schema-not-supported_thumb%5B1%5D.gif?imgmax=800" width="440" height="198" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Validation ($SCHEMA$): Element 'div' is not supported&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;&lt;a name="more"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This appears to be a bug in the system. When this is occurring your autocomplete will not have any html element – only asp.net controls and snippets – which makes it pretty hard to do your work.&lt;/p&gt;  &lt;p&gt;To fix this error &lt;a href="http://runtingsproper.blogspot.com/2009/11/vs2010-beta-2-validation-schema-element.html"&gt;without resetting all of your Visual Studio configuration settings&lt;/a&gt; back to factory defaults follow these steps:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Click Tools | Options… &lt;/li&gt;    &lt;li&gt;If you have &amp;quot;Show all settings&amp;quot; unticked then you can click the Validation node.     &lt;br /&gt;      &lt;br /&gt;Otherwise you will have to click Text Editor | HTML | Validation.&lt;/li&gt;    &lt;li&gt;Make a selection in the Target: drop down (I picked XHTML 1.0 Transitional).&lt;/li&gt;    &lt;li&gt;Click OK to save your changes.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_-p-n_FbMReM/SxEJ5WTJjII/AAAAAAAAAjQ/1Dh9PMBsvzE/s1600-h/validation-schema-2-select-validation-target%5B3%5D.gif"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="validation-schema-2-select-validation-target" border="0" alt="validation-schema-2-select-validation-target" src="http://lh4.ggpht.com/_-p-n_FbMReM/SxEJ5vQ0FlI/AAAAAAAAAjU/FrH0gwiGwRQ/validation-schema-2-select-validation-target_thumb%5B1%5D.gif?imgmax=800" width="426" height="260" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="wlWriterHeaderFooter" style="margin:0px; padding:0px 0px 0px 0px;"&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f11%2fupdate-vs2010-beta-2-validation-schema.html" rev="vote-for"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f11%2fupdate-vs2010-beta-2-validation-schema.html" style="border:0px" alt="kick it" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a rev="vote-for" href="http://dotnetshoutout.com/Submit?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f11%2fupdate-vs2010-beta-2-validation-schema.html"&gt;&lt;img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f11%2fupdate-vs2010-beta-2-validation-schema.html" style="border:0px" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://webdevvote.com/vote/?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f11%2fupdate-vs2010-beta-2-validation-schema.html" rev="vote-for"&gt;&lt;img src="http://webdevvote.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fruntingsproper.blogspot.com%2f2009%2f11%2fupdate-vs2010-beta-2-validation-schema.html" style="border:0px" alt="vote it on WebDevVote.com" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;img src="http://feeds.feedburner.com/~r/RunTingsProper/~4/McgbBr9PYps" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://runtingsproper.blogspot.com/feeds/9070541671659329154/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=5519904556829079674&amp;postID=9070541671659329154" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/9070541671659329154?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5519904556829079674/posts/default/9070541671659329154?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RunTingsProper/~3/McgbBr9PYps/update-vs2010-beta-2-validation-schema.html" title="Update - VS2010 Beta 2 – Validation ($SCHEMA$): Element is not supported" /><author><name>rtpHarry</name><uri>http://www.blogger.com/profile/12491312873295977300</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_-p-n_FbMReM/SxEJ4ze-6MI/AAAAAAAAAjM/YSBHRILUrmc/s72-c/validation-schema-not-supported_thumb%5B1%5D.gif?imgmax=800" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://runtingsproper.blogspot.com/2009/11/update-vs2010-beta-2-validation-schema.html</feedburner:origLink></entry></feed>
