How to Create an ASP.Net AJAX JavaScript Object Cache

If you have ever wanted an easy way to cache JavaScript objects and data in your client-side code just like you would when using the ASP.Net's Server side cache then read this article.

Monsur Hossain wrote a JavaScript LRU Cache which my partner found while we were searching for a JavaScript caching option.  As I am a big fan of the ASP.Net AJAX framework and the fact that I was extremely impressed with the feature rich cache written by Monsur, which was fashioned after the ASP.Net's cache. I decided to port the code to an ASP.Net AJAX component. 

ASP.Net AJAX extends JavaScript in some amazing ways which are beyond the scope of this article. However, ASP.Net AJAX does provide a framework to approach JavaScript in a more object oriented fashion.  One such feature of the framework is building classes based on the prototype design pattern which is my goal in porting Monsur's code.  You can find more information about the Least Recently Used caching algorithms at Wikipedia.  And if you are not currently using ASP.Net AJAX or have no plan to implement it I invite you to visit Monsur's site for the original implementation to which a link can be found at the end of this article. 

For those of you who do use ASP.Net AJAX and are looking for a JavaScript Object Cache read on as I describe the porting of the original which I call the JSOCache.

Start by creating a JSOCache.js file in your project.

JavaScript References, License Credit and Register Namespace

If you are developing with Visual Studio 2008 you will have the benefit of VS2008's JavaScript intelliSense.  Additionally for Licensing compliance and more importantly providing ample credit where it is due we will add the following to the beginning of our file JSOCache.js file.  I have added to this section a shameless plug referencing the effort of porting this to ASP.Net AJAX.  Lastly we will register the BehindTheCode.Web.UI namespace.

/// <reference name="MicrosoftAjax.js" />
/// <reference path="JSOCache.js" />

/*
MIT LICENSE
Copyright (c) 2007 Monsur Hossain (http://www.monsur.com)

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
/*

Ported to an ASP.Net AJAX   component by Joseph Caudill (http://www.behindthecode.net)

*/

Type.registerNamespace('BehindTheCode.Web.UI');

Create Enumerations and supporting Classes

CachePriority Enumeration

This enumeration will be used to reference the priority of the cached item.

BehindTheCode.Web.UI.CachePriority = function(){};
BehindTheCode.Web.UI.CachePriority.prototype = {
    /// <summary>
    ///     An easier way to refer to the priority of a cache item
    ///     Define an enumeration type and register it.
    /// </summary>
    Low: 1,
    Normal: 2,
    High: 4
}
BehindTheCode.Web.UI.CachePriority.registerEnum("BehindTheCode.Web.UI.CachePriority");

ItemExpireEventArgs Class

This event arguments class will be passed to the callback function of the CacheOptions when a cache item expires and a callback function has been provided.

BehindTheCode.Web.UI.ItemExpireEventArgs = function(key, value) {
    /// <summary>Adds a event handler for the tick event.</summary>
    /// <param name="key" type="Object">The key of the CacheItem that has expired.</param>
    /// <param name="value" type="Object">The expired item.</param>
    this._key = key;
    this._value = value; 
}
BehindTheCode.Web.UI.ItemExpireEventArgs.prototype = {

    dispose: function() {
    
        this._callback = null;
    },
    
    get_key : function() {
        /// <value type="Object">The key of the CacheItem that has expired.</value>
       return this._key;
    },
    set_key : function(value) {
        this._key = value;
    },
    
    get_value : function() {
        /// <value type="Object">The expired item.</value>
       return this._value;
    }
}
BehindTheCode.Web.UI.ItemExpireEventArgs.registerClass('BehindTheCode.Web.UI.ItemExpireEventArgs', Sys.EventArgs);

CacheOptions Class

This class manages priority and expiration options for a CacheItem as well as an expiration callback pointer.

