Home | PicNet Information Technology Services

How to make money from your website or blog using adsense and intelligent add placement

DiggThis
clock February 15, 2010 10:11 by author guido

Overview
This article will try to show you how best to maximize the income generating potential of a blog or a website by focusing on placement and settings of your advertisements. We will be using a new free service called Mouse Eye Tracking. This service allows you to see exactly how users interact with your website so it's a great tool for analyzing the placement of your AdSense adds.

Background
Making money from a popular blog post or website used to be fairly straight forward, you concentrated on having great content and the high revenue per click of online advertisement used to do the rest. Now days making a few dollars from a blog or a hobbyist web site is much harder and we have to start considering such things as:

  • Add placement, size, location
  • Look and Feel of the adds
  • The way the adds interact with the site content
  • Etc



Add Placement
If you are serious about making a few dollars from your website you unfortunately will need to invest some time trying out different placements for your adds, there is unfortunately no way around this. I will try however to show you that this can be a pretty easy process and hopefully help some of you make a dollar or two.

Analyzing your current add strategy
The first thing you need to do is register for a free account for the PicNet Mouse Eye Tracking Service. This will give you a code that needs to be inserted somewhere inside the body tag of your page. Note: This code does display a small message 'Mouse Eye Tracking by PicNet...' so ensure you style this message in such a way that it does not intrude on your content. Now let's look at the analysis of my blog with this tool.







As we can see, I had my add placed at the bottom of my screen and I was just using the standard look and feel of the AdSense adds. We can also see that NO ONE paid the adds any attention at all this day (this heat map shows a 24 hours period). So looking at the heat maps we can see that most of the activity is at the top of the screen and the right column.

Now I think I will try placing the add on the right hand side of the screen. This will allow the main content of the blog to still be the main player in the page but also make the adds more effective.

I left this for another 24 hours and this is the results



We can clearly now see much more activity in the adds now.
Now, I think I am happy with the position of these adds however they are taking way too much room and they are actually making it harder for users to use my side bar (you can see that by the lower activity in the side bar). So lets make the adds smaller, better looking and lets wait another 24 hours.



We can now see a lot more activity around this area. It appears that the smaller advertisement has made the add blend in a bit better with its surrounds. This may be why there is much more activity around the add region. In fact doing a click only analysis shows us that we have indeed had a few clicks.



Well, thats it. Hopefully this article helps you make a few more dollars from your blog/website. Please let me know how it goes with the usage of the Mouse Eye Tracking service as any feedback is welcome at the moment.

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd



Rendering a Spark Partial View to a string

clock September 25, 2009 09:56 by author guido

I needed to do this recently so I searched the interweb and quickly found this great article by Brent Edwards:

http://blog.edwardsdigital.com/post/Rendering-a-Spark-partial-view-to-a-string-or-JSONP-with-ASPNET-MVC.aspx

Now don't get me wrong, this works and is explained very well but I don't see the point in re-creating the ViewEngine? So I cleaned this up and ended up with:

