Liomans Blog

42 ist die Antwort – aber wie lautet die Frage?


hovercard

Gravatar Hovercards einbinden

| 0 comments

Schon länger ist der Dienst Gravatar in diversen Blogs eingebaut. Sowohl bei wordpress.com als auch in vielen Privaten. Hat man also ein Bild mit einer Emailadresse verknüpft erscheint es überall wo man kommentiert (und der Dienst eingebunden ist).  Seit einiger Zeit konnte man ein Erweitertes Profil gestalten und ein klick auf das Bild neben einem Kommentar führte zu diesem. Wenn man also möchte kann man so sein Facebook-Profil – Twitterstream oder andere Konten bekannt machen und verbreiten. Nun gibt es die Möglichkeit eben jene Informationen aus dem Profil schon beim mit der Maus über das Bild gehen sich kompakt anzeigen zu lassen.

Das Ergebnis sieht man oben im Bild und eingebaut ist es in ein Theme mit wenigen Klicks.

So wird es eingebaut.

Einfach in die functions.php des Themes folgende Zeile einfügen:

  1. wp_enqueue_script( 'gprofiles', 'http://s.gravatar.com/js/gprofiles.js', array( 'jquery' ), 'e', TRUE );
wp_enqueue_script( 'gprofiles', 'http://s.gravatar.com/js/gprofiles.js', array( 'jquery' ), 'e', TRUE );

Möchte man das ganze noch mehr gestalten muss man sich ein kleines Plugin schreiben. Eine genaue Anleitung dazu gibt es hier. Daher habe ich auch die oben beschriebene Anleitung.

Verbessern

In den Kommentaren hat Thomas Scholz geschrieben, dass das Skript erstens groß und zweitens mit einem WordPresstracker versehen ist. Möchte man das umgehen, kann man sich das Skript herunterladen und bearbeiten. Ohne Tracker sieht es dann so aus (Wenn ich alles erwischt habe):

  1. if ( \undefined\ == typeof( console ) ) {
  2.  console = { \log\: function(str){}, \debug\: function(str){} };
  3. }
  4.  
  5. var Gravatar = {
  6.  /* All loaded profiles, keyed off ghash */
  7.  \profile_stack\: {},
  8.  
  9.  // Mapping of ghash to the \currently waiting\ dom_id of where to render it
  10.  \profile_map\: {},
  11.  
  12.  /* Timeouts for hovering over and off Gravatar images */
  13.  \overTimeout\: false,
  14.  \outTimeout\: false,
  15.  
  16.  /* If true, show_card will bail */
  17.  \stopOver\: false,
  18.  
  19.  /* The img element, hash and ID of the Gravatar that is being hovered over */
  20.  \active_grav\: false,
  21.  \active_hash\: false,
  22.  \active_id\: false,
  23.  
  24.  /* The clone of the Gravatar img element that is being hovered over. */
  25.  \active_grav_clone\: false,
  26.  
  27.  /* Callback function for once a profile is loaded */
  28.  \profile_cb\: null,
  29.  
  30.  /* Wating throbber */
  31.  \throbber\: null,
  32.  
  33.  /* Has a custom background image been added to the card? */
  34.  \has_bg\: false,
  35.  \disabled\:false,
  36.  
  37.  \mouseOut\: function(e) {
  38.  e.stopImmediatePropagation();
  39.  Gravatar.stopOver = true;
  40.  
  41.  // console.debug( ':set out' );
  42.  Gravatar.outTimeout = setTimeout( function() {
  43.  // console.debug( ':do out' );
  44.  Gravatar.hide_card();
  45.  }, 300 );
  46.  },
  47.  
  48.  \init\: function() {
  49.  var ca = document.cookie.split( ';' ), i, c;
  50.  for ( i = 0; i < ca.length; i++ ) {
  51.  c = ca[i];
  52.  while ( ' ' == c.charAt(0) ) {
  53.  c=c.substring( 1, c.length );
  54.  }
  55.  if ( 0 == c.indexOf( 'nohovercard=1' ) ) {
  56.  return;
  57.  }
  58.  }
  59.  
  60.  /* Locate all Gravatar images and attach profile links to them. */
  61.  this.attach_profiles();
  62.  
  63.  /* Add CSS */
  64.  this.add_card_css();
  65.  
  66.  /* Find and show a hovercard when hovering over a Gravatar. */
  67.  jQuery('img.grav-hashed').live( 'mouseenter.gravatar mouseleave.gravatar', function(e) {
  68.  if ( Gravatar.disabled ) { return; }
  69.  e.preventDefault();
  70.  e.stopPropagation();
  71.  
  72.  if ( 'mouseleave' == e.type || 'mouseout' == e.type ) {
  73.  // console.debug( 'grav out' );
  74.  return Gravatar.mouseOut.call( this, e );
  75.  }
  76.  
  77.  Gravatar.stopOver = false;
  78.  
  79.  // console.debug( 'grav enter' );
  80.  /* Get and store the hash and ID for the active Gravatar */
  81.  Gravatar.active_id = jQuery(this).attr('id');
  82.  Gravatar.active_hash = Gravatar.active_id.split('-')[1];
  83.  
  84.  Gravatar.untilt_gravatar();
  85.  
  86.  // console.debug( ':clear over1' );
  87.  clearTimeout( Gravatar.overTimeout );
  88.  
  89.  // No profile data - see fetch_profile_error
  90.  if ( false === Gravatar.profile_map[ 'g' + Gravatar.active_hash ] ) {
  91.  return;
  92.  }
  93.  
  94.  // console.debug( ':clear out' );
  95.  clearTimeout( Gravatar.outTimeout );
  96.  
  97.  Gravatar.tilt_gravatar();
  98.  Gravatar.fetch_profile_by_hash( Gravatar.active_hash, Gravatar.active_id );
  99.  // console.debug( ':set over' );
  100.  Gravatar.overTimeout = setTimeout( function() {
  101.  Gravatar.show_card();
  102.  }, 600 );
  103.  });
  104.  
  105.  /* Maintain hovercard state when rolling over a hovercard or cloned image */
  106.  jQuery('div.gcard, img.grav-clone').live( 'mouseenter.gravatar mouseleave.gravatar', function(e) {
  107.  if ( Gravatar.disabled ) { return; }
  108.  e.preventDefault();
  109.  e.stopPropagation();
  110.  
  111.  if ( e.type == 'mouseenter' || e.type == 'mouseover' ) {
  112.  Gravatar.stopOver = false;
  113.  
  114.  // console.debug( 'clone enter' );
  115.  // console.debug( ':clear out2' );
  116.  clearTimeout( Gravatar.outTimeout );
  117.  } else {
  118.  // console.debug( 'clone out' );
  119.  Gravatar.mouseOut.call( this, e );
  120.  }
  121.  });
  122.  
  123.  /* Cancel a hovercard when scrolling. */
  124.  jQuery(window).bind( 'scroll', function() {
  125.  if ( !Gravatar.active_hash.length )
  126.  return;
  127.  
  128.  Gravatar.hide_card();
  129.  });
  130.  },
  131.  
  132.  \attach_profiles\: function( container ) {
  133.  /* Locate all Gravatar images and add profiles to them */
  134.  container = \undefined\ == typeof( container ) ? \body\ : container;
  135.  
  136.  jQuery( container + ' img[src*=gravatar.com/avatar]' ).not( '.no-grav, .no-grav img' ).each( function() {
  137.  hash = Gravatar.extract_hash( this );
  138.  
  139.  /* Add unique ID to image so we can reference it directly */
  140.  uniq = 0;
  141.  if ( jQuery( '#grav-' + hash + '-' + uniq ).length ) {
  142.  while ( jQuery( '#grav-' + hash + '-' + uniq ).length )
  143.  uniq++;
  144.  }
  145.  
  146.  /* Remove the hover titles for sanity */
  147.  var g = jQuery( this ).attr( 'id', 'grav-' + hash + '-' + uniq ).attr( 'title', '' ).removeAttr( 'title' );
  148.  if ( g.parent( 'a' ).length )
  149.  g.parent( 'a' ).attr( 'href', 'http://gravatar.com/' + hash ).attr( 'title', '' ).removeAttr( 'title' );
  150.  
  151.  g.addClass('grav-hashed');
  152.  });
  153.  },
  154.  
  155.  \show_card\: function() {
  156.  if ( Gravatar.stopOver ) {
  157.  return;
  158.  }
  159.  
  160.  dom_id = this.profile_map[ 'g' + Gravatar.active_hash ];
  161.  
  162.  // Close any existing cards
  163.  jQuery( '.gcard' ).hide();
  164.  
  165.  // Bail if we're waiting on a fetch
  166.  if ( 'fetching' == this.profile_stack[ 'g' + Gravatar.active_hash ] ) {
  167.  Gravatar.show_throbber();
  168.  this.listen( Gravatar.active_hash, 'show_card' );
  169.  // console.log( 'still fetching ' + hash );
  170.  return;
  171.  }
  172.  
  173.  // If we haven't fetched this profile yet, do it now and do this later
  174.  if ( 'undefined' == typeof( this.profile_stack[ 'g' + Gravatar.active_hash ] ) ) {
  175.  Gravatar.show_throbber();
  176.  this.listen( Gravatar.active_hash, 'show_card' );
  177.  // console.log( 'need to start fetching ' + hash + '@' + dom_id );
  178.  this.fetch_profile_by_hash( Gravatar.active_hash, dom_id );
  179.  return;
  180.  }
  181.  
  182.  Gravatar.hide_throbber();
  183.  
  184.  // console.log( 'show_card: hash: ' + hash + ', DOM ID: ' + dom_id );
  185.  
  186.  // No HTML? build it
  187.  if ( !jQuery( '#profile-' + this.active_hash  ).length )
  188.  this.build_card( this.active_hash, this.profile_stack[ 'g' + this.active_hash ] );
  189.  
  190.  this.render_card( this.active_grav, 'profile-' + this.active_hash );
  191.  },
  192.  
  193.  \hide_card\: function() {
  194.  // console.debug( ':clear over3' );
  195.  clearTimeout( Gravatar.overTimeout );
  196.  
  197.  /* Untilt the Gravatar image */
  198.  this.untilt_gravatar();
  199.  grav_resize.current_image = false
  200.  jQuery( 'div.gcard' ).filter( '#profile-' + this.active_hash ).fadeOut(120, function() {
  201.  jQuery('img.grav-large').stop().remove();
  202.  } ).end().not( '#profile-' + this.active_hash ).hide();
  203.  },
  204.  
  205.  \render_card\: function( grav, card_id ) {
  206.  var card_el = jQuery( '#' + card_id  ).stop();
  207.  
  208.  // console.log( 'render_card for ' + grav_id + ', ' + card_id );
  209.  // Change CSS positioning based on where grav_id is in the page
  210.  var grav_el  = grav;
  211.  var grav_pos = grav_el.offset();
  212.  
  213.  if ( null != grav_pos ) {
  214.  var grav_width  = grav_el.width();
  215.  var grav_height = grav_el.height();
  216.  var grav_space  = 5 + ( grav_width * .4 );
  217.  
  218.  var card_width  = card_el.width();
  219.  var card_height = card_el.height();
  220.  if ( card_width == jQuery(window).width() ) {
  221.  card_width  = 400;
  222.  card_height = 200;
  223.  }
  224.  
  225.  /*
  226.  console.log( grav_pos );
  227.  console.log( 'grav_width = ' + grav_width + \\n\ +
  228.  'grav_height = ' + grav_height + \\n\ +
  229.  'grav_space = ' + grav_space + \\n\ +
  230.  'card_width = ' + card_width + \\n\ +
  231.  'card_height = ' + card_height + \\n\ );
  232.  */
  233.  
  234.  /* Position to the right of the element */
  235.  var left = grav_pos.left + grav_width + grav_space;
  236.  var top = grav_pos.top;
  237.  var grav_pos_class = 'pos-right';
  238.  
  239.  /* Position to the left of the element if space on the right is not enough. */
  240.  if ( grav_pos.left + grav_width + grav_space + card_width > jQuery(window).width() + jQuery(window).scrollLeft() ) {
  241.  left = grav_pos.left - ( card_width + grav_space );
  242.  grav_pos_class = 'pos-left';
  243.  }
  244.  
  245.  /* Reposition the card itself */
  246.  var top_offset = grav_height * .25;
  247.  jQuery( '#' + card_id ).removeClass( 'pos-right pos-left' ).addClass( grav_pos_class ).css( { 'top': ( top - top_offset ) + 'px', 'left': left + 'px' } );
  248.  
  249.  /* Position of the small arrow in relation to the Gravatar */
  250.  var arrow_offset = ( grav_height / 2 );
  251.  if ( arrow_offset > card_height )
  252.  arrow_offset = card_height / 2;
  253.  if ( arrow_offset > ( card_height / 2 ) - 6 )
  254.  arrow_offset = ( card_height / 2 ) - 6;
  255.  if ( arrow_offset > 53 )
  256.  arrow_offset = 53; // Max
  257.  if ( this.has_bg )
  258.  arrow_offset = arrow_offset - 8;
  259.  if ( arrow_offset < 0 )
  260.  arrow_offset = 0; // Min
  261.  var css = {
  262.  'height': ( ( grav_height * 1.5 ) + top_offset ) + 'px'
  263.  };
  264.  if ( 'pos-right' == grav_pos_class ) {
  265.  css['right'] = 'auto';
  266.  css['left'] = '-7px';
  267.  css['background-position'] = '0px ' + arrow_offset + 'px';
  268.  } else {
  269.  css['right'] = '-10px';
  270.  css['left'] = 'auto';
  271.  css['background-position'] = '0px ' + arrow_offset + 'px';
  272.  }
  273.  jQuery( '#' + card_id + ' .grav-cardarrow' ).css( css );
  274.  }
  275.  
  276.  card_el.stop().css( { opacity: 0 } ).show().animate( { opacity: 1 }, 150, 'linear', function() {
  277.  jQuery( this ).stop();
  278.  grav_resize.init( card_id );
  279.  grav_gallery.init( card_id );
  280.  });
  281.  },
  282.  
  283.  \build_card\: function( hash, profile ) {
  284.  Object.size = function(obj) {
  285.  var size = 0, key;
  286.  for (key in obj) {
  287.  if (obj.hasOwnProperty(key)) size++;
  288.  }
  289.  return size;
  290.  };
  291.  
  292.  // console.log( 'Build profile card for: ' + hash );
  293.  // console.log( profile );
  294.  GProfile.init( profile );
  295.  
  296.  urls = GProfile.get( 'urls' );
  297.  photos = GProfile.get( 'photos' );
  298.  services = GProfile.get( 'accounts' );
  299.  
  300.  limit = 100;
  301.  if ( Object.size( urls ) > 3 )
  302.  limit += 90;
  303.  else
  304.  limit += 10 + ( 20 * Object.size( urls ) );
  305.  
  306.  if ( Object.size( services ) > 0 )
  307.  limit += 30;
  308.  
  309.  description = GProfile.get( 'aboutMe' );
  310.  description = description.replace( /<[^>]+>/ig, '' );
  311.  description = description.toString().substr( 0, limit );
  312.  if ( limit == description.length )
  313.  description += '<a href=\' + GProfile.get( 'profileUrl' ) + '\ target=\_blank\>&#8230;</a>';
  314.  
  315. var card_class = 'grav-inner';
  316.  
  317. // console.log( Gravatar.my_hash, hash );
  318. if ( Gravatar.my_hash && hash == Gravatar.my_hash ) {
  319. card_class += ' grav-is-user';
  320. if ( !description.length ) {
  321. description = \<p>Want a better profile? <a class='grav-edit-profile' href='http://gravatar.com/profiles/edit/' target='_blank'>Click here</a>.</p>\;
  322.  }
  323.  }
  324.  
  325.  if ( description.length ) {
  326.  card_class += ' gcard-about';
  327.  }
  328.  
  329.  card = '<div id=\profile-' + hash + '\> \
  330. <div> \
  331. <div> \
  332. <h4><a href=\' + GProfile.get( 'profileUrl' ) + '\ target=\_blank\>' + GProfile.get( 'displayName' ) + '</a></h4> \
  333.  <p> \
  334.  ' + description + ' \
  335.  </p> \
  336.  </div> \
  337.  <div>';
  338.  
  339. if ( Object.size( urls ) || Object.size( services ) ) {
  340. card_class += ' gcard-links';
  341. }
  342. card += '<h5>Personal Links</h5> \
  343.  <ul>';
  344. url_count = 0;
  345. for ( var u in urls ) {
  346. if ( !urls[u]['value'] || !urls[u]['title'] )
  347. continue;
  348. if ( url_count > 2 ) {
  349. card += '<li><a href=\' + GProfile.get( 'profileUrl' ) + '\ target=\_blank\> + ' + ( urls.length - url_count )  + ' more</a></li>';
  350. break;
  351. }
  352.  
  353. card += '<li><a href=\' + urls[u]['value'] + '\ data-hmac=\' + urls[u]['hmac'] + '\ target=\_blank\>' + urls[u]['title'] + '</a></li>';
  354. url_count++;
  355. }
  356. card += '</ul>';
  357.  
  358. // console.log( 'Services to include in card:' );
  359. // console.log( services );
  360. if ( Object.size( services ) ) {
  361. card_class += ' gcard-services';
  362. }
  363. card += '<ul>';
  364. services_out = 0;
  365. for ( var s in services ) {
  366. if ( !services[s]['url'] )
  367. continue;
  368. if ( services_out >= 6 )
  369. break;
  370. card += '<li><a href=\' + services[s].url + '\ title=\' + services[s].shortname + '\ data-hmac=\' + services[s]['hmac'] + '\ target=\_blank\></a></li>';
  371. services_out++;
  372. }
  373. card += '</ul>';
  374.  
  375. card += '</div>'; // right col
  376.  
  377. if ( Object.size( photos ) > 1 ) {
  378. card_class += ' gcard-gallery';
  379. }
  380. card += '<div> \
  381.  Previous \
  382.  <div> \
  383.  <ul>';
  384. for ( var p in photos ) {
  385. if ( !photos[p]['value'] )
  386. continue;
  387. card += '<li><a href=\' + photos[p]['value'] + '?size=600&axis=y\><img src=\' + photos[p]['value'] + '?size=50&axis=y\ alt=\Grav\ /></a></li>';
  388. }
  389. card += '</ul> \
  390.  </div> \
  391.  Next \
  392.  </div>'; // gallery
  393.  
  394. card += '<div></div> \
  395.  <div><a href=\http://gravatar.com/\ title=\Powered by Gravatar.com\ target=\_blank\>&nbsp;</a></div> \
  396.  <div style=\clear:both\></div>';
  397.  
  398. card += '<p>Turn off hovercards</p>';
  399.  
  400. card += '</div></div>'; // .grav-inner, .gcard
  401.  
  402. // console.log( 'Finished building card for ' + dom_id );
  403. jQuery( 'body' ).append( jQuery( card ) );
  404. jQuery( '#profile-' + hash + ' .grav-inner' ).addClass( card_class );
  405.  
  406. // Custom Background
  407. this.has_bg = false;
  408. bg = GProfile.get( 'profileBackground' );
  409. if ( Object.size( bg ) ) {
  410. this.has_bg = true;
  411. var bg_css = {
  412. padding: '8px 0'
  413. };
  414. if ( bg.color )
  415. bg_css['background-color'] = bg.color;
  416. if ( bg.url )
  417. bg_css['background-image'] = 'url(' + bg.url + ')';
  418. if ( bg.position )
  419. bg_css['background-position'] = bg.position;
  420. if ( bg.repeat )
  421. bg_css['background-repeat'] = bg.repeat;
  422. jQuery( '#profile-' + hash ).css( bg_css );
  423. }
  424.  
  425. // Resize card based on what's visible
  426.  if ( !jQuery( '#profile-' + hash + ' .gcard-links' ).length && !jQuery( '#profile-' + hash + ' .gcard-services' ).length )
  427.  jQuery( '#profile-' + hash + ' .grav-rightcol' ).css( { 'width': 'auto' } );
  428.  if ( !jQuery( '#profile-' + hash + ' .gcard-about' ).length )
  429.  jQuery( '#profile-' + hash + ' .grav-leftcol' ).css( { 'width': 'auto' } );
  430.  
  431.  // Trigger callback if defined
  432.  if ( jQuery.isFunction( Gravatar.profile_cb ) ) {
  433.  Gravatar.loaded_js( hash, 'profile-' + hash );
  434.  }
  435.  
  436.  },
  437.  
  438.  \tilt_gravatar\: function() {
  439.  /* Set the active gravatar */
  440.  this.active_grav = jQuery('img#' + this.active_id);
  441.  
  442.  if ( jQuery('img#grav-clone-' + this.active_hash).length )
  443.  return;
  444.  
  445.  /* Clone the image */
  446.  this.active_grav_clone = this.active_grav.clone().attr( 'id', 'grav-clone-' + this.active_hash ).addClass('grav-clone');
  447.  
  448.  var top = this.active_grav.offset().top;
  449.  var left = this.active_grav.offset().left;
  450. /*
  451.  top  -= 2;
  452.  left -= 2;
  453. */
  454.  
  455.  /* Style clone */
  456.  var fancyCSS = {
  457.  '-webkit-transform': 'rotate(-4deg) scale(1.3)',
  458.  '-moz-transform': 'rotate(-4deg) scale(1.3)',
  459.  '-o-transform': 'rotate(-4deg) scale(1.3)',
  460.  'transform': 'rotate(-4deg) scale(1.3)',
  461.  '-webkit-box-shadow': '0 0 4px #aaa',
  462.  '-moz-box-shadow': '0 0 4px #aaa',
  463.  'box-shadow': '0 0 4px #aaa',
  464.  'border-width': '2px 2px ' + ( this.active_grav.height() / 5 ) + 'px 2px',
  465.  'border-color': '#fff',
  466.  'border-style': 'solid',
  467.  'padding': '0px'
  468.  };
  469.  if ( jQuery.browser.msie && 9 > jQuery.browser.version ) {
  470.  fancyCSS['filter'] = \progid:DXImageTransform.Microsoft.Matrix(M11='1.29683327', M12='0.0906834159', M21='-0.0906834159', M22='1.29683327', SizingMethod='auto expand') progid:DXImageTransform.Microsoft.Glow(Color='#aaaaaa', strength='2'\;
  471.  top  -= 5;
  472.  left -= 6;
  473.  }
  474.  var appendix = this.active_grav_clone.css( fancyCSS ).wrap( '<a href=\http://gravatar.com/' + this.active_hash + '\ target=\_blank\></a>' ).parent().css( {
  475.  'position': 'absolute',
  476.  'top': top + 'px',
  477.  'left': left + 'px',
  478.  'z-index': 15,
  479.  'border': 'none',
  480.  'text-decoration': 'none'
  481.  } );
  482.  
  483.  /* Append the clone on top of the original */
  484.  jQuery('body').append( appendix );
  485.  this.active_grav_clone.removeClass('grav-hashed');
  486.  },
  487.  
  488.  \untilt_gravatar\: function() {
  489.  jQuery('img.grav-clone, a.grav-clone-a').remove();
  490.  Gravatar.hide_throbber();
  491.  },
  492.  
  493.  \show_throbber\: function() {
  494.  // console.log( 'throbbing...' );
  495.  if ( !Gravatar.throbber ) {
  496.  Gravatar.throbber = jQuery( '<div id=\grav-throbber\ style=\position: absolute; z-index: 16\><img src=\http://s.gravatar.com/images/throbber.gif\ alt=\.\ width=\15\ height=\15\ /></div>' );
  497.  }
  498.  
  499.  jQuery( 'body' ).append( Gravatar.throbber );
  500.  
  501.  var offset = jQuery('#' + Gravatar.active_id).offset();
  502.  
  503.  Gravatar.throbber.css( {
  504.  top: offset.top + 2 + 'px',
  505.  left: offset.left + 1 + 'px'
  506.  } );
  507.  },
  508.  
  509.  \hide_throbber\: function() {
  510.  // Remove the throbber if it exists.
  511.  if ( !Gravatar.throbber ) {
  512.  return;
  513.  }
  514.  // console.log( 'stopped throbbing.' );
  515.  Gravatar.throbber.remove();
  516.  },
  517.  
  518.  /***
  519.  * Helper Methods
  520.  */
  521.  
  522.  \fetch_profile_by_email\: function( email ) {
  523.  // console.debug( 'fetch_profile_by_email' );
  524.  return this.fetch_profile_by_hash( this.md5( email ) );
  525.  },
  526.  
  527.  \fetch_profile_by_hash\: function( hash, dom_id ) {
  528.  // This is so that we know which specific Grav is waiting on us
  529.  this.profile_map[ 'g' + hash ] = dom_id;
  530.  // console.log( this.profile_map );
  531.  
  532.  // If we already have it, no point getting it again, so just return it and notify any listeners
  533.  if ( this.profile_stack[ 'g' + hash ] && 'object' == typeof( this.profile_stack[ 'g' + hash ] ) )
  534.  return this.profile_stack[ 'g' + hash ];
  535.  
  536.  // console.log( 'fetch_profile_by_hash: ' + hash, dom_id );
  537.  this.profile_stack[ 'g' + hash ] = 'fetching';
  538.  // Not using $.getJSON because it won't call an error handler for remote URLs
  539.  this.load_js( 'http://en.gravatar.com/' + hash + '.json?callback=Gravatar.fetch_profile_callback', function() {
  540.  Gravatar.fetch_profile_error( hash, dom_id );
  541.  } );
  542.  },
  543.  
  544.  \fetch_profile_callback\: function( profile ) {
  545.  if ( !profile || 'object' != typeof( profile ) )
  546.  return;
  547.  // console.log( 'Received profile via callback:' );
  548.  // console.log( profile );
  549.  this.profile_stack[ 'g' + profile.entry[0].hash ] = profile;
  550.  this.notify( profile.entry[0].hash );
  551.  },
  552.  
  553.  \fetch_profile_error\: function( hash, dom_id ) {
  554.  Gravatar.profile_map[ 'g' + hash ] = false;
  555.  var grav = jQuery( '#' + dom_id );
  556.  if ( grav.parent( 'a[href=http://gravatar.com/' + hash + ']' ).size() ) {
  557.  grav.unwrap();
  558.  }
  559.  // console.debug( dom_id, Gravatar.active_id );
  560.  if ( dom_id == Gravatar.active_id ) {
  561.  Gravatar.hide_card();
  562.  }
  563.  },
  564.  
  565.  \listen\: function( key, callback ) {
  566.  if ( !this.notify_stack )
  567.  this.notify_stack = {};
  568.  
  569.  key = 'g' + key; // Force valid first char
  570.  // console.log( 'listening for: ' + key );
  571.  if ( !this.notify_stack[ key ] )
  572.  this.notify_stack[ key ] = [];
  573.  
  574.  // Make sure it's not already queued
  575.  for ( a = 0; a < this.notify_stack[ key ].length; a++ ) {
  576.  if ( callback == this.notify_stack[ key ][ a ] ) {
  577.  // console.log( 'already' );
  578.  return;
  579.  }
  580.  }
  581.  
  582.  this.notify_stack[ key ][ this.notify_stack[ key ].length ] = callback;
  583.  // console.log( 'added listener: ' + key + ' => ' + callback );
  584.  // console.log( this.notify_stack );
  585.  },
  586.  
  587.  \notify\: function( key ) {
  588.  // console.log( 'trigger notification: ' + key );
  589.  if ( !this.notify_stack )
  590.  this.notify_stack = {};
  591.  
  592.  key = 'g' + key; // Force valid first char
  593.  if ( !this.notify_stack[ key ] )
  594.  this.notify_stack[ key ] = [];
  595.  
  596.  // Reverse it so that notifications are sent in the order they were queued
  597.  // console.log( 'notifying key: ' + key + ' (with ' + this.notify_stack[ key ].length + ' listeners)' );
  598.  for ( a = 0; a < this.notify_stack[ key ].length; a++ ) {
  599.  if ( false == this.notify_stack[ key ][ a ] || \undefined\ == typeof( this.notify_stack[ key ][ a ] ) )
  600.  continue;
  601.  
  602.  // console.log( 'send notification to: ' + this.notify_stack[ key ][ a ] );
  603.  Gravatar[ this.notify_stack[ key ][ a ] ]( key.substr( 1 ) );
  604.  this.notify_stack[ key ][ a ] = false;
  605.  }
  606.  },
  607.  
  608.  \extract_hash\: function( str ) {
  609.  // Get hash from img src
  610.  hash = /gravatar.com\/avatar\/([0-9a-f]{32})/.exec( jQuery( str ).attr( 'src' ) );
  611.  if ( null != hash && \object\ == typeof( hash ) && 2 == hash.length ) {
  612.  hash = hash[1];
  613.  } else {
  614.  hash = /gravatar_id\=([0-9a-f]{32})/.exec( jQuery( str ).attr( 'src' ) );
  615.  if ( null !== hash && \object\ == typeof( hash ) && 2 == hash.length ) {
  616.  hash = hash[1];
  617.  } else {
  618.  return false;
  619.  }
  620.  }
  621.  return hash;
  622.  },
  623.  
  624.  \load_js\: function( src, error_handler ) {
  625.  if ( !this.loaded_scripts )
  626.  this.loaded_scripts = [];
  627.  
  628.  if ( this.loaded_scripts[ src ] )
  629.  return;
  630.  
  631.  this.loaded_scripts[ src ] = true;
  632.  
  633.  var new_script = document.createElement( 'script' );
  634.  new_script.src = src;
  635.  new_script.type = 'text/javascript';
  636.  if ( jQuery.isFunction( error_handler ) ) {
  637.  new_script.onerror = error_handler;
  638.  }
  639.  
  640.  // console.log( src );
  641.  document.getElementsByTagName( 'head' )[0].appendChild( new_script );
  642.  },
  643.  
  644.  \loaded_js\: function( hash, dom_id ) {
  645.  Gravatar.profile_cb( hash, dom_id );
  646.  },
  647.  
  648.  \add_card_css\: function() {
  649.  if ( jQuery( '#gravatar-card-css' ).length )
  650.  return;
  651.  
  652.  var urlS = jQuery( 'script[src*=gravatar.com/js/gprofiles.js]' ), url;
  653.  if ( urlS.size() )
  654.  url = urlS.attr( 'src' ).replace( /\/js\/gprofiles\.js.*$/, '' );
  655.  else
  656.  url = 'http://s.gravatar.com';
  657.  
  658.  new_css = \<link rel='stylesheet' type='text/css' id='gravatar-card-css' href='\ + url + \/css/hovercard.css?v=2' />\;
  659.  new_css += \<link rel='stylesheet' type='text/css' id='gravatar-card-services-css' href='\ + url + \/css/services.css' />\;
  660.  
  661.  jQuery( 'head' ).append( new_css );
  662.  // console.log( 'Added CSS for profile cards to DOM' );
  663.  },
  664.  
  665.  \md5\: function( str ) {
  666.  return hex_md5( str );
  667.  },
  668.  
  669.  \autofill\: function( email, map ) {
  670.  // console.log('autofill');
  671.  if ( !email.length || -1 == email.indexOf( '@' ) )
  672.  return;
  673.  
  674.  this.autofill_map = map;
  675.  hash = this.md5( email );
  676.  // console.log( this.profile_stack[ 'g' + hash ] );
  677.  if ( \undefined\ == typeof( this.profile_stack[ 'g' + hash ] ) ) {
  678.  this.listen( hash, 'autofill_data' );
  679.  this.fetch_profile_by_hash( hash );
  680.  } else {
  681.  // console.log( 'stack: ' + this.profile_stack[ 'g' + hash ] );
  682.  this.autofill_data( hash );
  683.  }
  684.  },
  685.  
  686.  \autofill_data\: function( hash ) {
  687.  // console.log( this.autofill_map );
  688.  // console.log( this.profile_stack[ 'g' + hash ] );
  689.  GProfile.init( this.profile_stack[ 'g' + hash ] );
  690.  for ( var m in this.autofill_map ) {
  691.  // console.log( m );
  692.  // console.log( this.autofill_map[ m ] );
  693.  switch ( m ) {
  694.  case 'url':
  695.  link = GProfile.get( 'urls' );
  696.  // console.log( link );
  697.  jQuery( '#' + this.autofill_map[ m ] ).val( link[0][ 'value' ] );
  698.  break;
  699.  case 'urls':
  700.  links = GProfile.get( 'urls' );
  701.  links_str = '';
  702.  // console.log( links );
  703.  for ( l = 0; l < links.length; l++ ) {
  704.  links_str += links[ l ][ 'value' ] + \\n\;
  705.  }
  706.  jQuery( '#' + this.autofill_map[ m ] ).val( links_str );
  707.  break;
  708.  default:
  709.  parts = m.split( /\./ );
  710.  if ( parts[ 1 ] ) {
  711.  val = GProfile.get( m );
  712.  switch ( parts[ 0 ] ) {
  713.  case 'ims':
  714.  case 'phoneNumbers':
  715.  val = val.value;
  716.  break;
  717.  case 'emails':
  718.  val = val[0].value;
  719.  case 'accounts':
  720.  val = val.url;
  721.  break;
  722.  }
  723.  jQuery( '#' + this.autofill_map[ m ] ).val( val );
  724.  } else {
  725.  jQuery( '#' + this.autofill_map[ m ] ).val( GProfile.get( m ) );
  726.  }
  727.  }
  728.  }
  729.  },
  730.  
  731.  \whee\: function() {
  732.  if ( Gravatar.whee.didWhee ) {
  733.  return;
  734.  }
  735.  Gravatar.whee.didWhee = true;
  736.  if ( document.styleSheets[0].addRule ) {
  737.  document.styleSheets[0].addRule( '.grav-tag a', 'background-position: 22px 100% !important' );
  738.  } else {
  739.  jQuery( '.grav-tag a' ).css( 'background-position', '22px 100%' );
  740.  }
  741.  jQuery( 'img[src*=gravatar.com/]' ).addClass( 'grav-whee' ).css( {
  742.  '-webkit-box-shadow': '1px 1px 3px #aaa',
  743.  '-moz-box-shadow': '1px 1px 3px #aaa',
  744.  'box-shadow': '1px 1px 3px #aaa',
  745.  'border': '2px white solid'
  746.  } );
  747.  var i = 0;
  748.  setInterval( function() {
  749.  jQuery( '.grav-whee' ).css( {
  750.  '-webkit-transform': 'rotate(-' + i + 'deg) scale(1.3)',
  751.  '-moz-transform': 'rotate(-' + i + 'deg) scale(1.3)',
  752.  'transform': 'rotate(-' + i + 'deg) scale(1.3)'
  753.  });
  754.  i++;
  755.  if ( 360 == i ) {
  756.  i = 0;
  757.  }
  758.  }, 6 );
  759.  return false;
  760.  },
  761.  
  762. }
  763.  
  764. jQuery( function() {
  765.  Gravatar.init();
  766. });
  767.  
  768. /**
  769.  * Provides an interface for acceseing profile data returned from Gravatar.com.
  770.  * Use GProfile.init() to set up data, based on the JSON returned from Gravatar,
  771.  * then GProfile.get() to access data more easily.
  772.  */
  773. var GProfile = {
  774.  \data\: {},
  775.  
  776.  \init\: function( data ) {
  777.  if ( 'fetching' == data )
  778.  return false;
  779.  if ( 'undefined' == typeof( data.entry[0] ) )
  780.  return false;
  781.  GProfile.data = data.entry[0];
  782.  },
  783.  
  784.  /**
  785.  * Returns a value from the profile data.
  786.  * @param string attr The name of the attribute you want
  787.  * @param int num (Optional) 0-based array index of the value from this attribute. Use 0 if you're not sure
  788.  * @return Mixed value of the attribute, or empty string.
  789.  */
  790.  \get\: function( attr ) {
  791.  // Handle x.y references
  792.  if ( -1 != attr.indexOf( '.' ) ) {
  793.  parts = attr.split( /\./ );
  794.  // console.log(parts);
  795.  if ( GProfile.data[ parts[ 0 ] ] ) {
  796.  if ( GProfile.data[ parts[ 0 ] ][ parts[ 1 ] ] )
  797.  return GProfile.data[ parts[ 0 ] ][ parts[ 1 ] ]
  798.  
  799.  for ( i = 0, s = GProfile.data[ parts[ 0 ] ].length; i < s; i++ ) {
  800.  if ( GProfile.data[ parts[ 0 ] ][ i ].type && parts[ 1 ] == GProfile.data[ parts[ 0 ] ][ i ].type // phoneNumbers | ims
  801.  || GProfile.data[ parts[ 0 ] ][ i ].shortname && parts[ 1 ] == GProfile.data[ parts[ 0 ] ][ i ].shortname // accounts
  802.  || GProfile.data[ parts[ 0 ] ][ i ].primary && parts[ 1 ] == 'primary' ) { // emails
  803.  
  804.  return GProfile.data[ parts[ 0 ] ][ i ];
  805.  }
  806.  }
  807.  }
  808.  
  809.  return '';
  810.  }
  811.  
  812.  // Handle \top-level\ elements
  813.  if ( GProfile.data[ attr ] )
  814.  return GProfile.data[ attr ];
  815.  
  816.  // And some \aliases\
  817.  if ( 'url' == attr ) {
  818.  if ( GProfile.data.urls.length )
  819.  return GProfile.data.urls[0].value;
  820.  }
  821.  
  822.  return '';
  823.  }
  824. };
  825.  
  826. var grav_resize = {
  827.  card_id: '',
  828.  orig_width: 0,
  829.  orig_height: 0,
  830.  orig_top: 0,
  831.  orig_left: 0,
  832.  current_image: false,
  833.  
  834.  init: function( card_id ) {
  835.  grav_resize.card_id = card_id;
  836.  grav_resize.bind_enlarge();
  837.  },
  838.  
  839.  enlarge: function( el ) {
  840.  /* Remove any enlarged images */
  841.  if ( jQuery('img.grav-large').stop().remove().size() ) {
  842.  grav_resize.current_image = false;
  843.  return;
  844.  }
  845.  
  846.  grav_resize.current_image = el.attr( 'src' );
  847.  /* Preload the larger version of the image */
  848.  jQuery( '#' + grav_resize.card_id + ' .grav-tag a' ).css( 'background-position', '22px 100%' );
  849.  var fullsize = jQuery('<img />').attr( 'src', grav_resize.current_image + '&size=400' ).load( function() {
  850.  jQuery( '#' + grav_resize.card_id + ' .grav-tag a' ).css( 'background-position', '22px 0' );
  851.  } );
  852.  
  853.  /* Clone the image */
  854.  var the_clone = el.clone();
  855.  
  856.  the_clone.css({
  857.  'position': 'absolute',
  858.  'top': grav_resize.orig_top,
  859.  'left': grav_resize.orig_left,
  860.  'background-color': '#333',
  861.  'width': grav_resize.orig_width,
  862.  'height': grav_resize.orig_height,
  863.  'border-color': '#555'
  864.  });
  865.  
  866.  the_clone.appendTo(el.parent());
  867.  
  868.  /* Get the image ratio */
  869.  var    horiz_padding = 0;
  870.  var    vert_padding = 0;
  871.  var border_width = 6;
  872.  var card = jQuery( '#' + grav_resize.card_id + ' .grav-inner' );
  873.  
  874.  if ( el.width() > el.height() ) {
  875.  var ratio = el.height() / el.width();
  876.  var width = card.outerWidth();
  877.  var height = ( width * ratio );
  878.  var vert_padding = ( card.outerHeight() - height ) / 2;
  879.  
  880.  // if height it too big resize it width wise.
  881.  if ( height > card.outerHeight() ) {
  882.  var ratio = el.width() / el.height();
  883.  var height = card.outerHeight();
  884.  var width = ( height * ratio );
  885.  var horiz_padding = ( card.outerWidth() - width ) / 2;
  886.  }
  887.  
  888.  } else {
  889.  var ratio = el.width() / el.height();
  890.  var height = card.outerHeight();
  891.  var width = ( height * ratio );
  892.  var horiz_padding = ( card.outerWidth() - width ) / 2;
  893.  }
  894.  
  895.  the_clone.stop().animate({
  896.  'top': 0,
  897.  'left': 0,
  898.  'width': width - border_width + 'px',
  899.  'height': height - border_width + 'px',
  900.  'z-index': 99,
  901.  'padding-left': horiz_padding + 'px',
  902.  'padding-right': horiz_padding + 'px',
  903.  'padding-top': vert_padding + 'px',
  904.  'padding-bottom': vert_padding + 'px'
  905.  }, 250, function() {
  906.  /* Make the clone the fullsize image that was preloaded */
  907.  the_clone.addClass('grav-large');
  908.  the_clone.attr('src', fullsize.attr('src') );
  909.  
  910.  /* Add the close button */
  911.  the_clone.parent().append('<div>X</div>');
  912.  jQuery('.grav-large-close').hide().fadeIn(100);
  913.  } );
  914.  
  915.  jQuery('#'+grav_resize.card_id+' .grav-gallery img').unbind('click');
  916.  
  917.  jQuery('.grav-large-close' ).live( 'click', function() {
  918.  grav_resize.reduce( the_clone );
  919.  });
  920.  
  921.  jQuery(the_clone).click( function() {
  922.  grav_resize.reduce( the_clone );
  923.  });
  924.  },
  925.  
  926.  reduce: function( el ) {
  927.  jQuery('.grav-large-close').remove();
  928.  
  929.  el.stop().animate({
  930.  'top': grav_resize.orig_top,
  931.  'left': grav_resize.orig_left,
  932.  'width': grav_resize.orig_width,
  933.  'height': grav_resize.orig_height,
  934.  'padding-left': 0,
  935.  'padding-right': 0,
  936.  'padding-top': 0,
  937.  'padding-bottom': 0
  938.  }, 250, function() {
  939.  jQuery('img.grav-large').remove();
  940.  grav_resize.bind_enlarge( grav_resize.card_id );
  941.  grav_resize.current_image = false;
  942.  });
  943.  },
  944.  
  945.  bind_enlarge: function() {
  946.  jQuery('#' + grav_resize.card_id + ' .grav-gallery img').parent( 'a' ).click( function(e) {
  947.  if ( jQuery.browser.msie && jQuery.browser.version < 9.0 )
  948.  return;
  949.  
  950.  e.preventDefault();
  951.  
  952.  if ( grav_resize.current_image ) {
  953.  return;
  954.  }
  955.  
  956.  var img = jQuery(this).find( 'img' ).not( '.grav-large' );
  957.  var position = img.position();
  958.  
  959.  grav_resize.orig_width = img.width();
  960.  grav_resize.orig_height = img.height();
  961.  grav_resize.orig_top = position.top;
  962.  grav_resize.orig_left = position.left;
  963.  
  964.  grav_resize.enlarge( img );
  965.  });
  966.  }
  967. }
  968.  
  969. var grav_gallery = {
  970.  orig_left: 0,
  971.  pos: 0,
  972.  
  973.  init: function( card ) {
  974.  grav_gallery.bind_arrows( card, true );
  975.  
  976.  /* Also recheck the arrows are correct once the user hovers over the gallery section, in case the images took a while to load */
  977.  jQuery('#' + card + ' .grav-gallery').mouseover( function() {
  978.  grav_gallery.bind_arrows( card, false );
  979.  });
  980.  },
  981.  
  982.  bind_arrows: function( card, reset ) {
  983.  var gallery_el = jQuery('#' + card + ' .grav-gallery ul');
  984.  if ( !gallery_el.size() ) {
  985.  return;
  986.  }
  987.  grav_gallery.orig_left = gallery_el.css('margin-left').replace('px','');
  988.  grav_gallery.pos = gallery_el.find( 'li:last').position();
  989.  
  990.  jQuery('#' + card + ' a.grav-gallery-next').live( 'click', function() {
  991.  if ( grav_gallery.pos.left > 275 )
  992.  gallery_el.animate({'margin-left': parseFloat(grav_gallery.orig_left) - 314 + 'px'}, 300, function() { grav_gallery.highlight_arrows( card, false ); } );
  993.  
  994.  return false;
  995.  });
  996.  
  997.  jQuery('#' + card + ' a.grav-gallery-prev').live( 'click', function() {
  998.  if ( 0 != grav_gallery.orig_left )
  999.  gallery_el.animate({'margin-left': parseFloat(grav_gallery.orig_left) + 314 + 'px'}, 300, function() { grav_gallery.highlight_arrows( card, false ) } );
  1000.  
  1001.  return false;
  1002.  });
  1003.  
  1004.  if ( reset )
  1005.  jQuery('#' + card + ' .grav-gallery ul').css({'margin-left': 0});
  1006.  
  1007.  grav_gallery.highlight_arrows( card, true );
  1008.  },
  1009.  
  1010.  highlight_arrows: function( card ) {
  1011.  grav_gallery.orig_left = jQuery('#' + card + ' .grav-gallery ul').css('margin-left').replace('px','');
  1012.  grav_gallery.last = jQuery('#' + card + ' .grav-gallery ul li:last');
  1013.  
  1014.  if ( grav_gallery.last.position().left < 275 )
  1015.  jQuery('#' + card + ' a.grav-gallery-next').css({'background-position': '-39px 0'});
  1016.  else
  1017.  jQuery('#' + card + ' a.grav-gallery-next').css({'background-position': '-26px 0'});
  1018.  
  1019.  if ( 0 != grav_gallery.orig_left )
  1020.  jQuery('#' + card + ' a.grav-gallery-prev').css({'background-position': '0 0'});
  1021.  else
  1022.  jQuery('#' + card + ' a.grav-gallery-prev').css({'background-position': '-13px 0'});
  1023.  }
  1024. }
  1025.  
  1026. /*
  1027.  * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
  1028.  * Digest Algorithm, as defined in RFC 1321.
  1029.  * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
  1030.  * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
  1031.  * Distributed under the BSD License
  1032.  * See http://pajhome.org.uk/crypt/md5 for more info.
  1033.  */
  1034.  
  1035. var hexcase=0;var b64pad=\\;var chrsz=8;function hex_md5(s){return binl2hex(core_md5(str2binl(s),s.length*chrsz))}function b64_md5(s){return binl2b64(core_md5(str2binl(s),s.length*chrsz))}function str_md5(s){return binl2str(core_md5(str2binl(s),s.length*chrsz))}function hex_hmac_md5(a,b){return binl2hex(core_hmac_md5(a,b))}function b64_hmac_md5(a,b){return binl2b64(core_hmac_md5(a,b))}function str_hmac_md5(a,b){return binl2str(core_hmac_md5(a,b))}function md5_vm_test(){return hex_md5(\abc\)==\900150983cd24fb0d6963f7d28e17f72\}function core_md5(x,e){x[e>>5]|=0x80<<((e)%32);x[(((e+64)>>>9)<<4)+14]=e;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;for(var i=0;i<x.length;i+=16){var f=a;var g=b;var h=c;var j=d;a=md5_ff(a,b,c,d,x[i+0],7,-680876936);d=md5_ff(d,a,b,c,x[i+1],12,-389564586);c=md5_ff(c,d,a,b,x[i+2],17,606105819);b=md5_ff(b,c,d,a,x[i+3],22,-1044525330);a=md5_ff(a,b,c,d,x[i+4],7,-176418897);d=md5_ff(d,a,b,c,x[i+5],12,1200080426);c=md5_ff(c,d,a,b,x[i+6],17,-1473231341);b=md5_ff(b,c,d,a,x[i+7],22,-45705983);a=md5_ff(a,b,c,d,x[i+8],7,1770035416);d=md5_ff(d,a,b,c,x[i+9],12,-1958414417);c=md5_ff(c,d,a,b,x[i+10],17,-42063);b=md5_ff(b,c,d,a,x[i+11],22,-1990404162);a=md5_ff(a,b,c,d,x[i+12],7,1804603682);d=md5_ff(d,a,b,c,x[i+13],12,-40341101);c=md5_ff(c,d,a,b,x[i+14],17,-1502002290);b=md5_ff(b,c,d,a,x[i+15],22,1236535329);a=md5_gg(a,b,c,d,x[i+1],5,-165796510);d=md5_gg(d,a,b,c,x[i+6],9,-1069501632);c=md5_gg(c,d,a,b,x[i+11],14,643717713);b=md5_gg(b,c,d,a,x[i+0],20,-373897302);a=md5_gg(a,b,c,d,x[i+5],5,-701558691);d=md5_gg(d,a,b,c,x[i+10],9,38016083);c=md5_gg(c,d,a,b,x[i+15],14,-660478335);b=md5_gg(b,c,d,a,x[i+4],20,-405537848);a=md5_gg(a,b,c,d,x[i+9],5,568446438);d=md5_gg(d,a,b,c,x[i+14],9,-1019803690);c=md5_gg(c,d,a,b,x[i+3],14,-187363961);b=md5_gg(b,c,d,a,x[i+8],20,1163531501);a=md5_gg(a,b,c,d,x[i+13],5,-1444681467);d=md5_gg(d,a,b,c,x[i+2],9,-51403784);c=md5_gg(c,d,a,b,x[i+7],14,1735328473);b=md5_gg(b,c,d,a,x[i+12],20,-1926607734);a=md5_hh(a,b,c,d,x[i+5],4,-378558);d=md5_hh(d,a,b,c,x[i+8],11,-2022574463);c=md5_hh(c,d,a,b,x[i+11],16,1839030562);b=md5_hh(b,c,d,a,x[i+14],23,-35309556);a=md5_hh(a,b,c,d,x[i+1],4,-1530992060);d=md5_hh(d,a,b,c,x[i+4],11,1272893353);c=md5_hh(c,d,a,b,x[i+7],16,-155497632);b=md5_hh(b,c,d,a,x[i+10],23,-1094730640);a=md5_hh(a,b,c,d,x[i+13],4,681279174);d=md5_hh(d,a,b,c,x[i+0],11,-358537222);c=md5_hh(c,d,a,b,x[i+3],16,-722521979);b=md5_hh(b,c,d,a,x[i+6],23,76029189);a=md5_hh(a,b,c,d,x[i+9],4,-640364487);d=md5_hh(d,a,b,c,x[i+12],11,-421815835);c=md5_hh(c,d,a,b,x[i+15],16,530742520);b=md5_hh(b,c,d,a,x[i+2],23,-995338651);a=md5_ii(a,b,c,d,x[i+0],6,-198630844);d=md5_ii(d,a,b,c,x[i+7],10,1126891415);c=md5_ii(c,d,a,b,x[i+14],15,-1416354905);b=md5_ii(b,c,d,a,x[i+5],21,-57434055);a=md5_ii(a,b,c,d,x[i+12],6,1700485571);d=md5_ii(d,a,b,c,x[i+3],10,-1894986606);c=md5_ii(c,d,a,b,x[i+10],15,-1051523);b=md5_ii(b,c,d,a,x[i+1],21,-2054922799);a=md5_ii(a,b,c,d,x[i+8],6,1873313359);d=md5_ii(d,a,b,c,x[i+15],10,-30611744);c=md5_ii(c,d,a,b,x[i+6],15,-1560198380);b=md5_ii(b,c,d,a,x[i+13],21,1309151649);a=md5_ii(a,b,c,d,x[i+4],6,-145523070);d=md5_ii(d,a,b,c,x[i+11],10,-1120210379);c=md5_ii(c,d,a,b,x[i+2],15,718787259);b=md5_ii(b,c,d,a,x[i+9],21,-343485551);a=safe_add(a,f);b=safe_add(b,g);c=safe_add(c,h);d=safe_add(d,j)}return Array(a,b,c,d)}function md5_cmn(q,a,b,x,s,t){return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b)}function md5_ff(a,b,c,d,x,s,t){return md5_cmn((b&c)|((~b)&d),a,b,x,s,t)}function md5_gg(a,b,c,d,x,s,t){return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t)}function md5_hh(a,b,c,d,x,s,t){return md5_cmn(b^c^d,a,b,x,s,t)}function md5_ii(a,b,c,d,x,s,t){return md5_cmn(c^(b|(~d)),a,b,x,s,t)}function core_hmac_md5(a,b){var c=str2binl(a);if(c.length>16)c=core_md5(c,a.length*chrsz);var d=Array(16),opad=Array(16);for(var i=0;i<16;i++){d[i]=c[i]^0x36363636;opad[i]=c[i]^0x5C5C5C5C}var e=core_md5(d.concat(str2binl(b)),512+b.length*chrsz);return core_md5(opad.concat(e),512+128)}function safe_add(x,y){var a=(x&0xFFFF)+(y&0xFFFF);var b=(x>>16)+(y>>16)+(a>>16);return(b<<16)|(a&0xFFFF)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))}function str2binl(a){var b=Array();var c=(1<<chrsz)-1;for(var i=0;i<a.length*chrsz;i+=chrsz)b[i>>5]|=(a.charCodeAt(i/chrsz)&c)<<(i%32);return b}function binl2str(a){var b=\\;var c=(1<<chrsz)-1;for(var i=0;i<a.length*32;i+=chrsz)b+=String.fromCharCode((a[i>>5]>>>(i%32))&c);return b}function binl2hex(a){var b=hexcase?\0123456789ABCDEF\:\0123456789abcdef\;var c=\\;for(var i=0;i<a.length*4;i++){c+=b.charAt((a[i>>2]>>((i%4)*8+4))&0xF)+b.charAt((a[i>>2]>>((i%4)*8))&0xF)}return c}function binl2b64(a){var b=\ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\;var c=\\;for(var i=0;i<a.length*4;i+=3){var d=(((a[i>>2]>>8*(i%4))&0xFF)<<16)|(((a[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((a[i+2>>2]>>8*((i+2)%4))&0xFF);for(var j=0;j<4;j++){if(i*8+j*6>a.length*32)c+=b64pad;else c+=b.charAt((d>>6*(3-j))&0x3F)}}return c};
if ( \undefined\ == typeof( console ) ) {
 console = { \log\: function(str){}, \debug\: function(str){} };
}

var Gravatar = {
 /* All loaded profiles, keyed off ghash */
 \profile_stack\: {},

 // Mapping of ghash to the \currently waiting\ dom_id of where to render it
 \profile_map\: {},

 /* Timeouts for hovering over and off Gravatar images */
 \overTimeout\: false,
 \outTimeout\: false,

 /* If true, show_card will bail */
 \stopOver\: false,

 /* The img element, hash and ID of the Gravatar that is being hovered over */
 \active_grav\: false,
 \active_hash\: false,
 \active_id\: false,

 /* The clone of the Gravatar img element that is being hovered over. */
 \active_grav_clone\: false,

 /* Callback function for once a profile is loaded */
 \profile_cb\: null,

 /* Wating throbber */
 \throbber\: null,

 /* Has a custom background image been added to the card? */
 \has_bg\: false,
 \disabled\:false,

 \mouseOut\: function(e) {
 e.stopImmediatePropagation();
 Gravatar.stopOver = true;

 // console.debug( ':set out' );
 Gravatar.outTimeout = setTimeout( function() {
 // console.debug( ':do out' );
 Gravatar.hide_card();
 }, 300 );
 },

 \init\: function() {
 var ca = document.cookie.split( ';' ), i, c;
 for ( i = 0; i < ca.length; i++ ) {
 c = ca[i];
 while ( ' ' == c.charAt(0) ) {
 c=c.substring( 1, c.length );
 }
 if ( 0 == c.indexOf( 'nohovercard=1' ) ) {
 return;
 }
 }

 /* Locate all Gravatar images and attach profile links to them. */
 this.attach_profiles();

 /* Add CSS */
 this.add_card_css();

 /* Find and show a hovercard when hovering over a Gravatar. */
 jQuery('img.grav-hashed').live( 'mouseenter.gravatar mouseleave.gravatar', function(e) {
 if ( Gravatar.disabled ) { return; }
 e.preventDefault();
 e.stopPropagation();

 if ( 'mouseleave' == e.type || 'mouseout' == e.type ) {
 // console.debug( 'grav out' );
 return Gravatar.mouseOut.call( this, e );
 }

 Gravatar.stopOver = false;

 // console.debug( 'grav enter' );
 /* Get and store the hash and ID for the active Gravatar */
 Gravatar.active_id = jQuery(this).attr('id');
 Gravatar.active_hash = Gravatar.active_id.split('-')[1];

 Gravatar.untilt_gravatar();

 // console.debug( ':clear over1' );
 clearTimeout( Gravatar.overTimeout );

 // No profile data - see fetch_profile_error
 if ( false === Gravatar.profile_map[ 'g' + Gravatar.active_hash ] ) {
 return;
 }

 // console.debug( ':clear out' );
 clearTimeout( Gravatar.outTimeout );

 Gravatar.tilt_gravatar();
 Gravatar.fetch_profile_by_hash( Gravatar.active_hash, Gravatar.active_id );
 // console.debug( ':set over' );
 Gravatar.overTimeout = setTimeout( function() {
 Gravatar.show_card();
 }, 600 );
 });

 /* Maintain hovercard state when rolling over a hovercard or cloned image */
 jQuery('div.gcard, img.grav-clone').live( 'mouseenter.gravatar mouseleave.gravatar', function(e) {
 if ( Gravatar.disabled ) { return; }
 e.preventDefault();
 e.stopPropagation();

 if ( e.type == 'mouseenter' || e.type == 'mouseover' ) {
 Gravatar.stopOver = false;

 // console.debug( 'clone enter' );
 // console.debug( ':clear out2' );
 clearTimeout( Gravatar.outTimeout );
 } else {
 // console.debug( 'clone out' );
 Gravatar.mouseOut.call( this, e );
 }
 });

 /* Cancel a hovercard when scrolling. */
 jQuery(window).bind( 'scroll', function() {
 if ( !Gravatar.active_hash.length )
 return;

 Gravatar.hide_card();
 });
 },

 \attach_profiles\: function( container ) {
 /* Locate all Gravatar images and add profiles to them */
 container = \undefined\ == typeof( container ) ? \body\ : container;

 jQuery( container + ' img[src*=gravatar.com/avatar]' ).not( '.no-grav, .no-grav img' ).each( function() {
 hash = Gravatar.extract_hash( this );

 /* Add unique ID to image so we can reference it directly */
 uniq = 0;
 if ( jQuery( '#grav-' + hash + '-' + uniq ).length ) {
 while ( jQuery( '#grav-' + hash + '-' + uniq ).length )
 uniq++;
 }

 /* Remove the hover titles for sanity */
 var g = jQuery( this ).attr( 'id', 'grav-' + hash + '-' + uniq ).attr( 'title', '' ).removeAttr( 'title' );
 if ( g.parent( 'a' ).length )
 g.parent( 'a' ).attr( 'href', 'http://gravatar.com/' + hash ).attr( 'title', '' ).removeAttr( 'title' );

 g.addClass('grav-hashed');
 });
 },

 \show_card\: function() {
 if ( Gravatar.stopOver ) {
 return;
 }

 dom_id = this.profile_map[ 'g' + Gravatar.active_hash ];

 // Close any existing cards
 jQuery( '.gcard' ).hide();

 // Bail if we're waiting on a fetch
 if ( 'fetching' == this.profile_stack[ 'g' + Gravatar.active_hash ] ) {
 Gravatar.show_throbber();
 this.listen( Gravatar.active_hash, 'show_card' );
 // console.log( 'still fetching ' + hash );
 return;
 }

 // If we haven't fetched this profile yet, do it now and do this later
 if ( 'undefined' == typeof( this.profile_stack[ 'g' + Gravatar.active_hash ] ) ) {
 Gravatar.show_throbber();
 this.listen( Gravatar.active_hash, 'show_card' );
 // console.log( 'need to start fetching ' + hash + '@' + dom_id );
 this.fetch_profile_by_hash( Gravatar.active_hash, dom_id );
 return;
 }

 Gravatar.hide_throbber();

 // console.log( 'show_card: hash: ' + hash + ', DOM ID: ' + dom_id );

 // No HTML? build it
 if ( !jQuery( '#profile-' + this.active_hash  ).length )
 this.build_card( this.active_hash, this.profile_stack[ 'g' + this.active_hash ] );

 this.render_card( this.active_grav, 'profile-' + this.active_hash );
 },

 \hide_card\: function() {
 // console.debug( ':clear over3' );
 clearTimeout( Gravatar.overTimeout );

 /* Untilt the Gravatar image */
 this.untilt_gravatar();
 grav_resize.current_image = false
 jQuery( 'div.gcard' ).filter( '#profile-' + this.active_hash ).fadeOut(120, function() {
 jQuery('img.grav-large').stop().remove();
 } ).end().not( '#profile-' + this.active_hash ).hide();
 },

 \render_card\: function( grav, card_id ) {
 var card_el = jQuery( '#' + card_id  ).stop();

 // console.log( 'render_card for ' + grav_id + ', ' + card_id );
 // Change CSS positioning based on where grav_id is in the page
 var grav_el  = grav;
 var grav_pos = grav_el.offset();

 if ( null != grav_pos ) {
 var grav_width  = grav_el.width();
 var grav_height = grav_el.height();
 var grav_space  = 5 + ( grav_width * .4 );

 var card_width  = card_el.width();
 var card_height = card_el.height();
 if ( card_width == jQuery(window).width() ) {
 card_width  = 400;
 card_height = 200;
 }

 /*
 console.log( grav_pos );
 console.log( 'grav_width = ' + grav_width + \\n\ +
 'grav_height = ' + grav_height + \\n\ +
 'grav_space = ' + grav_space + \\n\ +
 'card_width = ' + card_width + \\n\ +
 'card_height = ' + card_height + \\n\ );
 */

 /* Position to the right of the element */
 var left = grav_pos.left + grav_width + grav_space;
 var top = grav_pos.top;
 var grav_pos_class = 'pos-right';

 /* Position to the left of the element if space on the right is not enough. */
 if ( grav_pos.left + grav_width + grav_space + card_width > jQuery(window).width() + jQuery(window).scrollLeft() ) {
 left = grav_pos.left - ( card_width + grav_space );
 grav_pos_class = 'pos-left';
 }

 /* Reposition the card itself */
 var top_offset = grav_height * .25;
 jQuery( '#' + card_id ).removeClass( 'pos-right pos-left' ).addClass( grav_pos_class ).css( { 'top': ( top - top_offset ) + 'px', 'left': left + 'px' } );

 /* Position of the small arrow in relation to the Gravatar */
 var arrow_offset = ( grav_height / 2 );
 if ( arrow_offset > card_height )
 arrow_offset = card_height / 2;
 if ( arrow_offset > ( card_height / 2 ) - 6 )
 arrow_offset = ( card_height / 2 ) - 6;
 if ( arrow_offset > 53 )
 arrow_offset = 53; // Max
 if ( this.has_bg )
 arrow_offset = arrow_offset - 8;
 if ( arrow_offset < 0 )
 arrow_offset = 0; // Min
 var css = {
 'height': ( ( grav_height * 1.5 ) + top_offset ) + 'px'
 };
 if ( 'pos-right' == grav_pos_class ) {
 css['right'] = 'auto';
 css['left'] = '-7px';
 css['background-position'] = '0px ' + arrow_offset + 'px';
 } else {
 css['right'] = '-10px';
 css['left'] = 'auto';
 css['background-position'] = '0px ' + arrow_offset + 'px';
 }
 jQuery( '#' + card_id + ' .grav-cardarrow' ).css( css );
 }

 card_el.stop().css( { opacity: 0 } ).show().animate( { opacity: 1 }, 150, 'linear', function() {
 jQuery( this ).stop();
 grav_resize.init( card_id );
 grav_gallery.init( card_id );
 });
 },

 \build_card\: function( hash, profile ) {
 Object.size = function(obj) {
 var size = 0, key;
 for (key in obj) {
 if (obj.hasOwnProperty(key)) size++;
 }
 return size;
 };

 // console.log( 'Build profile card for: ' + hash );
 // console.log( profile );
 GProfile.init( profile );

 urls = GProfile.get( 'urls' );
 photos = GProfile.get( 'photos' );
 services = GProfile.get( 'accounts' );

 limit = 100;
 if ( Object.size( urls ) > 3 )
 limit += 90;
 else
 limit += 10 + ( 20 * Object.size( urls ) );

 if ( Object.size( services ) > 0 )
 limit += 30;

 description = GProfile.get( 'aboutMe' );
 description = description.replace( /<[^>]+>/ig, '' );
 description = description.toString().substr( 0, limit );
 if ( limit == description.length )
 description += '<a href=\' + GProfile.get( 'profileUrl' ) + '\ target=\_blank\>&#8230;</a>';

 var card_class = 'grav-inner';

 // console.log( Gravatar.my_hash, hash );
 if ( Gravatar.my_hash && hash == Gravatar.my_hash ) {
 card_class += ' grav-is-user';
 if ( !description.length ) {
 description = \<p>Want a better profile? <a class='grav-edit-profile' href='http://gravatar.com/profiles/edit/' target='_blank'>Click here</a>.</p>\;
 }
 }

 if ( description.length ) {
 card_class += ' gcard-about';
 }

 card = '<div id=\profile-' + hash + '\> \
 <div> \
 <div> \
 <h4><a href=\' + GProfile.get( 'profileUrl' ) + '\ target=\_blank\>' + GProfile.get( 'displayName' ) + '</a></h4> \
 <p> \
 ' + description + ' \
 </p> \
 </div> \
 <div>';

 if ( Object.size( urls ) || Object.size( services ) ) {
 card_class += ' gcard-links';
 }
 card += '<h5>Personal Links</h5> \
 <ul>';
 url_count = 0;
 for ( var u in urls ) {
 if ( !urls[u]['value'] || !urls[u]['title'] )
 continue;
 if ( url_count > 2 ) {
 card += '<li><a href=\' + GProfile.get( 'profileUrl' ) + '\ target=\_blank\> + ' + ( urls.length - url_count )  + ' more</a></li>';
 break;
 }

 card += '<li><a href=\' + urls[u]['value'] + '\ data-hmac=\' + urls[u]['hmac'] + '\ target=\_blank\>' + urls[u]['title'] + '</a></li>';
 url_count++;
 }
 card += '</ul>';

 // console.log( 'Services to include in card:' );
 // console.log( services );
 if ( Object.size( services ) ) {
 card_class += ' gcard-services';
 }
 card += '<ul>';
 services_out = 0;
 for ( var s in services ) {
 if ( !services[s]['url'] )
 continue;
 if ( services_out >= 6 )
 break;
 card += '<li><a href=\' + services[s].url + '\ title=\' + services[s].shortname + '\ data-hmac=\' + services[s]['hmac'] + '\ target=\_blank\></a></li>';
 services_out++;
 }
 card += '</ul>';

 card += '</div>'; // right col

 if ( Object.size( photos ) > 1 ) {
 card_class += ' gcard-gallery';
 }
 card += '<div> \
 Previous \
 <div> \
 <ul>';
 for ( var p in photos ) {
 if ( !photos[p]['value'] )
 continue;
 card += '<li><a href=\' + photos[p]['value'] + '?size=600&axis=y\><img src=\' + photos[p]['value'] + '?size=50&axis=y\ alt=\Grav\ /></a></li>';
 }
 card += '</ul> \
 </div> \
 Next \
 </div>'; // gallery

 card += '<div></div> \
 <div><a href=\http://gravatar.com/\ title=\Powered by Gravatar.com\ target=\_blank\>&nbsp;</a></div> \
 <div style=\clear:both\></div>';

 card += '<p>Turn off hovercards</p>';

 card += '</div></div>'; // .grav-inner, .gcard

 // console.log( 'Finished building card for ' + dom_id );
 jQuery( 'body' ).append( jQuery( card ) );
 jQuery( '#profile-' + hash + ' .grav-inner' ).addClass( card_class );

 // Custom Background
 this.has_bg = false;
 bg = GProfile.get( 'profileBackground' );
 if ( Object.size( bg ) ) {
 this.has_bg = true;
 var bg_css = {
 padding: '8px 0'
 };
 if ( bg.color )
 bg_css['background-color'] = bg.color;
 if ( bg.url )
 bg_css['background-image'] = 'url(' + bg.url + ')';
 if ( bg.position )
 bg_css['background-position'] = bg.position;
 if ( bg.repeat )
 bg_css['background-repeat'] = bg.repeat;
 jQuery( '#profile-' + hash ).css( bg_css );
 }

 // Resize card based on what's visible
 if ( !jQuery( '#profile-' + hash + ' .gcard-links' ).length && !jQuery( '#profile-' + hash + ' .gcard-services' ).length )
 jQuery( '#profile-' + hash + ' .grav-rightcol' ).css( { 'width': 'auto' } );
 if ( !jQuery( '#profile-' + hash + ' .gcard-about' ).length )
 jQuery( '#profile-' + hash + ' .grav-leftcol' ).css( { 'width': 'auto' } );

 // Trigger callback if defined
 if ( jQuery.isFunction( Gravatar.profile_cb ) ) {
 Gravatar.loaded_js( hash, 'profile-' + hash );
 }

 },

 \tilt_gravatar\: function() {
 /* Set the active gravatar */
 this.active_grav = jQuery('img#' + this.active_id);

 if ( jQuery('img#grav-clone-' + this.active_hash).length )
 return;

 /* Clone the image */
 this.active_grav_clone = this.active_grav.clone().attr( 'id', 'grav-clone-' + this.active_hash ).addClass('grav-clone');

 var top = this.active_grav.offset().top;
 var left = this.active_grav.offset().left;
/*
 top  -= 2;
 left -= 2;
*/

 /* Style clone */
 var fancyCSS = {
 '-webkit-transform': 'rotate(-4deg) scale(1.3)',
 '-moz-transform': 'rotate(-4deg) scale(1.3)',
 '-o-transform': 'rotate(-4deg) scale(1.3)',
 'transform': 'rotate(-4deg) scale(1.3)',
 '-webkit-box-shadow': '0 0 4px #aaa',
 '-moz-box-shadow': '0 0 4px #aaa',
 'box-shadow': '0 0 4px #aaa',
 'border-width': '2px 2px ' + ( this.active_grav.height() / 5 ) + 'px 2px',
 'border-color': '#fff',
 'border-style': 'solid',
 'padding': '0px'
 };
 if ( jQuery.browser.msie && 9 > jQuery.browser.version ) {
 fancyCSS['filter'] = \progid:DXImageTransform.Microsoft.Matrix(M11='1.29683327', M12='0.0906834159', M21='-0.0906834159', M22='1.29683327', SizingMethod='auto expand') progid:DXImageTransform.Microsoft.Glow(Color='#aaaaaa', strength='2'\;
 top  -= 5;
 left -= 6;
 }
 var appendix = this.active_grav_clone.css( fancyCSS ).wrap( '<a href=\http://gravatar.com/' + this.active_hash + '\ target=\_blank\></a>' ).parent().css( {
 'position': 'absolute',
 'top': top + 'px',
 'left': left + 'px',
 'z-index': 15,
 'border': 'none',
 'text-decoration': 'none'
 } );

 /* Append the clone on top of the original */
 jQuery('body').append( appendix );
 this.active_grav_clone.removeClass('grav-hashed');
 },

 \untilt_gravatar\: function() {
 jQuery('img.grav-clone, a.grav-clone-a').remove();
 Gravatar.hide_throbber();
 },

 \show_throbber\: function() {
 // console.log( 'throbbing...' );
 if ( !Gravatar.throbber ) {
 Gravatar.throbber = jQuery( '<div id=\grav-throbber\ style=\position: absolute; z-index: 16\><img src=\http://s.gravatar.com/images/throbber.gif\ alt=\.\ width=\15\ height=\15\ /></div>' );
 }

 jQuery( 'body' ).append( Gravatar.throbber );

 var offset = jQuery('#' + Gravatar.active_id).offset();

 Gravatar.throbber.css( {
 top: offset.top + 2 + 'px',
 left: offset.left + 1 + 'px'
 } );
 },

 \hide_throbber\: function() {
 // Remove the throbber if it exists.
 if ( !Gravatar.throbber ) {
 return;
 }
 // console.log( 'stopped throbbing.' );
 Gravatar.throbber.remove();
 },

 /***
 * Helper Methods
 */

 \fetch_profile_by_email\: function( email ) {
 // console.debug( 'fetch_profile_by_email' );
 return this.fetch_profile_by_hash( this.md5( email ) );
 },

 \fetch_profile_by_hash\: function( hash, dom_id ) {
 // This is so that we know which specific Grav is waiting on us
 this.profile_map[ 'g' + hash ] = dom_id;
 // console.log( this.profile_map );

 // If we already have it, no point getting it again, so just return it and notify any listeners
 if ( this.profile_stack[ 'g' + hash ] && 'object' == typeof( this.profile_stack[ 'g' + hash ] ) )
 return this.profile_stack[ 'g' + hash ];

 // console.log( 'fetch_profile_by_hash: ' + hash, dom_id );
 this.profile_stack[ 'g' + hash ] = 'fetching';
 // Not using $.getJSON because it won't call an error handler for remote URLs
 this.load_js( 'http://en.gravatar.com/' + hash + '.json?callback=Gravatar.fetch_profile_callback', function() {
 Gravatar.fetch_profile_error( hash, dom_id );
 } );
 },

 \fetch_profile_callback\: function( profile ) {
 if ( !profile || 'object' != typeof( profile ) )
 return;
 // console.log( 'Received profile via callback:' );
 // console.log( profile );
 this.profile_stack[ 'g' + profile.entry[0].hash ] = profile;
 this.notify( profile.entry[0].hash );
 },

 \fetch_profile_error\: function( hash, dom_id ) {
 Gravatar.profile_map[ 'g' + hash ] = false;
 var grav = jQuery( '#' + dom_id );
 if ( grav.parent( 'a[href=http://gravatar.com/' + hash + ']' ).size() ) {
 grav.unwrap();
 }
 // console.debug( dom_id, Gravatar.active_id );
 if ( dom_id == Gravatar.active_id ) {
 Gravatar.hide_card();
 }
 },

 \listen\: function( key, callback ) {
 if ( !this.notify_stack )
 this.notify_stack = {};

 key = 'g' + key; // Force valid first char
 // console.log( 'listening for: ' + key );
 if ( !this.notify_stack[ key ] )
 this.notify_stack[ key ] = [];

 // Make sure it's not already queued
 for ( a = 0; a < this.notify_stack[ key ].length; a++ ) {
 if ( callback == this.notify_stack[ key ][ a ] ) {
 // console.log( 'already' );
 return;
 }
 }

 this.notify_stack[ key ][ this.notify_stack[ key ].length ] = callback;
 // console.log( 'added listener: ' + key + ' => ' + callback );
 // console.log( this.notify_stack );
 },

 \notify\: function( key ) {
 // console.log( 'trigger notification: ' + key );
 if ( !this.notify_stack )
 this.notify_stack = {};

 key = 'g' + key; // Force valid first char
 if ( !this.notify_stack[ key ] )
 this.notify_stack[ key ] = [];

 // Reverse it so that notifications are sent in the order they were queued
 // console.log( 'notifying key: ' + key + ' (with ' + this.notify_stack[ key ].length + ' listeners)' );
 for ( a = 0; a < this.notify_stack[ key ].length; a++ ) {
 if ( false == this.notify_stack[ key ][ a ] || \undefined\ == typeof( this.notify_stack[ key ][ a ] ) )
 continue;

 // console.log( 'send notification to: ' + this.notify_stack[ key ][ a ] );
 Gravatar[ this.notify_stack[ key ][ a ] ]( key.substr( 1 ) );
 this.notify_stack[ key ][ a ] = false;
 }
 },

 \extract_hash\: function( str ) {
 // Get hash from img src
 hash = /gravatar.com\/avatar\/([0-9a-f]{32})/.exec( jQuery( str ).attr( 'src' ) );
 if ( null != hash && \object\ == typeof( hash ) && 2 == hash.length ) {
 hash = hash[1];
 } else {
 hash = /gravatar_id\=([0-9a-f]{32})/.exec( jQuery( str ).attr( 'src' ) );
 if ( null !== hash && \object\ == typeof( hash ) && 2 == hash.length ) {
 hash = hash[1];
 } else {
 return false;
 }
 }
 return hash;
 },

 \load_js\: function( src, error_handler ) {
 if ( !this.loaded_scripts )
 this.loaded_scripts = [];

 if ( this.loaded_scripts[ src ] )
 return;

 this.loaded_scripts[ src ] = true;

 var new_script = document.createElement( 'script' );
 new_script.src = src;
 new_script.type = 'text/javascript';
 if ( jQuery.isFunction( error_handler ) ) {
 new_script.onerror = error_handler;
 }

 // console.log( src );
 document.getElementsByTagName( 'head' )[0].appendChild( new_script );
 },

 \loaded_js\: function( hash, dom_id ) {
 Gravatar.profile_cb( hash, dom_id );
 },

 \add_card_css\: function() {
 if ( jQuery( '#gravatar-card-css' ).length )
 return;

 var urlS = jQuery( 'script[src*=gravatar.com/js/gprofiles.js]' ), url;
 if ( urlS.size() )
 url = urlS.attr( 'src' ).replace( /\/js\/gprofiles\.js.*$/, '' );
 else
 url = 'http://s.gravatar.com';

 new_css = \<link rel='stylesheet' type='text/css' id='gravatar-card-css' href='\ + url + \/css/hovercard.css?v=2' />\;
 new_css += \<link rel='stylesheet' type='text/css' id='gravatar-card-services-css' href='\ + url + \/css/services.css' />\;

 jQuery( 'head' ).append( new_css );
 // console.log( 'Added CSS for profile cards to DOM' );
 },

 \md5\: function( str ) {
 return hex_md5( str );
 },

 \autofill\: function( email, map ) {
 // console.log('autofill');
 if ( !email.length || -1 == email.indexOf( '@' ) )
 return;

 this.autofill_map = map;
 hash = this.md5( email );
 // console.log( this.profile_stack[ 'g' + hash ] );
 if ( \undefined\ == typeof( this.profile_stack[ 'g' + hash ] ) ) {
 this.listen( hash, 'autofill_data' );
 this.fetch_profile_by_hash( hash );
 } else {
 // console.log( 'stack: ' + this.profile_stack[ 'g' + hash ] );
 this.autofill_data( hash );
 }
 },

 \autofill_data\: function( hash ) {
 // console.log( this.autofill_map );
 // console.log( this.profile_stack[ 'g' + hash ] );
 GProfile.init( this.profile_stack[ 'g' + hash ] );
 for ( var m in this.autofill_map ) {
 // console.log( m );
 // console.log( this.autofill_map[ m ] );
 switch ( m ) {
 case 'url':
 link = GProfile.get( 'urls' );
 // console.log( link );
 jQuery( '#' + this.autofill_map[ m ] ).val( link[0][ 'value' ] );
 break;
 case 'urls':
 links = GProfile.get( 'urls' );
 links_str = '';
 // console.log( links );
 for ( l = 0; l < links.length; l++ ) {
 links_str += links[ l ][ 'value' ] + \\n\;
 }
 jQuery( '#' + this.autofill_map[ m ] ).val( links_str );
 break;
 default:
 parts = m.split( /\./ );
 if ( parts[ 1 ] ) {
 val = GProfile.get( m );
 switch ( parts[ 0 ] ) {
 case 'ims':
 case 'phoneNumbers':
 val = val.value;
 break;
 case 'emails':
 val = val[0].value;
 case 'accounts':
 val = val.url;
 break;
 }
 jQuery( '#' + this.autofill_map[ m ] ).val( val );
 } else {
 jQuery( '#' + this.autofill_map[ m ] ).val( GProfile.get( m ) );
 }
 }
 }
 },

 \whee\: function() {
 if ( Gravatar.whee.didWhee ) {
 return;
 }
 Gravatar.whee.didWhee = true;
 if ( document.styleSheets[0].addRule ) {
 document.styleSheets[0].addRule( '.grav-tag a', 'background-position: 22px 100% !important' );
 } else {
 jQuery( '.grav-tag a' ).css( 'background-position', '22px 100%' );
 }
 jQuery( 'img[src*=gravatar.com/]' ).addClass( 'grav-whee' ).css( {
 '-webkit-box-shadow': '1px 1px 3px #aaa',
 '-moz-box-shadow': '1px 1px 3px #aaa',
 'box-shadow': '1px 1px 3px #aaa',
 'border': '2px white solid'
 } );
 var i = 0;
 setInterval( function() {
 jQuery( '.grav-whee' ).css( {
 '-webkit-transform': 'rotate(-' + i + 'deg) scale(1.3)',
 '-moz-transform': 'rotate(-' + i + 'deg) scale(1.3)',
 'transform': 'rotate(-' + i + 'deg) scale(1.3)'
 });
 i++;
 if ( 360 == i ) {
 i = 0;
 }
 }, 6 );
 return false;
 },

}

jQuery( function() {
 Gravatar.init();
});

/**
 * Provides an interface for acceseing profile data returned from Gravatar.com.
 * Use GProfile.init() to set up data, based on the JSON returned from Gravatar,
 * then GProfile.get() to access data more easily.
 */
var GProfile = {
 \data\: {},

 \init\: function( data ) {
 if ( 'fetching' == data )
 return false;
 if ( 'undefined' == typeof( data.entry[0] ) )
 return false;
 GProfile.data = data.entry[0];
 },

 /**
 * Returns a value from the profile data.
 * @param string attr The name of the attribute you want
 * @param int num (Optional) 0-based array index of the value from this attribute. Use 0 if you're not sure
 * @return Mixed value of the attribute, or empty string.
 */
 \get\: function( attr ) {
 // Handle x.y references
 if ( -1 != attr.indexOf( '.' ) ) {
 parts = attr.split( /\./ );
 // console.log(parts);
 if ( GProfile.data[ parts[ 0 ] ] ) {
 if ( GProfile.data[ parts[ 0 ] ][ parts[ 1 ] ] )
 return GProfile.data[ parts[ 0 ] ][ parts[ 1 ] ]

 for ( i = 0, s = GProfile.data[ parts[ 0 ] ].length; i < s; i++ ) {
 if ( GProfile.data[ parts[ 0 ] ][ i ].type && parts[ 1 ] == GProfile.data[ parts[ 0 ] ][ i ].type // phoneNumbers | ims
 || GProfile.data[ parts[ 0 ] ][ i ].shortname && parts[ 1 ] == GProfile.data[ parts[ 0 ] ][ i ].shortname // accounts
 || GProfile.data[ parts[ 0 ] ][ i ].primary && parts[ 1 ] == 'primary' ) { // emails

 return GProfile.data[ parts[ 0 ] ][ i ];
 }
 }
 }

 return '';
 }

 // Handle \top-level\ elements
 if ( GProfile.data[ attr ] )
 return GProfile.data[ attr ];

 // And some \aliases\
 if ( 'url' == attr ) {
 if ( GProfile.data.urls.length )
 return GProfile.data.urls[0].value;
 }

 return '';
 }
};

var grav_resize = {
 card_id: '',
 orig_width: 0,
 orig_height: 0,
 orig_top: 0,
 orig_left: 0,
 current_image: false,

 init: function( card_id ) {
 grav_resize.card_id = card_id;
 grav_resize.bind_enlarge();
 },

 enlarge: function( el ) {
 /* Remove any enlarged images */
 if ( jQuery('img.grav-large').stop().remove().size() ) {
 grav_resize.current_image = false;
 return;
 }

 grav_resize.current_image = el.attr( 'src' );
 /* Preload the larger version of the image */
 jQuery( '#' + grav_resize.card_id + ' .grav-tag a' ).css( 'background-position', '22px 100%' );
 var fullsize = jQuery('<img />').attr( 'src', grav_resize.current_image + '&size=400' ).load( function() {
 jQuery( '#' + grav_resize.card_id + ' .grav-tag a' ).css( 'background-position', '22px 0' );
 } );

 /* Clone the image */
 var the_clone = el.clone();

 the_clone.css({
 'position': 'absolute',
 'top': grav_resize.orig_top,
 'left': grav_resize.orig_left,
 'background-color': '#333',
 'width': grav_resize.orig_width,
 'height': grav_resize.orig_height,
 'border-color': '#555'
 });

 the_clone.appendTo(el.parent());

 /* Get the image ratio */
 var    horiz_padding = 0;
 var    vert_padding = 0;
 var border_width = 6;
 var card = jQuery( '#' + grav_resize.card_id + ' .grav-inner' );

 if ( el.width() > el.height() ) {
 var ratio = el.height() / el.width();
 var width = card.outerWidth();
 var height = ( width * ratio );
 var vert_padding = ( card.outerHeight() - height ) / 2;

 // if height it too big resize it width wise.
 if ( height > card.outerHeight() ) {
 var ratio = el.width() / el.height();
 var height = card.outerHeight();
 var width = ( height * ratio );
 var horiz_padding = ( card.outerWidth() - width ) / 2;
 }

 } else {
 var ratio = el.width() / el.height();
 var height = card.outerHeight();
 var width = ( height * ratio );
 var horiz_padding = ( card.outerWidth() - width ) / 2;
 }

 the_clone.stop().animate({
 'top': 0,
 'left': 0,
 'width': width - border_width + 'px',
 'height': height - border_width + 'px',
 'z-index': 99,
 'padding-left': horiz_padding + 'px',
 'padding-right': horiz_padding + 'px',
 'padding-top': vert_padding + 'px',
 'padding-bottom': vert_padding + 'px'
 }, 250, function() {
 /* Make the clone the fullsize image that was preloaded */
 the_clone.addClass('grav-large');
 the_clone.attr('src', fullsize.attr('src') );

 /* Add the close button */
 the_clone.parent().append('<div>X</div>');
 jQuery('.grav-large-close').hide().fadeIn(100);
 } );

 jQuery('#'+grav_resize.card_id+' .grav-gallery img').unbind('click');

 jQuery('.grav-large-close' ).live( 'click', function() {
 grav_resize.reduce( the_clone );
 });

 jQuery(the_clone).click( function() {
 grav_resize.reduce( the_clone );
 });
 },

 reduce: function( el ) {
 jQuery('.grav-large-close').remove();

 el.stop().animate({
 'top': grav_resize.orig_top,
 'left': grav_resize.orig_left,
 'width': grav_resize.orig_width,
 'height': grav_resize.orig_height,
 'padding-left': 0,
 'padding-right': 0,
 'padding-top': 0,
 'padding-bottom': 0
 }, 250, function() {
 jQuery('img.grav-large').remove();
 grav_resize.bind_enlarge( grav_resize.card_id );
 grav_resize.current_image = false;
 });
 },

 bind_enlarge: function() {
 jQuery('#' + grav_resize.card_id + ' .grav-gallery img').parent( 'a' ).click( function(e) {
 if ( jQuery.browser.msie && jQuery.browser.version < 9.0 )
 return;

 e.preventDefault();

 if ( grav_resize.current_image ) {
 return;
 }

 var img = jQuery(this).find( 'img' ).not( '.grav-large' );
 var position = img.position();

 grav_resize.orig_width = img.width();
 grav_resize.orig_height = img.height();
 grav_resize.orig_top = position.top;
 grav_resize.orig_left = position.left;

 grav_resize.enlarge( img );
 });
 }
}

var grav_gallery = {
 orig_left: 0,
 pos: 0,

 init: function( card ) {
 grav_gallery.bind_arrows( card, true );

 /* Also recheck the arrows are correct once the user hovers over the gallery section, in case the images took a while to load */
 jQuery('#' + card + ' .grav-gallery').mouseover( function() {
 grav_gallery.bind_arrows( card, false );
 });
 },

 bind_arrows: function( card, reset ) {
 var gallery_el = jQuery('#' + card + ' .grav-gallery ul');
 if ( !gallery_el.size() ) {
 return;
 }
 grav_gallery.orig_left = gallery_el.css('margin-left').replace('px','');
 grav_gallery.pos = gallery_el.find( 'li:last').position();

 jQuery('#' + card + ' a.grav-gallery-next').live( 'click', function() {
 if ( grav_gallery.pos.left > 275 )
 gallery_el.animate({'margin-left': parseFloat(grav_gallery.orig_left) - 314 + 'px'}, 300, function() { grav_gallery.highlight_arrows( card, false ); } );

 return false;
 });

 jQuery('#' + card + ' a.grav-gallery-prev').live( 'click', function() {
 if ( 0 != grav_gallery.orig_left )
 gallery_el.animate({'margin-left': parseFloat(grav_gallery.orig_left) + 314 + 'px'}, 300, function() { grav_gallery.highlight_arrows( card, false ) } );

 return false;
 });

 if ( reset )
 jQuery('#' + card + ' .grav-gallery ul').css({'margin-left': 0});

 grav_gallery.highlight_arrows( card, true );
 },

 highlight_arrows: function( card ) {
 grav_gallery.orig_left = jQuery('#' + card + ' .grav-gallery ul').css('margin-left').replace('px','');
 grav_gallery.last = jQuery('#' + card + ' .grav-gallery ul li:last');

 if ( grav_gallery.last.position().left < 275 )
 jQuery('#' + card + ' a.grav-gallery-next').css({'background-position': '-39px 0'});
 else
 jQuery('#' + card + ' a.grav-gallery-next').css({'background-position': '-26px 0'});

 if ( 0 != grav_gallery.orig_left )
 jQuery('#' + card + ' a.grav-gallery-prev').css({'background-position': '0 0'});
 else
 jQuery('#' + card + ' a.grav-gallery-prev').css({'background-position': '-13px 0'});
 }
}

/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

var hexcase=0;var b64pad=\\;var chrsz=8;function hex_md5(s){return binl2hex(core_md5(str2binl(s),s.length*chrsz))}function b64_md5(s){return binl2b64(core_md5(str2binl(s),s.length*chrsz))}function str_md5(s){return binl2str(core_md5(str2binl(s),s.length*chrsz))}function hex_hmac_md5(a,b){return binl2hex(core_hmac_md5(a,b))}function b64_hmac_md5(a,b){return binl2b64(core_hmac_md5(a,b))}function str_hmac_md5(a,b){return binl2str(core_hmac_md5(a,b))}function md5_vm_test(){return hex_md5(\abc\)==\900150983cd24fb0d6963f7d28e17f72\}function core_md5(x,e){x[e>>5]|=0x80<<((e)%32);x[(((e+64)>>>9)<<4)+14]=e;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;for(var i=0;i<x.length;i+=16){var f=a;var g=b;var h=c;var j=d;a=md5_ff(a,b,c,d,x[i+0],7,-680876936);d=md5_ff(d,a,b,c,x[i+1],12,-389564586);c=md5_ff(c,d,a,b,x[i+2],17,606105819);b=md5_ff(b,c,d,a,x[i+3],22,-1044525330);a=md5_ff(a,b,c,d,x[i+4],7,-176418897);d=md5_ff(d,a,b,c,x[i+5],12,1200080426);c=md5_ff(c,d,a,b,x[i+6],17,-1473231341);b=md5_ff(b,c,d,a,x[i+7],22,-45705983);a=md5_ff(a,b,c,d,x[i+8],7,1770035416);d=md5_ff(d,a,b,c,x[i+9],12,-1958414417);c=md5_ff(c,d,a,b,x[i+10],17,-42063);b=md5_ff(b,c,d,a,x[i+11],22,-1990404162);a=md5_ff(a,b,c,d,x[i+12],7,1804603682);d=md5_ff(d,a,b,c,x[i+13],12,-40341101);c=md5_ff(c,d,a,b,x[i+14],17,-1502002290);b=md5_ff(b,c,d,a,x[i+15],22,1236535329);a=md5_gg(a,b,c,d,x[i+1],5,-165796510);d=md5_gg(d,a,b,c,x[i+6],9,-1069501632);c=md5_gg(c,d,a,b,x[i+11],14,643717713);b=md5_gg(b,c,d,a,x[i+0],20,-373897302);a=md5_gg(a,b,c,d,x[i+5],5,-701558691);d=md5_gg(d,a,b,c,x[i+10],9,38016083);c=md5_gg(c,d,a,b,x[i+15],14,-660478335);b=md5_gg(b,c,d,a,x[i+4],20,-405537848);a=md5_gg(a,b,c,d,x[i+9],5,568446438);d=md5_gg(d,a,b,c,x[i+14],9,-1019803690);c=md5_gg(c,d,a,b,x[i+3],14,-187363961);b=md5_gg(b,c,d,a,x[i+8],20,1163531501);a=md5_gg(a,b,c,d,x[i+13],5,-1444681467);d=md5_gg(d,a,b,c,x[i+2],9,-51403784);c=md5_gg(c,d,a,b,x[i+7],14,1735328473);b=md5_gg(b,c,d,a,x[i+12],20,-1926607734);a=md5_hh(a,b,c,d,x[i+5],4,-378558);d=md5_hh(d,a,b,c,x[i+8],11,-2022574463);c=md5_hh(c,d,a,b,x[i+11],16,1839030562);b=md5_hh(b,c,d,a,x[i+14],23,-35309556);a=md5_hh(a,b,c,d,x[i+1],4,-1530992060);d=md5_hh(d,a,b,c,x[i+4],11,1272893353);c=md5_hh(c,d,a,b,x[i+7],16,-155497632);b=md5_hh(b,c,d,a,x[i+10],23,-1094730640);a=md5_hh(a,b,c,d,x[i+13],4,681279174);d=md5_hh(d,a,b,c,x[i+0],11,-358537222);c=md5_hh(c,d,a,b,x[i+3],16,-722521979);b=md5_hh(b,c,d,a,x[i+6],23,76029189);a=md5_hh(a,b,c,d,x[i+9],4,-640364487);d=md5_hh(d,a,b,c,x[i+12],11,-421815835);c=md5_hh(c,d,a,b,x[i+15],16,530742520);b=md5_hh(b,c,d,a,x[i+2],23,-995338651);a=md5_ii(a,b,c,d,x[i+0],6,-198630844);d=md5_ii(d,a,b,c,x[i+7],10,1126891415);c=md5_ii(c,d,a,b,x[i+14],15,-1416354905);b=md5_ii(b,c,d,a,x[i+5],21,-57434055);a=md5_ii(a,b,c,d,x[i+12],6,1700485571);d=md5_ii(d,a,b,c,x[i+3],10,-1894986606);c=md5_ii(c,d,a,b,x[i+10],15,-1051523);b=md5_ii(b,c,d,a,x[i+1],21,-2054922799);a=md5_ii(a,b,c,d,x[i+8],6,1873313359);d=md5_ii(d,a,b,c,x[i+15],10,-30611744);c=md5_ii(c,d,a,b,x[i+6],15,-1560198380);b=md5_ii(b,c,d,a,x[i+13],21,1309151649);a=md5_ii(a,b,c,d,x[i+4],6,-145523070);d=md5_ii(d,a,b,c,x[i+11],10,-1120210379);c=md5_ii(c,d,a,b,x[i+2],15,718787259);b=md5_ii(b,c,d,a,x[i+9],21,-343485551);a=safe_add(a,f);b=safe_add(b,g);c=safe_add(c,h);d=safe_add(d,j)}return Array(a,b,c,d)}function md5_cmn(q,a,b,x,s,t){return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b)}function md5_ff(a,b,c,d,x,s,t){return md5_cmn((b&c)|((~b)&d),a,b,x,s,t)}function md5_gg(a,b,c,d,x,s,t){return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t)}function md5_hh(a,b,c,d,x,s,t){return md5_cmn(b^c^d,a,b,x,s,t)}function md5_ii(a,b,c,d,x,s,t){return md5_cmn(c^(b|(~d)),a,b,x,s,t)}function core_hmac_md5(a,b){var c=str2binl(a);if(c.length>16)c=core_md5(c,a.length*chrsz);var d=Array(16),opad=Array(16);for(var i=0;i<16;i++){d[i]=c[i]^0x36363636;opad[i]=c[i]^0x5C5C5C5C}var e=core_md5(d.concat(str2binl(b)),512+b.length*chrsz);return core_md5(opad.concat(e),512+128)}function safe_add(x,y){var a=(x&0xFFFF)+(y&0xFFFF);var b=(x>>16)+(y>>16)+(a>>16);return(b<<16)|(a&0xFFFF)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))}function str2binl(a){var b=Array();var c=(1<<chrsz)-1;for(var i=0;i<a.length*chrsz;i+=chrsz)b[i>>5]|=(a.charCodeAt(i/chrsz)&c)<<(i%32);return b}function binl2str(a){var b=\\;var c=(1<<chrsz)-1;for(var i=0;i<a.length*32;i+=chrsz)b+=String.fromCharCode((a[i>>5]>>>(i%32))&c);return b}function binl2hex(a){var b=hexcase?\0123456789ABCDEF\:\0123456789abcdef\;var c=\\;for(var i=0;i<a.length*4;i++){c+=b.charAt((a[i>>2]>>((i%4)*8+4))&0xF)+b.charAt((a[i>>2]>>((i%4)*8))&0xF)}return c}function binl2b64(a){var b=\ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\;var c=\\;for(var i=0;i<a.length*4;i+=3){var d=(((a[i>>2]>>8*(i%4))&0xFF)<<16)|(((a[i+1>>2]>>8*((i+1)%4))&0xFF)<<8)|((a[i+2>>2]>>8*((i+2)%4))&0xFF);for(var j=0;j<4;j++){if(i*8+j*6>a.length*32)c+=b64pad;else c+=b.charAt((d>>6*(3-j))&0x3F)}}return c};

Minimiert man das ganze noch mit einem JSMinifier wie diesem, schrumpft das ganz noch einmal deutlich ein.
Die so erhaltene Datei (Hier zum Download: Hovercard.js.gz )
Läd man z.B. in MEINBLOG/wp-includes/js und trägt folgendes in die funtions.php des Themes ein:

  1. //GRavatar
  2. wp_enqueue_script( 'gprofiles', '/wp-includes/js/Hovercard.js', array( 'jquery' ), 'e', TRUE );
  3. ?>
//GRavatar
wp_enqueue_script( 'gprofiles', '/wp-includes/js/Hovercard.js', array( 'jquery' ), 'e', TRUE );
?>

Update: Der Minimierte Code geht noch nicht!!! Nur die ungepackte Version funktioniert!!!

flattr this!

Diesen Artikel weiterempfehlen:



Diese Artikel könnten dich auch interessieren:

Leave a Reply

Required fields are marked *.


This Blog will give regular Commentators DoFollow Status. Implemented from IT Blögg