BehindTheCode.Web.UI.CacheOptions = function(priority, expiration, expirationSliding, callback) {
    /// <summary>Represents the options for a CacheItem</summary>
    /// <param name="priority" type="BehindTheCode.Web.UI.CachePriority">
    ///     The priority to be given to the CacheItem. 
    ///     How important it is to leave this item in the cache.
    ///     You can use the values CachePriority.Low, .Normal, or 
    ///     .High, or you can just use an integer.  Note that 
    ///     placing a priority on an item does not guarantee 
    ///     it will remain in cache.  It can still be purged if 
    ///     an expiration is hit, or if the cache is full.
    /// </param>
    /// <param name="expiration" type="Date">The datetime when the CacheItem should expire</param>
    /// <param name="expiractionSliding" type="Number">
    ///     An integer representing the seconds since
    ///     the last cache access after which the item
    ///     should expire
    /// </param>
    /// <param name="callback" type="Function">
    ///     A function that gets called when the item is purged
    ///     from cache.  An ItemExpireEventArgs is passed as parameters to the callback function.
    /// </param>

    if (priority == null) priority = BehindTheCode.Web.UI.CachePriority.Normal;
    if (expiration != null) expiration = expiration.getTime();
    this._priority = priority;
    this._expirationAbsolute = expiration;
    this._expirationSliding = expirationSliding;
    this._callback = callback;
}
BehindTheCode.Web.UI.CacheOptions.prototype = {

    dispose: function() {
        this._callback = null;
    },
    
    get_priority : function() {
        /// <value type="String">
        ///     key of cached item
        /// </value>
        return this._priority;
    },
    set_priority : function(value) {
        this._priority = value;
    },
    
    get_expirationAbsolute : function() {
        /// <value type="Number">
        ///     
        /// </value>
       return this._expirationAbsolute;
    },
    set_expirationAbsolute : function(value) {
        this._expirationAbsolute = value;
    },
    
    get_expirationSliding : function() {
        /// <value type="Number">
        ///     An integer representing the seconds since
        ///     the last cache access after which the item
        ///     should expire
        /// </value>
       return this._expirationSliding;
    },
    set_expirationSliding : function(value) {
        this._expirationSliding = value;
    },
    
    get_callback : function() {
        /// <value type="Function">
        ///     A function that gets called when the item is purged
        ///     from cache.  An ItemExpireEventArgs is passed as parameters to the callback function.
        /// </value>
       return this._callback;
    },
    set_callback : function(value) {
        this._callback = value;
    }
}
BehindTheCode.Web.UI.CacheOptions.registerClass('BehindTheCode.Web.UI.CacheOptions', null, Sys.IDisposable);

CacheItem Class

The CacheItem will represent an item in the cache.  It will manage the key, cached object/value and optionally a CacheOptions defining how the JSOCache will manage the CacheItem.

BehindTheCode.Web.UI.CacheItem = function(key, value, options) {
    /// <summary>The CacheItem will represent an item in the cache.</summary>
    /// <param name="key" type="Object">Represents the unique key of the Cache Item</param>
    /// <param name="value" type="Object">The object or value to be cached</param>
    /// <param name="options" type="BehindTheCode.Web.UI.CacheOptions">The options by which the item will be managed</param>
    
    // Validate the key
    if ((key == null) || (value == ''))
        throw new Error("key cannot be null or empty");
        
    // Set the consturtor values
    this._key = key;
    this._value = value;
    
    // Set a generic CacheOptions if one was not provided
    if (options == null)
        options = new BehindTheCode.Web.UI.CacheOptions(BehindTheCode.Web.UI.CachePriority.Normal, null, null, null);
    this._options = options;
    this._lastAccessed = new Date().getTime();
}

BehindTheCode.Web.UI.CacheItem.prototype = {

    dispose: function() {
        this._options.dispose();
    },
    
    get_key : function() {
        /// <value type="Object">
        ///     key of cached item
        /// </value>
       return this._key;
    },
    set_key : function(value) {
        this._key = value;
    },
    
    get_value : function() {
        /// <value type="Object">
        ///     The cached object/value
        /// </value>
       return this._value;
    },
    set_value : function(value) {
        this._value = value;
    },
    
    get_options : function() {
        /// <value type="BehindTheCode.Web.UI.CacheOptions">
        ///     The cache options by which the cached item is managed
        /// </value>
       return this._options;
    },
    set_options : function(value) {
        this._options = value;
    },
    
    get_lastAccessed : function() {
        /// <value type="Date">
        ///     The date the item was lasted accessed from the cache
        /// </value>
       return this._lastAccessed;
    },
    set_lastAccessed : function(value) {
        this._lastAccessed = value;
    }      
}
BehindTheCode.Web.UI.CacheItem.registerClass('BehindTheCode.Web.UI.CacheItem', null, Sys.IDisposable);

Creating the JSOCache Class

Finally we get to the JSOCache which is the caching component. 

JSOCache Class

Constructor

In the constructor we will define and initialize our private fields.  We will provide an optional parameter of the max size for the cache, and create the items array and statistics object.

BehindTheCode.Web.UI.JSOCache = function(maxSize) {
    /// <summary>The JSOCache acts as a key/value cache which applies the LRU caching algorithm.</summary>
    /// <param name="maxSize" type="Number">Optional. The maximum size of the cache. Default is -1 unlimited.</param>
    BehindTheCode.Web.UI.JSOCache.initializeBase(this);
    
    maxSize = maxSize == undefined ? -1 : maxSize;

    // Properties
    this._maxSize = maxSize;
    this._fillFactor = .75;
    this._count = 0;
    this._stats = new Object();
    this._stats.hits = 0;
    this._stats.misses = 0;  
    
    // Variables
    this._items = new Array();
    this._purgeSize = Math.round(this._maxSize * this._fillFactor);
}

Start the Prototype and Define Public Methods

setItem Sets an item in the cache
getItem Retrieves an item from the cache. Returns null if the item was not found
clear Remove all items from the cache
toHtmlString Generates HTML List of items in the cache and the statistics of the cache
BehindTheCode.Web.UI.JSOCache.prototype = {

    dispose : function() {
        /// <summary>
        ///     Dispose of the componenet
        /// </summary>
        /// <returns />
        
        this._items = null;
        this._stats = null;
        
        BehindTheCode.Web.UI.JSOCache.callBaseMethod(this, 'dispose');
    },

    getItem : function(key) {
        /// <summary>
        ///     Retrieves an item from the cache.
        /// </summary>
        /// <param name="key" type="Object">
        ///     The key of the desired item in the cache
        /// </param>
        /// <returns>
        ///     Returns the matching item from the cache.
        ///     Returns null if the item doesn't exist
        ///     or it is expired.
        /// </returns>

        var item = this._items[key];
        
        if (item != null) {
            if (!this._isExpired(item)) {
                // if the item is not expired
                // update its last accessed date
                item.set_lastAccessed(new Date().getTime());
            } else {
                // if the item is expired, remove it from the cache
                this._removeItem(key);
                item = null;
            }
        }
        
        // return the item value (if it exists), or null
        var returnVal = null;
        if (item != null) {
            returnVal = item.get_value();
            this._stats.hits++;
        } else {
            this._stats.misses++;
        }
        return returnVal;
    },

    setItem : function(key, value, options) {
        /// <summary>
        ///     Sets an item in the cache
        /// </summary>
        /// <param name="key" type="Object">
        ///     The unique key that will represent the object
        /// </param>
        /// <param name="value" type="Object">
        ///     The object to cache
        /// </param>
        /// <param name="options" type="BehindTheCode.Web.UI.CacheOptions">
        ///     The options by which the item will be managed.
        /// </param>
        /// <returns />    

        // add a new cache item to the cache
        if (this._items[key] != null)
            this._removeItem(key);
        this._addItem(new BehindTheCode.Web.UI.CacheItem(key, value, options));
        
        // if the cache is full, purge it
        if ((this._maxSize > 0) && (this._count > this._maxSize)) {
            this._purge();
        }
    },
    
    clear : function() {
        /// <summary>
        ///     Remove all items from the cache
        /// </summary>
        /// <returns />  
        
        // loop through each item in the cache and remove it
        for (var key in this._items) {
          this._removeItem(key);
        }  
    },

    toHtmlString : function() {
        /// <summary>
        ///     Generates HTML List of items in the cache.
        /// </summary>
        /// <returns> 
        ///     HTML
        /// </returns>      
        var returnStr = this._count + " item(s) in cache<br /><ul>";
        for (var key in this._items) {
            var item = this._items[key];
            try {
                returnStr = returnStr + "<li>" + item.get_key().toString() + " = " + (item.get_value().toHtmlString != undefined ? item.get_value().toHtmlString() : item.get_value().toString()) + "</li>";
            } catch(e) {
                returnStr = returnStr + "<li>" + item.get_key().toString() + " = " + item.get_value().toString() + "</li>";
            }
        }
        returnStr = returnStr + "</ul>";
        returnStr = returnStr + "<br />";
        returnStr = returnStr + "<br />";
        returnStr = returnStr + "<b>Stats</b><br />";
        returnStr = returnStr + "Hits = " + this._stats.hits + "<br />";
        returnStr = returnStr + "Misses = " + this._stats.misses + "<br />";
        return returnStr;
    },

Define Private Methods

addItem Add an item to the cache
removeItem Remove an item from the cache, call the callback function (if necessary)
isExpired Checks an items expiration state
purge Remove old elements from the cache based upon the associated options
    _purge : function() {
        /// <summary>
        ///     Remove old elements from the cache based upon the associated options
        /// </summary>
        /// <returns />     
             
        var tmparray = new Array();
        
        // loop through the cache, expire items that should be expired
        // otherwise, add the item to an array
        for (var key in this._items) {
            var item = this._items[key];
            if (this._isExpired(item)) {
                this._removeItem(key);
            } else {
                tmparray.push(item);
            }
        }
        
        if (tmparray.length > this._purgeSize) {

            // sort this array based on cache priority and the last accessed date
            tmparray = tmparray.sort(function(a, b) { 
                if (a.get_options().get_priority() != b.get_options().get_priority()) {
                    return b.get_options().get_priority() - a.get_options().get_priority();
                } else {
                    return b.get_lastAccessed() - a.get_lastAccessed();
                }
            });
            
            // remove items from the end of the array
            while (tmparray.length > this._purgeSize) {
                var ritem = tmparray.pop();
                this._removeItem(ritem.get_key());
            }
        }
    },
    
    _addItem : function(item) {
        /// <summary>
        ///     Add an item to the cache
        /// </summary>
        /// <param name="item" type="BehindTheCode.Web.UI.CacheItem">
        ///     The item to add to the cache
        /// </param>
        /// <returns /> 
        
        this._items[item.get_key()] = item;
        this._count++;
    },

    _removeItem : function(key) {
        /// <summary>
        ///     Remove an item from the cache, call the callback function (if necessary)
        /// </summary>
        /// <param name="key" type="Object">
        ///     The key of the object to be removed
        /// </param>
        /// <returns /> 
        
        var item = this._items[key];
        delete this._items[key];
        this._count--;
        
        // if there is a callback function, call it at the end of execution
        if (item.get_options().get_callback() != null) {
            var callback = function() {
                
                item.get_options().get_callback()(this, new BehindTheCode.Web.UI.ItemExpireEventArgs(item.get_key(), item.get_value()));
            }
            setTimeout(callback, 0);
        }
    },
    
    _isExpired : function(item) {
        /// <summary>
        ///     Checks an items expiration state
        /// </summary>
        /// <param name="item" type="Object">
        ///     The item to check
        /// </param>
        /// <returns> 
        ///     Returns true if the item should be expired based on its expiration options
        /// </returns>  
        var now = new Date().getTime();
        var expired = false;
        if ((item.get_options().get_expirationAbsolute()) && (item.get_options().get_expirationAbsolute() < now)) {
            // if the absolute expiration has passed, expire the item
            expired = true;
        } 
        if ((expired == false) && (item.get_options().get_expirationSliding())) {
            // if the sliding expiration has passed, expire the item
            var lastAccess = item.get_lastAccessed() + (item.get_options().get_expirationSliding() * 1000);

            if (lastAccess < now) {
                expired = true;
            }
        }
        return expired;
    },

Define Properties

maxSize The max size of the cache
fillFactor The factor to use when determining the size at which to purge items from the cache
count Gets the current count of items in the cache
stats Stats of the cache
    get_maxSize : function() {
        /// <value type="Number" integer="true">
        ///     The max size of the cache
        /// </value>
       return this._maxSize;
    },
    set_maxSize : function(value) {
        if (this._maxSize != value) {
            this._maxSize = value;
            this.raisePropertyChanged('MaxSize');
        }
    },
    
    get_fillFactor : function() {
        /// <value type="Number" integer="true">
        ///     The factor to use when determining the size at which to purge items from the cache
        /// </value>
       return this._fillFactor;
    },
    set_fillFactor : function(value) {
        if (this._fillFactor != value) {
            this._fillFactor = value;
            this.raisePropertyChanged('FillFactor');
        }
    },
    
    get_count : function() {
        /// <value type="Number" integer="true">
        ///     Gets the current count of items in the cache
        /// </value>
       return this._count;
    },
    set_count : function(value) {
        if (this._count != value) {
            this._count = value;
            this.raisePropertyChanged('Count');
        }
    },
    
    get_stats : function() {
        /// <value type="Object">
        ///     Stats of the cache
        /// </value>
       return this._stats;
    },
    set_stats : function(value) {
        if (this._stats != value) {
            this._stats = value;
            this.raisePropertyChanged('Stats');
        }
    }     

Close the Prototype, Register Class and Call Notify Script Loaded

       
}
BehindTheCode.Web.UI.JSOCache.registerClass('BehindTheCode.Web.UI.JSOCache', Sys.Component);

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

Download the Code

JSOCache.js (17.85 kb) - ASP.NET AJAX Component

Monsur Hossain original implementation as Javascript LRU Cache

Comments

Strange... I just stumbled on your website by looking for 'cheap laptop' on Bing. But I haven't found any articles about that subject on here?

Jun 24 Colby Zolman

I found a link to your web site on a Currency trading blog, and I must say... Your web site is a lot better. You make the subject easier to understand, thanks

Jun 26 Andrew Pelt

Howdy there,just discovered your web-site when i google something and wonder what webhosting do you use for your website,the speed is more faster than my website, i really need to know it.will back to check it out,i appreciate it!

Not a serious reader, but I unquestionably didn't mind reading this. My momma constantly told me to learn more; stunning what you can acquire from reading.

Jun 29 abercrombie

I be able to not grant on all, but the topic is really exciting. Congratulations!

Jul 04 Elmer Blohm

I just signed up to your news feed after reading this piece! Can you publish more regarding the topic in future posts?

A moderately good read, at any rate up to where I read too. I'm quite confident your CSS file is messed up. I had the identical problem on my blog a while back. Try playing around with the CSS. Your columns look wrong in Mozilla (for me at least).

Jul 05 Becky Poque

Hello webmaster can I use some of the information from this post if I provide a link back to your site?

Jul 07 Becky Poque

I saw a news item concerning that on television last night. Thanks for the more in-depth explanation

I watched something regarding this on television yesterday. Thanks for the more in-depth explanation

Can I quote you in my report for school?

amazon coupon codes

Lenen Zonder BKR Toetsing Lenen zonder BKR toetsing stijgt in populariteit op het Internet. Veel mensen met een zogeheten BKR notatie, die toch geld willen lenen zijn op zoek naar ...

I had a web site like this once, but it got spammed so bad I had to close it. You seem to have a better spam filter! Kudos!

Jul 25 migraine

Migraine is hoofdpijn die in aanvallen komt. De hoofdpijn komt plotseling op, soms midden in de nacht zodat u er wakker van wordt. De pijn zit meestal aan

Jul 27 cash loans

The most wasted of all days is one without laughter.

Jul 28 migraine

Leven met migraine: hoe ga je met je migraine om en wat is de beste behandeling?

Aug 01 lenen

U wilt geld lenen zonder BKR toetsing? De opties hiervoor worden groter, kijk verder en ontdek hoe u wél geld kunt lenen, snel & eenvoudig.

Aug 01 lenen

Lenen Zonder BKR Toetsing Lenen zonder BKR toetsing stijgt in populariteit op het Internet. Veel mensen met een zogeheten BKR notatie, die toch geld willen lenen zijn op zoek naar ...

Aug 05 Seattle Limo

Thank you so much for this!  I havent been this thrilled by a blog for a LONG time!  Youve got it, whatever that means in blogging.  HaHa.  Youre definitely someone that has something to say that people need to hear.  Keep up the great work.  Keep on inspiring the people!

Awesome post! I have read many other posts in your blog and many of them are really great to read! I think i haven't found many such good blogs.

I have therefore bookmarked your blog in my delicious account as i would love to visit again!

I have been to your blog before! There are many other blogs still you have many other posts which are really interesting!

Are there many other interesting posts coming in future?


Aug 07 Cam Chat

lol a couple of the reviews bloggers write are just silly and unrelated, sometimes i wonder whether they at all read the post before writing or whether they merely look at the subject of the post and write the very first thought that comes to their minds. But it is nice to find a fresh commentary every now and then in contrast to the exact same, traditional blog garbage which I oftentimes notice on the blogs. Cheers

Aug 11 hypotheek

Hypotheken? Heel veel hypotheek informatie: verschillende hypotheekvormen, hypotheekrentes, nationale hypotheek garantie, hoe een hypotheek te vergelijken.

Aug 11 hypotheek

Bereken zelf uw hypotheek. Hypotheek berekenen? Maak snel een indicatieve berekening van het maximale leenbedrag van uw hypotheek.

Aug 16 Tote

You Know What? http://www.bagsok.com Keep to be In Vogue for 2010 Spring Gwen Stefani’s http://www.bagsok.com/collection/124 , Take a Look and Make a Comment http://www.bagsok.com/Tote Gifts for Bachelors

Aug 16 cam sex

You may have not intended to do so, but I think you have managed to express the state of mind that a lot of people are in. The sense of wanting to help, but not knowing how or where, is something a lot of us are going through.

Hello webmaster can I use some of the information from this post if I provide a link back to your site?

Incredibly good evaluation within the subject matter. I've to perform with specialist laptop computers, much more accurately, I repair it and also set up the software package. I'm usually seeking for blogs like this, where We've great suggestions and current information on the subject.

i know this is not exactly on topic, but i have a blog using the blogengine platform as well and i'm having issues with my comments displaying. is there a setting i am forgetting? maybe you could help me out? thank you.

Tremendous blog. I'll have to remember to check back again.

Aug 21 air jordan 9

I like your professional looking blog. It is very neat and tidy.

Always  interesting  to  follow  an  different   blog .  Thank you  for the  post .

Very interesting, would like to take another look at this.

Aug 22 Cykoria kawa

Interesting article. I really enjoyed it and have some thoughts.

Thank you for the article. I almost passed your website up in Google but now I'm glad I clicked on through and got to examine it. I'm definitely better informed now. I'll be telling my buddies about your site. They'll for sure enjoy the heck out of what I just read too. LOL. --Diane

By visiting your webpage, the first impression for me is strong. I can’t imagine when and why you share this great topic but don’t spread it with social bookmarking. This information can be published as reference in online journal, or even in press release site. An early improvement in your site is great, can give us more time in your website. Would you mind if I capture several screenshot as my collection, because I’ve joined several researches? General purpose for me is to tell you about this discussion. My critical question for us is the resource that you have used to manage this site. In order to make great discussion, you are great because you post new topic in several areas. But, I suggest in giving personal opinion, please refer to big or authority sites, I am sure you will be fine in giving past or future experiences. In my environment, I am sure your capability to enrich people can be strong advantage for your future.

Aug 24 harry

<a href="www.capitalbuildcare.co.uk">builders bournemouth</a>

Submitting articles to article directories makes for a good way to make your website a success. While

Aug 25 Sex Chat

I was very pleased to find this site.I wanted to thank you for this great read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.

Have you thought about adding some sort of bookmarking buttons or links to your website?

kinda get tired of it all to be honest. its just irratating. i am tired of trying these paid networks and getting nothing but spam. seriously. but i guess it runs with the territory, i won't be paying for a dating site though.

Thanks for writing this I'll tell my partner and see what she thinks.

Aug 25 Leonida Prats

Thanks For Making This Website. Awesome Stuff!

Aug 26 fsbo

I just stumbled on your blog when I was lookng on google. I have to say that the information here was the most complete that I found anywhere. I am definitely bookmarking this to come back and read later.

What's happenin, just wanted to drop by and let you know that I don't agree with you. Maybe it's just a personal bias. We has had an Amerigroup Coroporation Mortgage for over the past 5 years and we have had nothing but good expericences with amerigroup. Amerigroup mortgage is veteran owned and operated and is a memeber of the bbb. If you don't agrree I bet you don't have any good comeback.

Pretty good post. I just stumbled upon your blog and wanted to say that I have really enyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon

To begin with ,you have  picked  a  really   beautiful   wordpress theme .  You gave me an idea  for a future  blog  that i  plan  to  create .  In addition  ,i  honestly  enjoy most of  your   posts  and your  unique  point of view. Thanks  

Aug 27 cam girls

I was very delighted to find this site.I wanted to thank you for this amazing read!! I definitely enjoyed every little bit of it and I have you bookmarked to check out new stuff you post.

Aug 27 digital radio

Thank you for the entry. I almost passed your we site up in Ask but now I'm glad I clicked on through and got to read it. I'm definitely a little better informed now. I know quite a few people that will want to check it out. They'll for sure enjoy the heck out of what I just read too. LOL. --Matthew

Thanks for the great post. I purchase viagra online and it's not that expensive.

coming up with new articles is somewhat boring, it is ultimately worth the time which you spend working.

Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming. Thanks again and good luck!

Aug 28 Terrell Hudok

do you have an rss feed? I want to add it to my reader but I can't find it...

Wow. This is pretty accurate overall but I think your grammar could definitely use some work.

Aug 29 chat nude

I cannot seem to locate your syndication feed, I would like to get more your posts.

What's the difference between a car and a golf ball? Tiger can drive a ball 400 yards.

Aug 31 air jordan 16

I'm a big blog enthusiast and with all of the blogs out there now, very few stand out like yours does. Your blog caught my eye and I thought that I would post to let you know that.

Aug 31 Totally

Nice, just to let you know the post isnt showing up properly on my iphone - I think there is a plugin you can grab that takes care of that now.

Why didnt I think about this?  I hear exactly what youre saying and Im so happy that I came across your blog.  You really know what youre talking about, and you made me feel like I should learn more about this.  Thanks for this; Im officially a huge fan of your blog.

Most African-American artists market and exhibit in the African-American community. Successful Black art festivals and expos, where artists sell and exhibit, recognize the importance of marketing to this special community. It is in this community where the strength and the value of African-American art begins. It is this community that has provided the foundation for the Blackstream Renaissance. Read more - http://www.octobergallery.com

Aug 31 blonde jokes

nice blog! keep the good work!

Just came across this post through Bing. Really well written. and I like the layout of your site. From where did you get it?

Thanks for this great post. The info I have gained from your blog is truly inspiring.

This is very interesting. Keep blogging the way you do.