public static string GetPartialViewHtml(ViewDataDictionary viewData, string viewRalativePath) {
  SparkViewFactory f = (SparkViewFactory) ViewEngines.Engines.First(e => e is SparkViewFactory);           
  SparkView view = (SparkView) f.Engine.CreateInstance(f.CreateDescriptor(null, null, viewRalativePath, null, false));
  view.ViewData = viewData;      
  StringWriter writer = new StringWriter();  
  view.RenderView(writer);  
  return writer.ToString();

 

Done, now for anyone that has tried to do this with ASP.Net MVC View engine, I pity you.

Thanks

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd



Sharing MVC Views Across Projects

clock August 12, 2009 04:25 by author guido

This is something I have been wanting to do for a while in the ASP.Net world however its not untill recently (with MVC) that this has been a 'clean' possibility. This article demonstrates how to do this.

Inspiration

At PicNet are always trying to deliver quality products at the cheapest possible cost to the user.  The way we do is is by having 'template' driven projects. This allows us to generate data access layers very quickly (see previous articles) and we also copy template web projects, windows projects, mobile projects that give us a good starting point.  We also levarage custom libraries heavily.  However we could never put any of the view code (aspx, ascx) in these libraries as it was just not clean.

Embedded Views

To store your shared views in a library project simply copy the view code (aspx, ascx, master) into your library project.  Please ensure that the view code compiles.  By this I mean that all references are still valid (without requiring Web.config namespaces).  Tools like Resharper will show wether the view is valid or not.  Then mark the view as an 'Embedded Resource'.  To do this just right click on the file name -> Properties and set the Buidl Action to 'Embedded Resource'.  You will then need to rebuild the project to embed the resource in the DLL.

 

The View Engine

Add the following View Engine to your library project.

 

/// <summary>

/// This class will read all embedded views in THIS dll and will dumpo them out to the

/// ~/tmp/Views directory.

/// </summary>

public class EmbeddedResourceViewEngine : WebFormViewEngine

{

    public EmbeddedResourceViewEngine() {            

        MasterLocationFormats = new[] {

            "~/Views/{1}/{0}.master",

            "~/Views/Shared/{0}.master",

            "~/tmp/Views/{0}.master"

        };

 

        ViewLocationFormats = new[] {

            "~/Views/{1}/{0}.aspx",

            "~/Views/{1}/{0}.ascx",

            "~/Views/Shared/{0}.aspx",

            "~/Views/Shared/{0}.ascx",

            "~/tmp/Views/{0}.aspx",

            "~/tmp/Views/{0}.ascx"

        };

        PartialViewLocationFormats = ViewLocationFormats;

 

        DumpOutViews();

    }

 

    private static void DumpOutViews()

    {

        IEnumerable<string> resources = typeof (EmbeddedResourceViewEngine).Assembly.GetManifestResourceNames().Where(name => name.EndsWith(".master") || name.EndsWith(".aspx") || name.EndsWith(".ascx"));

        foreach (string res in resources) { DumpOutView(res); }                

    }

 

    private static void DumpOutView(string res)

    {

        string rootPath = HttpContext.Current.Server.MapPath("~/tmp/Views/");

        if (!Directory.Exists(rootPath)) {

            Directory.CreateDirectory(rootPath);

        }

 

        Stream resStream = typeof (EmbeddedResourceViewEngine).Assembly.GetManifestResourceStream(res);

        int lastSeparatorIdx = res.LastIndexOf('.');

        string extension = res.Substring(lastSeparatorIdx + 1);

        res = res.Substring(0, lastSeparatorIdx);

        lastSeparatorIdx = res.LastIndexOf('.');

        string fileName = res.Substring(lastSeparatorIdx + 1);

 

        FileUtils.WriteFileContents(rootPath + fileName + "." + extension, resStream);

    }

}

 

 

This view engine simply gets the views that have been stored as embedded resources and dumps them out to the ~/tmp/Views directory.

 

Register the View Engine

In Global.asax.cs just add:

 

public static void RegisterCustomViewEngines(ViewEngineCollection viewEngines)  

{  

  viewEngines.Clear();  

  viewEngines.Add(new EmbeddedResourceViewEngine());  

}  

...

protected void Application_Start(object sender, EventArgs e)

{

  RegisterRoutes(RouteTable.Routes);

  RegisterCustomViewEngines(ViewEngines.Engines);

}

 

That's It

That's it all the embedded views now simply behave like shared views.

 

 

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd



Code Generated DAL (Data Access Layer) using ORM - Article 3

clock July 20, 2009 06:11 by author guido

Overview

Well, we're getting to the business end of these series of articles. In this article we will complete our PicNet.CodeGeneratedDALDemo.Data implementation, which means we will generate all of the required POCO files. We will also create a few tests to test the whole thing out.

Generating the NHibernate POCO Objects

To generate the POCOs download this articles source code. You can then just run nant dal as we described in Article 1.

The Generated POCOs

Lets have a look at the objects I create.

FIELDS

You will notifce a FIELDS enumeration at the top. I use this instead of passing magic strings around the place and simply serves the purpose of trying to remove the use of these magic strings and give a little bit of compile time checking for field names.

Constructors

I generate 3 constructors. These are: - The default constructor (required for serialisation, etc). - Required fields constructor (All fields that do not allow nulls) - All fields constructor

GetPropertyValueImpl and SetPropertyValueImpl

These methods are just implementations of IGetSetPropertyValue which provide a lightning fast alternative to reflection.

Properties

All of the object properties will follow. These save their dirty state and have a few NHibernate hacks that make life a little easier.

Misc Members

Finally we have the miscellaneous members ToString, GetHashCode, Equals, Clone, etc.

Compiling the Project

Once the POCOs have been generated you have to ensure that they are all included in the project. You also have to ensure that the hbm.xml files are marked as 'Embedded Resource'. Once you do this the entire project should compile.

Creating Tests

I have included only one very simple test class in the testing project but more importantly I have included the class 'InMemeoryDataTests' . This class allows you to create in memory NHibernate tests using SQLite.

Conclusion

This article wraps up this series of articles on using code generated data access layers. I hope that if you have taken the time to work through these things you will now appreciate the ease and speed of development that this approach gives. This approach is not for all projects but in my experience suits a vast majority of them. Some things that you may consider when working with this code.

  • GetHashCode is not ideal as it uses the ID of an object for hashcode and this causes a plethora of well known issues when working with NHibernate.
  • Nullables are not supported (have never gotten around to adding it in)
  • This is a highly canabilised version of this code and is missing a lot of important features such as encryption, meta data helpers, serialisation helpers, etc.

Enjoy

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd



JQuery Table Filter Plugin

clock June 29, 2009 07:32 by author guido


This project has moved. New Home Page


Update 1/Mar/2010

The home page for this project is now at http://www.picnet.com.au/picnet_table_filter.html
Thanks

Update 11/Feb/2010

I will be moving this project to its own page with the source code at codeplex very shortly. This is because this project has taken on a life of its own and I personally don't want to be the only mantainer (having very limited time). So I'm sending a call out to anyone that wants to participate on the ongoing development of this project. Please email me (guido.tapia@picnet.com.au) if you would like to be a developer of this project. Note: I assume very little time will be required.

Once the new site is ready this blog post will be sanitized (links removed and comments closed) as everything will live on the new site.

Thanks

Introduction

This plugin adds column filtering capabilities to a regular <table> by adding a row to the <thead> section of a table and adding filters that allows real time filtering of tabular data.  Download this demo bundle for a quick start.

Note: We use this library in the production of many of our custom software development projects so it is production ready.

Demo

A simple demo page.

Getting Started

This plugin uses several other popular plugins so you will need to download these plugins before starting.

You can also use this packed version of the scripts. These plugins will then need to be referenced in the <head> section of your page.


 
<script type="text/javascript" src="Scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.cookie.js"></script>   
<script type="text/javascript" src="Scripts/picnet.jquery.tablefilter.js"></script>
 

Or (For Production Code)

 


 
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" type="text/javascript"></script>    
<script type="text/javascript" src="Scripts/scripts-pack.js"></script>  
 

 

 

This plugin will then create the filters in a row in the THEAD element of the table so add this if it is not already there.


 
<table id='demotable'>        
    <thead>
        <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>        
    </thead>
    <tbody>
        <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
        ....
    </tbody>
</table>
 

Hook in your table when the document is loaded.

 


 
$(document).ready(function() {
    $('#demotable).tableFilter();
});
 

Filter Types

Currently the picnet.jquery.tablefilter.js only supports two kinds of filters.  The first and default is 'text' which just produces a text box for context sensitive text matches.  The second is 'ddl', this produces a drop down list that allows the selection of a single item in that list.  To specify the filter type simply add "filter-type='ddl'" in the header cell of the required column.  I.e.


 
<table id='demotable'>        
    <thead>
        <tr><th>Col1</th><th>Col2</th><th filter-type='ddl'>Col3</th></tr>        
    </thead>
    <tbody>
        <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
        ....
    </tbody>
</table>
 

Options

We can also pass an options object to control some basic behaviours of the tableFilter. The current supported options are.

 

  • additionalFilterTriggers: These are additional input controls that will be hooked in to the filter code. Currently only type='text' and type='checkbox' controls are supported.
  • clearFiltersControls: Controls that onclick will clear all of the filter values (including additionalFilterTriggers).
  • matchingRow: function(state, tr, textTokens) { ... } These event will allow you to determine wether a matching row is actually correctly matching. This event will be called when a row is considered to have matched the filter, returning false will override this assumtion and hide the row from the results.
  • matchingCell: function(state, td, textTokens) { ... } This event behaves the same as the one above but allows more granular overriding capabilities. Returning false will again override the default match logic.

 

Example 1: Adding an additional whole row filter

Lets suppose that appart from having column filters we also want to have a quick find style filter that matches any cell in a row. To do this simply add the textbox to the additionalFilterTriggers array. TODO

 


 
<head>
    ...
    <script type="text/javascript">  
    $(document).ready(function() {
        // Initialise Plugin
        var options = {
            additionalFilterTriggers: [$('#quickfind')]
        };
        $('#demotable).tableFilter(options);
    });
    </script>
</head>
<body>
    Quick Find: <input type="text" id="quickfind"/>
    <table id='demotable'>        
        <thead>
            <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>        
        </thead>
        <tbody>
            <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
            ...
        </tbody>
    </table>
    ...
 

 

Example 2: Adding an additional checkbox filter

Let’s suppose that we have a Boolean column that we want to filter. The best way to do this will be to add a checkbox filter so let’s do this. We will keep the quick find filter to show how to have multiple additional filters. 

 


 
<head>
    ...
    <script type="text/javascript">
    $(document).ready(function() {
         // Initialise Plugin
        var options = {
            additionalFilterTriggers: [$('#onlyyes'), $('#quickfind')],
            matchingRow: function(state, tr, textTokens) {
                if (!state || state.id != 'onlyyes') { return true; }
                return state.value != true || tr.children('td:eq(2)').text() == 'yes';
            }
        };
         $('#demotable').tableFilter(options);
    });
<

p>    </script>
 
</head>
<body>    
    Only Show Yes: <input type="checkbox" id="onlyyes"/>
    <br/>
    Quick Find: <input type="text" id="quickfind"/>
    <table id='demotable'>        
        <thead>
            <tr><th>Col1</th><th>Col2</th><th>Boolean Col3</th></tr>        
        </thead>
        <tbody>
            <tr><td>Value 1</th><th>Value 2</th><th>yes</th></tr>        
            ...
        </tbody>
    </table>
    ...
 

 

Example 3: Clear Filters

Having a clear filters button comes in very handy, especially when you have a table with a larger number of columns. To add this functionality simply add your clickable control to the clearFiltersControls array. 

 


 
<head>
    ...
    <script type="text/javascript">
        $(document).ready(function() {        
            // Initialise Plugin
            var options = {
                clearFiltersControls: [$('#cleanfilters')],            
            };
            $('#demotable').tableFilter(options);
        });
    </script>
</head>
<body>
    <a id="cleanfilters" href="#">Clear Filters</a>
    <br/>    
    <table id='demotable'>        
        <thead>
            <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>        
        </thead>
        <tbody>
            <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
            ...
        </tbody>
    </table>
...
 

 

Known Limitations

  • More custom filter types needed (such as multi select lists, radio lists, etc)
  • No support for custom additional filters other than checkbox.

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd