(function($){

  var _stablizer = $( '<div style="position:absolute;visibility:hidden;"></div>' );

  // GET returns value by key
  // SET returns true if hash was set (if different from current)
  $.hash = function ( value ) {
    
    var hash = (document.location.hash + '');
    
    // getter
    if ( arguments.length === 0 ) {
      return hash.replace( /^#/, '' );
    }
    
    // setter
    value = value.replace( /^#/, '' );

    // no need to set the hash, return false to indicate that nothing was done
    if ( hash === value ) {
      return false;
    }
  
    // DOM has a node with this id?
    var node = document.getElementById( value );

    if ( node ) {
      node.id = '';
      _stablizer
        .attr( 'id', value )
        .appendTo( document.body )
        .css( 'top', $.scroll().top + 'px' );
    }

    document.location.hash = value;

    if ( node ) {
      _stablizer[0].parentNode.removeChild( _stablizer[0] );
      node.id = value;
    }
    
    return true;  // return true to indicate that change occurend
    
  }
  
  $.hashvar = function ( key, val ) {
    
    // break down all values into a dict
    var hash = $.hash(), obj = {};

    if ( hash ) {
      $.each(hash.split( '&' ), function ( i, bit ) {
        var m = /^([^=]+)(?:=(.*))?$/.exec( bit );
        if ( m ) {
          obj[ decodeURIComponent(m[1]) ] = decodeURIComponent(m[2]||'');
        }
      });
    }

    // no paramter = return a dict of all values
    if ( arguments.length === 0 ) {
      return obj;
    }

    // single string parameter = get value by key
    else if ( arguments.length === 1 && typeof key === 'string' ) {
      return obj[ key ];
    }

    // two parameters = assign a value by key
    else if ( arguments.length > 1 ) {
      obj[ key ] = val;
    }

    // single object parameter = merge in a dict of parameters
    else if ( arguments.length === 1 && typeof key === 'object' ) {
      obj = $.extend( obj, key );
    }

    // serialize the object into a string
    var a = [];
    for ( key in obj ) {
      if ( key && obj.hasOwnProperty( key ) ) {
        a.push( encodeURIComponent( key ) + '=' + encodeURIComponent( obj[key] ) );
      }
    }
    return $.hash( a.join('&') );
    
  }

})(jQuery);