When I firstly saw your web, I've been around in many pages that I'll use to get my final assignment. I googling with my short idea in my brain, and then I met with useful article. I hope you can give several advices to me, because your knowledge is great, it can help many students to get great score in every task or project. If you don't mind, I will contact you to make short discussion for my project. I write my short comment for you to give support for your site; my friends had used your article as reference in specific term and condition. After that, my friends are satisfied with your article (I've given reference to read many pages in your site). We can make other discussion later, because it will be worth to me. Thanks in advance, hope you contact me, so we can broaden our knowledge together.

I'm getting a javascript error, is anyone else?

don't spend all the day in front of your computer, go out, exercise, go to the gym twice a week...

I'm getting a browser error, is anyone else?

This was a really informative post, Ive been searching for the last frew pieces for a report. The search is over!

Sep 01 used netbooks

I'm getting a javascript error, is anyone else?

When are you going to post again? You really entertain  a lot of people!

don't spend all the day in front of your computer, go out, exercise, go to the gym twice a week...

Hello everyone. I was just surfing the Internet for fun and came upon your website. Terrific post. Thanks a lot for sharing your experience! It is good to know that some people still put in an effort into managing their websites. I'll be sure to check back from time to time.

Thanks for the post. I just about passed your we site up in Google but now I'm glad I clicked the link and got to examine it. I'm definitely better informed now. I'll be sharing your site with some other people I know. They'll for sure enjoy the heck out of what I just read too. LOL. --Fuller

Sep 01 Eugene

I like the site layout . How was it made. It is so sweet!

Sep 01 Eugene

A cool blog post right there mate . Thank you for, posting .

I'm getting a javascript error, is anyone else?

Sep 01 Eugene

If you could email me with any tips about how you made this website look this cool , I would appreciate it.

Sep 01 Eugene

Amazing article, thank you, I will visit again later!

Brilliant, cheers, I will visit again now!

I adore this site layout . How do you make it. It is really sweet!

This really solved my problem, thank you!

I like the website layout ! How do you make it? It is very sweet!

Sep 01 sc2 hacks

When are you going to post again? You really entertain  a lot of people!

Can you email me with some hints on how you made this blog site look this good , I would appreciate it!

I'm getting a browser error, is anyone else?

Sep 01 zygor

Wow. This blog is cool. How did you  make it look like this ?

Sep 01 Health Advice

This really answered my problem, thank you!

Sep 01 Stock Picks

Oh man! This blog is amazing. How did you  make it look like this ?

This blog is extremely good. How was it made .

Can you message me with any pointers about how you made your blog look this awesome , I would appreciate it.

Just discovered this site through Yahoo, what a pleasant shock!

Comfortabl y, the article is in reality the sweetest on this notable topic. I concur with your conclusions and also can eagerly look forward to your coming updates. Simply just saying thanks will certainly not just be enough, for the fantasti c clarity in your writing. I definitely will perfect away grab your rss feed to stay privy of any updates. De lightful work and much success in your business endeavors!

Sep 02 gift idea

try to change your template, there are some great ones...

Wow, thanks for blogging about this content. I'm a real enthusiast and delight in reading your weblog. Believe it or not it's typically rather a real pain in the neck to come across this information created with any real sense of quailty like it is here. Thank You.

How are you, You should probably know that this blog is not showing up properly on my Motorola Slvr. Anyway, I’m now browsing this page on my pc, Thank you

Sep 03 ETFs

any plan to update this blog?

Sep 03 Jillane

Simply want to say your article is as tonishing. The clarity in your post is simply striking and i can assume you are an expert on this field. Well with your permission allow me to grab your rss feed to keep up to date with forthcoming post. Thanks a million and please keep up the effective work.

informative post

Sep 04 gay movies

tgae.

Sep 04 Coach Shoes

I appreciate the time you took to post this. I am very interested in this. Thank you for your well written post, In addition to my enthusiasm.

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Page List

    Calendar

    <<  September 2010  >>
    MoTuWeThFrSaSu
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    View posts in large calendar