diff --git a/app/controllers/albums_controller.rb b/app/controllers/albums_controller.rb
index 2fb5ac47f41b3c52574a882f260c9fc2e9b4fbfb..fe33376f3793953e86767f422fcb5d7aa794d5bb 100644
--- a/app/controllers/albums_controller.rb
+++ b/app/controllers/albums_controller.rb
@@ -12,7 +12,8 @@ class AlbumsController < ApplicationController
       flash[:notice] = "Successfully created album."
       redirect_to @album
     else
-      render :action => 'new'
+      flash[:error] = "Successfully failed."
+      redirect_to albums_path
     end
   end
   
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c525ad1cdde6d1612d1c38d362627ec4127c4806..c3b74a8611ea6257c286a06096beaf6a400d9232 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -16,9 +16,12 @@ class ApplicationController < ActionController::Base
   end
   
   def set_friends_and_status
-    @friends = Person.friends.all if current_user
-    @latest_status_message = StatusMessage.newest(current_user) if current_user
-    
+    if current_user
+      @groups = current_user.groups 
+      @friends = current_user.friends
+      @latest_status_message = StatusMessage.newest_for(current_user.person)
+      @group = params[:group] ? current_user.group_by_id(params[:group]) : current_user.groups.first 
+    end
   end
 
   def count_requests
diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb
index a74b12e433e0c413a81fec0c5c2ba3037df2f9ca..4075e04edfdc58e7c35c833f37fa9519f9dbe1e8 100644
--- a/app/controllers/blogs_controller.rb
+++ b/app/controllers/blogs_controller.rb
@@ -24,7 +24,6 @@ class BlogsController < ApplicationController
 
     if @blog.created_at
       flash[:notice] = "Successfully created blog."
-      redirect_to @blog
     else
       render :action => 'new'
     end
diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb
index 79bf76d12e1083cce4b8f9ffc6a681f90c72f21b..5d9959732f65750632a2c7f99f185ce08df6c368 100644
--- a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -4,11 +4,6 @@ class BookmarksController < ApplicationController
   def index
     @bookmark = Bookmark.new
     @bookmarks = Bookmark.paginate :page => params[:page], :order => 'created_at DESC'
-    
-
-    respond_to do |format|
-      format.html 
-    end
   end
   
   def edit
@@ -34,7 +29,6 @@ class BookmarksController < ApplicationController
 
     if @bookmark.created_at
       flash[:notice] = "Successfully created bookmark."
-      redirect_to @bookmark
     else
       render :action => 'new'
     end
diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb
deleted file mode 100644
index 438163fffe7c081961593602f1f47c00827b8c46..0000000000000000000000000000000000000000
--- a/app/controllers/dashboards_controller.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class DashboardsController < ApplicationController
-  before_filter :authenticate_user!
-  include ApplicationHelper
-
-  def index
-    @posts = Post.paginate :page => params[:page], :order => 'created_at DESC'
-  end
-
-  end
diff --git a/app/controllers/dev_utilities_controller.rb b/app/controllers/dev_utilities_controller.rb
index f5f96683f9f50294cab08121ce29006a570c8b53..a9711164ebac83917726431c84e34d378511ad51 100644
--- a/app/controllers/dev_utilities_controller.rb
+++ b/app/controllers/dev_utilities_controller.rb
@@ -1,33 +1,37 @@
 class DevUtilitiesController < ApplicationController
-  before_filter :authenticate_user!
+  before_filter :authenticate_user!, :except => [:set_backer_number]
   include ApplicationHelper
+  include RequestsHelper
 def warzombie
     render :nothing => true
-    if User.owner.email == "tom@tom.joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil
-      StatusMessage.create(:message => "There's a bomb in the lasagna!?", :person => User.owner) 
-      Bookmark.create(:title => "xkcd", :link => "http://xkcd.com/743/", :person => User.owner )
-      StatusMessage.create(:message => "I switched to Motoroi today, a Motorola Android-based phone, in Korea. Now, I am using Android phones in both the U.S. and Korea", :person => User.owner, :created_at => Time.now-930)
-      StatusMessage.create(:message => "I had 5 hours to study for it :-( GREs on Thursday. Wunderbar.", :person => User.owner, :created_at => Time.now-43990)
-      StatusMessage.create(:message => "Spotted in toy story 3: google maps, OSX, and windows XP. Two out of three isn't bad.", :person => User.owner, :created_at => Time.now-4390)
-      Bookmark.create( :title => "Reddit", :link => "http://reddit.com", :person => User.owner, :created_at => Time.now-54390)
-      Blog.create(:title => "I Love Rock'N'Roll - Joan Jett & The Blackhearts", :body => "<p>The loudspeakers played this song as we walked into the city pool for the first time this summer.  Those loudspeakers make every song sound fresh even if I have heard it a thousand times and their effect on this song was no different. Joan sounded young and strong and ready, and for a moment I forgot where or when I was.</p> <p>also i can tell it won’t be long and also happy summer imaginary constructs -mumblelard</p>", :person => User.owner, :created_at => Time.now-3090)  
-      StatusMessage.create(:message => "Commercials for IE make me SO MAD and my friends just don't get why.", :person => User.owner, :created_at => Time.now-30900)
-      Bookmark.create(:title => "Zombo.com", :link => "http://zombo.com", :person => User.owner, :created_at => Time.now-9090) 
-      StatusMessage.create(:message => "Why do I have \"No More Heroes\" by Westlife on repeat all day?", :person => User.owner, :created_at => Time.now-590000)
-      StatusMessage.create(:message => "Mmm. Friday night. Acknowledged.", :person => User.owner, :created_at => Time.now-503900)
-      StatusMessage.create(:message => "Getting a universal remote is the epitome of laziness, I do declare.", :person => User.owner, :created_at => Time.now-4400)
-      StatusMessage.create(:message => "Does anyone know how to merge two Skype contact entries of the same person? (i.e. one Skype ID and one mobile number)", :person => User.owner, :created_at => Time.now-400239)
-      StatusMessage.create(:message => "A cool, cool morning for once.", :person => User.owner, :created_at => Time.now-150000)
+    if current_user.email == "tom@tom.joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil
+      current_user.post(:status_message, :message => "There's a bomb in the lasagna!?") 
+      current_user.post(:bookmark, :title => "xkcd", :link => "http://xkcd.com/743/" )
+      current_user.post(:status_message, :message => "I switched to Motoroi today, a Motorola Android-based phone, in Korea. Now, I am using Android phones in both the U.S. and Korea", :created_at => Time.now-930)
+      current_user.post(:status_message, :message => "I had 5 hours to study for it :-( GREs on Thursday. Wunderbar.", :created_at => Time.now-43990)
+      current_user.post(:status_message, :message => "Spotted in toy story 3: google maps, OSX, and windows XP. Two out of three isn't bad.", :created_at => Time.now-4390)
+      current_user.post(:bookmark,  :title => "Reddit", :link => "http://reddit.com", :created_at => Time.now-54390)
+      current_user.post(:blog, :title => "I Love Rock'N'Roll - Joan Jett & The Blackhearts", :body => "<p>The loudspeakers played this song as we walked into the city pool for the first time this summer.  Those loudspeakers make every song sound fresh even if I have heard it a thousand times and their effect on this song was no different. Joan sounded young and strong and ready, and for a moment I forgot where or when I was.</p> <p>also i can tell it won’t be long and also happy summer imaginary constructs -mumblelard</p>", :created_at => Time.now-3090)  
+      current_user.post(:status_message, :message => "Commercials for IE make me SO MAD and my friends just don't get why.", :created_at => Time.now-30900)
+      current_user.post(:bookmark, :title => "Zombo.com", :link => "http://zombo.com", :created_at => Time.now-9090) 
+      current_user.post(:status_message, :message => "Why do I have \"No More Heroes\" by Westlife on repeat all day?", :created_at => Time.now-590000)
+      current_user.post(:status_message, :message => "Mmm. Friday night. Acknowledged.", :created_at => Time.now-503900)
+      current_user.post(:status_message, :message => "Getting a universal remote is the epitome of laziness, I do declare.", :created_at => Time.now-4400)
+      current_user.post(:status_message, :message => "Does anyone know how to merge two Skype contact entries of the same person? (i.e. one Skype ID and one mobile number)", :created_at => Time.now-400239)
+      current_user.post(:status_message, :message => "A cool, cool morning for once.", :created_at => Time.now-150000)
     end
   end
 
   def zombiefriends
     render :nothing => true
-    backer_info
-    if User.owner.email == "tom@tom.joindiaspora.com" && Person.friends.first.nil? 
-      backer_info.each do |backer|
+    bkr_info  = backer_info
+
+    if current_user.email == "tom@tom.joindiaspora.com" 
+      bkr_info.each do |backer|
+        backer_email = "#{backer['username']}@#{backer['username']}.joindiaspora.com"
+        rel_hash = relationship_flow(backer_email)
         logger.info "Zombefriending #{backer['given_name']} #{backer['family_name']}"
-        User.owner.send_friend_request_to("http://#{backer['username']}.joindiaspora.com/")
+        current_user.send_request(rel_hash, current_user.groups.first.id)
       end
     end
   end
@@ -35,7 +39,7 @@ def warzombie
   def zombiefriendaccept
     render :nothing => true
     Request.all.each{|r| 
-      User.owner.accept_friend_request(r.id)
+      current_user.accept_and_respond(r.id, current_user.groups.first.id)
     }
   end
 
@@ -44,4 +48,11 @@ def warzombie
     config['servers']['backer']
   end
 
+  def set_backer_number
+    render :nothing => true
+    seed_num_hash = {:seed_number => params[:number]}
+    file = File.new(Rails.root.join('config','backer_number.yml'),'w')
+    file.write(seed_num_hash.to_yaml)
+    file.close
+  end
 end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f3da1ec8ac15b9aa4eaec57279e10f7ec5e9632b
--- /dev/null
+++ b/app/controllers/groups_controller.rb
@@ -0,0 +1,50 @@
+class GroupsController < ApplicationController
+  before_filter :authenticate_user!
+
+  def index
+    @posts = Post.paginate :page => params[:page], :order => 'created_at DESC'
+  end
+
+  def create
+    @group = current_user.group(params[:group])
+    
+    if @group.created_at
+      flash[:notice] = "Successfully created group."
+      redirect_to @group
+    else
+      render :action => 'new'
+    end
+  end
+  
+  def new
+    @group = Group.new
+  end
+  
+  def destroy
+    @group = Group.first(:id => params[:id])
+    @group.destroy
+    flash[:notice] = "Successfully destroyed group."
+    redirect_to groups_url
+  end
+  
+  def show
+    @people_ids = @group.people.map {|p| p.id}
+    @posts = Post.paginate :person_id => @people_ids, :order => 'created_at DESC'
+    @group = Group.first(:id => params[:id])
+  end
+
+  def edit
+    @group = Group.first(:id => params[:id])
+  end
+
+  def update
+    @group = Group.first(:id => params[:id])
+    if @group.update_attributes(params[:group])
+      flash[:notice] = "Successfully updated group."
+      redirect_to @group
+    else
+      render :action => 'edit'
+    end
+  end
+
+end
diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb
index ec98269679e4807b9c3e2c01309bad56d4d82b30..e161f6acded699c35bd8e51e452caac9bc0a90e3 100644
--- a/app/controllers/people_controller.rb
+++ b/app/controllers/people_controller.rb
@@ -3,7 +3,7 @@ class PeopleController < ApplicationController
   
   def index
     unless params[:q]
-      @people = Person.friends.paginate :page => params[:page], :order => 'created_at DESC'
+      @people = current_user.friends.paginate :page => params[:page], :order => 'created_at DESC'
       render :index
     else
       @people = Person.search_for_friends(params[:q])
@@ -12,15 +12,16 @@ class PeopleController < ApplicationController
   end
   
   def show
-    @person= Person.where(:id => params[:id]).first
+    @person= current_user.friend_by_id(params[:id])
+  
     @person_profile = @person.profile
     @person_posts = Post.where(:person_id => @person.id).paginate :page => params[:page], :order => 'created_at DESC'
-    @latest_status_message = StatusMessage.newest(@person)
+    @latest_status_message = StatusMessage.newest_for(@person)
     @post_count = @person_posts.count
   end
   
   def destroy
-    current_user.unfriend(params[:id])
+    current_user.unfriend(current_user.friend_by_id(params[:id]))
     flash[:notice] = "unfriended person."
     redirect_to people_url
   end
diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb
index 128115d6af62f907c256b000303e21ea1d008736..2996a23ecd8e145f3c5b9b6d288cbb2f14809ff4 100644
--- a/app/controllers/photos_controller.rb
+++ b/app/controllers/photos_controller.rb
@@ -7,7 +7,6 @@ class PhotosController < ApplicationController
 
       if @photo.created_at
         flash[:notice] = "Successfully uploaded photo."
-        redirect_to @photo.album
       else
         render :action => 'album#new'
       end
@@ -25,14 +24,14 @@ class PhotosController < ApplicationController
   end
   
   def destroy
-    @photo = Photo.where(:id => params[:id]).first
+    @photo = Photo.first(:id => params[:id])
     @photo.destroy
     flash[:notice] = "Successfully deleted photo."
     redirect_to @photo.album
   end
   
   def show
-    @photo = Photo.where(:id => params[:id]).first
+    @photo = Photo.first(:id => params[:id])
     @album = @photo.album
   end
 
diff --git a/app/controllers/publics_controller.rb b/app/controllers/publics_controller.rb
index 128999d093c48b9e67f359df229f6e1e7fd00888..91edf995d9776deb4a8f96e39e429a4ae89388b8 100644
--- a/app/controllers/publics_controller.rb
+++ b/app/controllers/publics_controller.rb
@@ -3,23 +3,28 @@ class PublicsController < ApplicationController
   include Diaspora::Parser
   
   def hcard
-    @user = User.owner
-    render 'hcard'
+    @person = Person.first(:_id => params[:id])
+
+    unless @person.nil? || @person.owner.nil?
+      render 'hcard'
+    end
   end
 
   def host_meta
-    @user = User.owner
     render 'host_meta', :layout => false, :content_type => 'application/xrd+xml'
   end
 
   def webfinger
-    @user = Person.first(:email => params[:q].gsub('acct:', ''))
-    render 'webfinger', :layout => false, :content_type => 'application/xrd+xml'
+    @person = Person.by_webfinger(params[:q])
+    unless @person.nil? || @person.owner.nil?
+      render 'webfinger', :layout => false, :content_type => 'application/xrd+xml'
+    end
   end
   
   def receive
-    puts "SOMEONE JUST SENT ME: #{params[:xml]}"
-    store_objects_from_xml params[:xml]
+    @user = Person.first(:id => params[:id]).owner
+    Rails.logger.debug "PublicsController has received: #{params[:xml]}"
+    @user.receive params[:xml] if params[:xml]
     render :nothing => true
   end
   
diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb
index 39f9c8376e8002387f25aa45f53f33714f787d1b..f5c73660fd7277f847780a1907cf9f401414fc8f 100644
--- a/app/controllers/requests_controller.rb
+++ b/app/controllers/requests_controller.rb
@@ -8,10 +8,16 @@ class RequestsController < ApplicationController
   
   def destroy
     if params[:accept]
-      @friend = current_user.accept_friend_request params[:id]
-      
-      flash[:notice] = "you are now friends"
-      redirect_to root_url 
+
+      if params[:group_id]
+        @friend = current_user.accept_and_respond( params[:id], params[:group_id])
+        
+        flash[:notice] = "you are now friends"
+        redirect_to root_url 
+      else
+        flash[:error] = "please select a group!"
+        redirect_to requests_url
+      end
     else
       current_user.ignore_friend_request params[:id]
       flash[:notice] = "ignored friend request"
@@ -26,8 +32,8 @@ class RequestsController < ApplicationController
   
   def create
     rel_hash = relationship_flow(params[:request][:destination_url])
-    Rails.logger.info("Sending request: #{rel_hash}")
-    @request = current_user.send_request(rel_hash)
+    Rails.logger.debug("Sending request: #{rel_hash}")
+    @request = current_user.send_request(rel_hash, params[:request][:group])
 
     if @request
       flash[:notice] = "a friend request was sent to #{@request.destination_url}"
@@ -43,9 +49,4 @@ class RequestsController < ApplicationController
     end
   end
 
-
-  
-  private 
-
-
 end
diff --git a/app/controllers/sockets_controller.rb b/app/controllers/sockets_controller.rb
index e25472d52de9a5ff4e21aa51c831323acbeafedc..802aa9cb57bc292fbde0e1f5eb0806b517138f53 100644
--- a/app/controllers/sockets_controller.rb
+++ b/app/controllers/sockets_controller.rb
@@ -2,22 +2,14 @@ class SocketsController < ApplicationController
   include ApplicationHelper
   include SocketsHelper
   include Rails.application.routes.url_helpers
-  before_filter :authenticate_user! 
 
   def incoming(msg)
-    puts "#{msg} connected!"
+    puts "Got a connection to: #{msg}"
   end
   
-  def new_subscriber
-    WebSocket.subscribe
-  end
-  
-  def outgoing(object)
+  def outgoing(uid,object)
     @_request = ActionDispatch::Request.new({})
-    WebSocket.push_to_clients(action_hash(object))
+    Diaspora::WebSocket.push_to_user(uid, action_hash(uid, object))
   end
   
-  def delete_subscriber(sid)
-    WebSocket.unsubscribe(sid)
-  end
 end
diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb
index f499492e83521bab7e577eaf5a12129bd63763b9..f941389a55d20954de3936b766a860063ea005ee 100644
--- a/app/controllers/status_messages_controller.rb
+++ b/app/controllers/status_messages_controller.rb
@@ -1,5 +1,5 @@
 class StatusMessagesController < ApplicationController
-  #before_filter :authenticate_user!
+  before_filter :authenticate_user!
 
   def index
     @status_messages = StatusMessage.paginate :page => params[:page], :order => 'created_at DESC'
@@ -16,7 +16,6 @@ class StatusMessagesController < ApplicationController
     
     if @status_message.created_at
       flash[:notice] = "Successfully created status message."
-      redirect_to status_messages_url
     else
       render :action => 'new'
     end
@@ -38,7 +37,7 @@ class StatusMessagesController < ApplicationController
     
     respond_to do |format|
       format.html 
-      format.xml { render :xml => Post.build_xml_for(@status_message) }
+      format.xml { render :xml => @status_message.build_xml_for }
       format.json { render :json => @status_message }
     end
   end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 9b4411c7a3638c955f626e191bd389c1d2a0dfcd..12f87c481511d9289522d81abe1cf43b0f163015 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,12 +1,12 @@
 class UsersController < ApplicationController
+  before_filter :authenticate_user!, :except => [:new, :create]
 
-  before_filter :authenticate_user!
   def index
     @users = User.sort(:created_at.desc).all
   end
   def show
-    @user= Person.first(:id => params[:id])
-    @user_profile = @user.profile
+    @user= User.first(:id => params[:id])
+    @user_profile = @user.person.profile
   end
 
   def edit
@@ -25,4 +25,20 @@ class UsersController < ApplicationController
       render :action => 'edit'
     end
   end
+
+  def create
+    @user = User.instantiate(params[:user])
+   
+    if @user.created_at && @user.person.created_at 
+      flash[:notice] = "Successfully signed up."
+      redirect_to root_path
+    else
+      render :action => 'new'
+    end
+  end
+
+  def new
+    @user = User.new
+  end
+  
 end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2e2895fbb79d92e22bb35e9e2141ca9107c22172..7f6a7bae23737ec4829d0a30adddd65253a40b60 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -8,7 +8,7 @@ module ApplicationHelper
   end
 
   def mine?(post)
-    post.person == User.owner
+    current_user.owns? post
   end
   
   def type_partial(post)
@@ -31,12 +31,12 @@ module ApplicationHelper
     end
   end
 
-  def link_to_person(person)
-    link_to person.real_name, person_path(person)
+  def owner_image_tag
+    person_image_tag(current_user)
   end
 
-  def owner_image_tag
-    person_image_tag(User.owner)
+  def owner_image_link
+    person_image_link(current_user)
   end
 
   def person_image_tag(person)
@@ -50,10 +50,6 @@ module ApplicationHelper
     link_to person_image_tag(person), object_path(person)
   end
 
-  def owner_image_link
-    person_image_link(User.owner)
-  end
-
   def new_request(request_count)
     "new_requests" if request_count > 0
   end
diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb
index a94d176adc47b355a2ff18278d10307bb0cc297a..b1e4df9cdef74ea419215ae9a46f15c0e843484c 100644
--- a/app/helpers/comments_helper.rb
+++ b/app/helpers/comments_helper.rb
@@ -1,9 +1,3 @@
 module CommentsHelper
-  def target
-    
-  end
-  
-  def text
-    params[:comment][:text]
-  end
+
 end
diff --git a/app/helpers/photos_helper.rb b/app/helpers/photos_helper.rb
index b858aaf7e111a6720ab89d0639f1393071444eed..b9231fe948bcce634185995a02a31a21d1494cf2 100644
--- a/app/helpers/photos_helper.rb
+++ b/app/helpers/photos_helper.rb
@@ -5,7 +5,7 @@ module PhotosHelper
   end
 
   def link_to_prev(photo, album)
-    link_to "<< previous", photo_path(album.prev_photo(photo)), :rel => "prefetch"
+    link_to "<< prev", photo_path(album.prev_photo(photo)), :rel => "prefetch"
   end
 
   def link_to_next(photo, album)
diff --git a/app/helpers/publics_helper.rb b/app/helpers/publics_helper.rb
index e694adef9ed68bdaf8a01880d12a28e93fb559c9..1e8ecac8fb6b5030198a02c36382a251da0a1fb8 100644
--- a/app/helpers/publics_helper.rb
+++ b/app/helpers/publics_helper.rb
@@ -14,4 +14,11 @@ module PublicsHelper
       400
     end
   end
-end
\ No newline at end of file
+
+  def terse_url(full_url)
+    terse = full_url.gsub(/https?:\/\//, '')
+    terse.gsub!(/www\./, '')
+    terse = terse.chop! if terse[-1, 1] == '/'
+    terse
+  end
+end
diff --git a/app/helpers/requests_helper.rb b/app/helpers/requests_helper.rb
index 4404ec223044bff72a3f923c4fe44b3d9fa45789..16a50a886e8c38060ae3b96afecab32449635701 100644
--- a/app/helpers/requests_helper.rb
+++ b/app/helpers/requests_helper.rb
@@ -26,10 +26,16 @@ module RequestsHelper
   end
 
   def relationship_flow(identifier)
-    f = Redfinger.finger(identifier)
-    action = subscription_mode(f)
-    url = subscription_url(action, f)
-    
+    puts request.host
+    if identifier.include?(request.host)
+      person = Person.by_webfinger identifier
+      action = (person == current_user.person ? :none : :friend)
+      url = person.owner.receive_url
+    else
+      f = Redfinger.finger(identifier)
+      action = subscription_mode(f)
+      url = subscription_url(action, f)
+    end
     { action => url }
   end
 
diff --git a/app/helpers/sockets_helper.rb b/app/helpers/sockets_helper.rb
index f13576306475f4a346c07fc6fc9bc9cf60e59937..b357803998fd6b62227aa313ee95c5432ed551cd 100644
--- a/app/helpers/sockets_helper.rb
+++ b/app/helpers/sockets_helper.rb
@@ -5,17 +5,16 @@ module SocketsHelper
     (object.is_a? Post) ? object.id : object.post_id
   end
   
-  def url_options
-    {:host => ""}
-  end
+  #def url_options
+  #  {:host => ""}
+  #end
 
-  def action_hash(object)
+  def action_hash(uid, object)
     begin
-      v = render_to_string(:partial => type_partial(object), :locals => {:post => object}) unless object.is_a? Retraction
+      user = User.first(:id => uid)
+      v = render_to_string(:partial => type_partial(object), :locals => {:post => object, :current_user => user}) unless object.is_a? Retraction
     rescue Exception => e
-      puts "web socket view rendering failed for some reason." + v.inspect
-      puts object.inspect
-      puts e.message
+      Rails.logger.error("web socket view rendering failed for object #{object.inspect}.")
       raise e 
     end
     action_hash = {:class =>object.class.to_s.underscore.pluralize, :html => v, :post_id => obj_id(object)}
@@ -24,6 +23,7 @@ module SocketsHelper
       action_hash[:photo_hash] = object.thumb_hash
     elsif object.is_a? StatusMessage
       action_hash[:status_message_hash] = object.latest_hash
+      action_hash[:status_message_hash][:mine?] = true if object.person.owner_id == uid
     end
     
     action_hash.to_json
diff --git a/app/helpers/status_messages_helper.rb b/app/helpers/status_messages_helper.rb
index 57d0f2f17d873e937f99a29cdd8fccdd815826a6..840e789a0d5fc49bcf8c7be655bda2503faa69d5 100644
--- a/app/helpers/status_messages_helper.rb
+++ b/app/helpers/status_messages_helper.rb
@@ -1,5 +1,4 @@
 module StatusMessagesHelper
-
   def my_latest_message
     unless @latest_status_message.nil?
       return @latest_status_message.message
@@ -7,7 +6,4 @@ module StatusMessagesHelper
       return "No message to display."
     end
   end
-  
-  
-
 end
diff --git a/app/models/album.rb b/app/models/album.rb
index 3fb8917c4cf0b1dfa031ddb0407fd36ecb9db93f..03dc5ed1a8610161a6f25bcb3405ca28068d9aec 100644
--- a/app/models/album.rb
+++ b/app/models/album.rb
@@ -26,9 +26,9 @@ class Album
 
   def self.mine_or_friends(friend_param, current_user)
     if friend_param
-      Album.where(:person_id.ne => current_user.id)
+      Album.where(:person_id => current_user.friend_ids)
     else
-      Album.where(:person_id => current_user.id)
+      current_user.person.albums
     end
   end
   
diff --git a/app/models/blog.rb b/app/models/blog.rb
index 0df0dd5582f491e95011004540eca98f4e1917ec..3859cfa1e65a46e2ab3f9e838cfbad37e43b920a 100644
--- a/app/models/blog.rb
+++ b/app/models/blog.rb
@@ -15,8 +15,8 @@ class Blog < Post
   <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
   <title>#{self.title}</title>
   <content>#{self.body}</content>
-  <link rel="alternate" type="text/html" href="#{User.owner.url}blogs/#{self.id}"/>
-  <id>#{User.owner.url}blogs/#{self.id}</id>
+  <link rel="alternate" type="text/html" href="#{person.url}blogs/#{self.id}"/>
+  <id>#{person.url}blogs/#{self.id}</id>
   <published>#{self.created_at.xmlschema}</published>
   <updated>#{self.updated_at.xmlschema}</updated>
   </entry>
diff --git a/app/models/bookmark.rb b/app/models/bookmark.rb
index 8f793fd47b3c51a05e82d12cdc513964d6dbdd59..677bfa126da0104b9d2c726edb2044e45dadb653 100644
--- a/app/models/bookmark.rb
+++ b/app/models/bookmark.rb
@@ -12,27 +12,31 @@ class Bookmark < Post
   validates_format_of :link, :with =>
     /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix
 
-  before_validation :clean_link
-
   def to_activity
         <<-XML
   <entry>
   <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
   <title>#{self.title}</title>
-  <link rel="alternate" type="text/html" href="#{User.owner.url}bookmarks/#{self.id}"/>
+  <link rel="alternate" type="text/html" href="#{person.url}bookmarks/#{self.id}"/>
   <link rel="related" type="text/html" href="#{self.link}"/>
-  <id>#{User.owner.url}bookmarks/#{self.id}</id>
+  <id>#{person.url}bookmarks/#{self.id}</id>
   <published>#{self.created_at.xmlschema}</published>
   <updated>#{self.updated_at.xmlschema}</updated>
   </entry>
         XML
   end
+  
+  def self.instantiate params
+    params[:link] = clean_link(params[:link])
+    create params
+  end
 
   protected
-  def clean_link
-    if self.link
-      self.link = 'http://' + self.link unless self.link.match('https?://')
-      self.link = self.link + '/' if self.link[-1,1] != '/'
+  def self.clean_link link
+    if link
+      link = 'http://' + link unless link.match('https?://')
+      link = link + '/' if link[-1,1] != '/'
+      link
     end
   end
 end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 1808952a8338b5ee4f2152d6386fbf16750cb178..3b574f28f12b09877c45f773cd106dcf10b08e47 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -3,11 +3,12 @@ class Comment
   include ROXML
   include Diaspora::Webhooks
   include Encryptable
+  include Diaspora::Socketable
   
   xml_accessor :text
   xml_accessor :person, :as => Person
   xml_accessor :post_id
-  
+  xml_accessor :_id 
   
   key :text, String
   timestamps!
@@ -17,19 +18,22 @@ class Comment
   
   key :person_id, ObjectId
   belongs_to :person, :class_name => "Person"
+
+  validates_presence_of :text
   
-  after_save :send_people_comments_on_my_posts
-  after_save :send_to_view
-  
+  def push_upstream
+    Rails.logger.info("GOIN UPSTREAM")
+    push_to([post.person])
+  end
 
-  def ==(other)
-    (self.message == other.message) && (self.person.email == other.person.email)
+  def push_downstream
+    Rails.logger.info("SWIMMIN DOWNSTREAM")
+    push_to(post.people_with_permissions)
   end
-  
+
   #ENCRYPTION
   
   before_validation :sign_if_mine, :sign_if_my_post
-  #validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature}
   validates_true_for :post_creator_signature, :logic => lambda {self.verify_post_creator_signature}
   
   xml_accessor :creator_signature
@@ -53,8 +57,7 @@ class Comment
   end
 
   def verify_post_creator_signature
-    unless person == User.owner
-      puts "verifying post creator sig from #{post.person.real_name}"
+    if person.owner.nil?
       verify_signature(post_creator_signature, post.person)
     else
       true
@@ -64,19 +67,9 @@ class Comment
   
   protected
    def sign_if_my_post
-    if self.post.person == User.owner
-      self.post_creator_signature = sign
+    unless self.post.person.owner.nil?
+      self.post_creator_signature = sign_with_key self.post.person.encryption_key
     end
   end 
- 
-   def send_people_comments_on_my_posts
-    if User.owner.mine?(self.post) && !(self.person.is_a? User)
-      self.push_to(self.post.people_with_permissions)
-    end
-  end
-  
-  
-  def send_to_view
-    SocketsController.new.outgoing(self)
-  end
+
 end
diff --git a/app/models/group.rb b/app/models/group.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6b8f1892131882d3db7e8c42e5279ff9b6304174
--- /dev/null
+++ b/app/models/group.rb
@@ -0,0 +1,19 @@
+class Group 
+  include MongoMapper::Document
+  
+  key :name, String
+
+  key :person_ids, Array
+  key :request_ids, Array
+  key :post_ids, Array
+
+  many :people, :in => :person_ids, :class_name => 'Person'
+  many :requests, :in => :request_ids, :class_name => 'Request'
+  many :posts, :in => :post_ids, :class_name => 'Post'
+
+  belongs_to :user, :class_name => 'User'
+
+  timestamps!
+
+end
+
diff --git a/app/models/person.rb b/app/models/person.rb
index ee7ad104f2e7ec1819631a1c470b2f697c875148..d7fa74418dda6a55c5adf1d04c9a833fcb9df226 100644
--- a/app/models/person.rb
+++ b/app/models/person.rb
@@ -5,32 +5,35 @@ class Person
   xml_accessor :_id
   xml_accessor :email
   xml_accessor :url
-  xml_accessor :serialized_key
   xml_accessor :profile, :as => Profile
   
   
-  key :email, String
+  key :email, String, :unique => true
   key :url, String
-  key :active, Boolean, :default => false
 
   key :serialized_key, String 
 
+
+  key :owner_id, ObjectId
+  key :user_refs, Integer, :default => 0 
+
+  belongs_to :owner, :class_name => 'User'
   one :profile, :class_name => 'Profile'
+
   many :posts, :class_name => 'Post', :foreign_key => :person_id
   many :albums, :class_name => 'Album', :foreign_key => :person_id
 
+
   timestamps!
 
   before_validation :clean_url
-  validates_presence_of :email, :url, :serialized_key
+  validates_presence_of :email, :url, :profile, :serialized_key 
   validates_format_of :url, :with =>
      /^(https?):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(\.[a-z]{2,5})?(:[0-9]{1,5})?(\/.*)?$/ix
   
-  validates_true_for :url, :logic => lambda { self.url_unique?}
 
   after_destroy :remove_all_traces
 
-  scope :friends, where(:_type => "Person", :active => true)
   
   def self.search_for_friends(query)
     Person.all('$where' => "function() { return this.profile.first_name.match(/^#{query}/i) || this.profile.last_name.match(/^#{query}/i); }")
@@ -40,25 +43,84 @@ class Person
     "#{profile.first_name.to_s} #{profile.last_name.to_s}"
   end
 
-  def key
+  def encryption_key
     OpenSSL::PKey::RSA.new( serialized_key )
   end
 
-  def key= new_key
+  def encryption_key= new_key
     raise TypeError unless new_key.class == OpenSSL::PKey::RSA
     serialized_key = new_key.export
   end
   def export_key
-    key.public_key.export
+    encryption_key.public_key.export
   end
 
-  protected
+
+  ######## Posting ########
+  def post(class_name, options = {})
+    options[:person] = self
+    model_class = class_name.to_s.camelize.constantize
+    post = model_class.instantiate(options)
+    post.notify_people
+    post.socket_to_uid owner.id if (owner_id && post.respond_to?( :socket_to_uid))
+    post
+  end
+
+  ######## Commenting  ########
+  def comment(text, options = {})
+    raise "must comment on something!" unless options[:on]
+    c = Comment.new(:person_id => self.id, :text => text, :post => options[:on])
+    if c.save
+      begin
+      dispatch_comment c
+      rescue Exception => e
+        puts e.inspect
+        raise e
+      end
+      
+      
+      c.socket_to_uid owner.id if owner_id
+      true
+    else
+      Rails.logger.warn "this failed to save: #{c.inspect}"
+    end
+    false
+  end
+  
+  def dispatch_comment( c )
+    if owns? c.post
+      c.push_downstream
+    elsif owns? c
+      c.push_upstream
+    end
+  end
+  ##profile
+  def update_profile(params)
+    if self.update_attributes(params)
+      self.profile.notify_people!
+      true
+    else
+      false
+    end
+  end
+
+  def owns?(post)
+    self.id == post.person.id
+  end
+
+  def receive_url
+    "#{self.url}receive/users/#{self.id}/"
+  end
+
+  def self.by_webfinger( identifier )
+     Person.first(:email => identifier.gsub('acct:', ''))
+  end
   
-  def url_unique?
-    same_url = Person.first(:url => self.url)
-    return same_url.nil? || same_url.id == self.id
+  def remote?
+    owner.nil?
   end
 
+  protected
   def clean_url
     self.url ||= "http://localhost:3000/" if self.class == User
     if self.url
diff --git a/app/models/photo.rb b/app/models/photo.rb
index e57e2f78d4b0535c711b8db68f9eff7d9db276fc..d93a1189a90c5603d09b662cd416a3ee87800a70 100644
--- a/app/models/photo.rb
+++ b/app/models/photo.rb
@@ -37,22 +37,20 @@ class Photo < Post
   end
 
   def remote_photo
-    @remote_photo ||= User.owner.url.chop + image.url
+    @remote_photo ||= self.person.url.chop + image.url
   end
 
   def remote_photo= remote_path
-    Rails.logger.info("Setting remote photo with id #{id}")
     @remote_photo = remote_path
     image.download! remote_path
     image.store!
-    Rails.logger.info("Setting remote photo with id #{id}")
   end
 
   def ensure_user_picture
-    user = User.owner
-    if user.profile.image_url == image.url(:thumb_medium)
+    users = Person.all('profile.image_url' => image.url(:thumb_medium) )
+    users.each{ |user|
       user.profile.update_attributes!(:image_url => nil)
-    end
+    } 
   end
 
   def thumb_hash
diff --git a/app/models/post.rb b/app/models/post.rb
index 1b4149fdcbfdad5e7547a6d10aea8b1988761b16..e35b028cde0c3fd80959f969a70f024647806052 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -5,6 +5,7 @@ class Post
   include ROXML
   include Diaspora::Webhooks
   include Encryptable
+  include Diaspora::Socketable
 
   xml_accessor :_id
   xml_accessor :person, :as => Person
@@ -20,11 +21,8 @@ class Post
     
   timestamps!
 
-  after_save :send_to_view
-  after_save :notify_people
- 
   before_destroy :propagate_retraction
-  after_destroy :destroy_comments, :remove_from_view
+  after_destroy :destroy_comments
 
   def self.instantiate params
     self.create params
@@ -35,19 +33,10 @@ class Post
     Post.sort(:created_at.desc).all
   end
 
- def self.newest(person = nil)
-    return self.last if person.nil?
-
+  def self.newest_for(person)
     self.first(:person_id => person.id, :order => '_id desc')
   end
 
-   def self.my_newest
-     self.newest(User.owner)
-   end
-  def self.newest_by_email(email)
-    self.newest(Person.first(:email => email))
-  end
-
 #ENCRYPTION
   before_validation :sign_if_mine
   validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature}
@@ -69,10 +58,10 @@ class Post
   end
   
   def log_inspection
-    Rails.logger.info self.inspect
+    Rails.logger.debug self.inspect
   end
   def log_save_inspection
-    Rails.logger.info "After saving, object is:"
+    Rails.logger.debug "After saving, object is:"
     log_inspection
   end
 
@@ -85,13 +74,7 @@ protected
     Retraction.for(self).notify_people
   end
 
-  def send_to_view
-    SocketsController.new.outgoing(self)
-  end
-  
-  def remove_from_view
-    SocketsController.new.outgoing(Retraction.for(self))
-  end
+
 
 end
 
diff --git a/app/models/profile.rb b/app/models/profile.rb
index bb5176eacf6c660410358a14c1431a6b6e4efefc..9b4c81005428f63d2c5161be442732a8a4f8c6e1 100644
--- a/app/models/profile.rb
+++ b/app/models/profile.rb
@@ -20,8 +20,7 @@ class Profile
     self._parent_document.id
   end
   
-  def to_diaspora_xml
-    "<post>"+ self.to_xml.to_s + "</post>"
+  def person
+    Person.first(:id => self.person_id)
   end
-  
 end
diff --git a/app/models/request.rb b/app/models/request.rb
index f39d1267fbb4fdfc238dad319ab6e98730669de0..99625ad1341013543a7fcea9dc3cc62d8ec65e30 100644
--- a/app/models/request.rb
+++ b/app/models/request.rb
@@ -15,6 +15,7 @@ class Request
   key :callback_url, String
   key :person_id, ObjectId
   key :exported_key, String
+  key :group_id, ObjectId
 
   belongs_to :person
   
@@ -25,23 +26,35 @@ class Request
 
   before_validation :clean_link
 
-  scope :for_user, lambda{ |user| where(:destination_url => user.url) }
-  scope :from_user, lambda{ |user| where(:destination_url.ne => user.url) }
+  scope :for_user, lambda{ |user| where(:destination_url => user.receive_url) }
+  scope :from_user, lambda{ |user| where(:destination_url.ne => user.receive_url) }
 
-  def self.instantiate(options ={})
+  def self.instantiate(options = {})
     person = options[:from]
-    self.new(:destination_url => options[:to], :callback_url => person.url, :person => person, :exported_key => person.export_key)
+    self.new(:destination_url => options[:to],
+             :callback_url => person.receive_url, 
+             :person => person,
+             :exported_key => person.export_key,
+             :group_id => options[:into])
   end
-
-  def activate_friend 
-    p = Person.where(:url => self.person.url).first
-    p.active = true
-    p.save
+  
+  def reverse accepting_user
+    self.person = accepting_user.person
+    self.exported_key = accepting_user.export_key
+    self.destination_url = self.callback_url
+    save
+  end
+  
+  def set_pending_friend
+    p = Person.first(:id => self.person.id)
+    
+    self.person.save  #save pending friend
+    
   end
  
 #ENCRYPTION
-    before_validation :sign_if_mine
-    validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature}
+    #before_validation :sign_if_mine
+    #validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature}
     
     xml_accessor :creator_signature
     key :creator_signature, String
diff --git a/app/models/retraction.rb b/app/models/retraction.rb
index 9a07de141871993c7a85783137918b001d25480d..c9cf8dd77237fa6beb292ee3f2b277b5d2bb7295 100644
--- a/app/models/retraction.rb
+++ b/app/models/retraction.rb
@@ -5,9 +5,15 @@ class Retraction
 
   def self.for(object)
     retraction = self.new
-    retraction.post_id= object.id
+    if object.is_a? User
+      retraction.post_id = object.person.id
+      retraction.type = object.person.class.to_s
+    else
+      retraction.post_id = object.id
+      retraction.type = object.class.to_s
+    end
     retraction.person_id = person_id_from(object)
-    retraction.type = object.class.to_s
+    retraction.send(:sign_if_mine)
     retraction
   end
 
@@ -19,10 +25,14 @@ class Retraction
   attr_accessor :person_id
   attr_accessor :type
 
-  def perform
+  def perform receiving_user_id
+    Rails.logger.debug "Performing retraction for #{post_id}"
     begin
-      return unless signature_valid?
-      self.type.constantize.destroy(self.post_id)
+      return unless signature_valid? 
+      Rails.logger.debug("Retracting #{self.type} id: #{self.post_id}")
+      target = self.type.constantize.first(self.post_id)
+      target.unsocket_from_uid receiving_user_id if target.respond_to? :unsocket_from_uid
+      target.destroy
     rescue NameError
       Rails.logger.info("Retraction for unknown type recieved.")
     end
@@ -44,12 +54,22 @@ class Retraction
       object.person.id
     end
   end
+  
+  def person
+    Person.first(:id => self.person_id)
+  end
 
 #ENCRYPTION
     xml_reader :creator_signature
     
     def creator_signature
-      @creator_signature ||= sign if person_id == User.owner.id
+      object =  self.type.constantize.first(:id => post_id)
+
+      if object.class == Person && person_id == object.id
+        @creator_signature || sign_with_key(object.key)
+      elsif person_id == object.person.id
+        @creator_signature || sign_if_mine 
+      end
     end
 
     def creator_signature= input
diff --git a/app/models/status_message.rb b/app/models/status_message.rb
index fe641bdb2e95e5be53c18a01c5f3c506252c12a5..3fb9aa39d01447d662de73edc4c4520af9b32f64 100644
--- a/app/models/status_message.rb
+++ b/app/models/status_message.rb
@@ -13,8 +13,8 @@ class StatusMessage < Post
   <entry>
   <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
   <title>#{self.message}</title>
-  <link rel="alternate" type="text/html" href="#{User.owner.url}status_messages/#{self.id}"/>
-  <id>#{User.owner.url}status_messages/#{self.id}</id>
+  <link rel="alternate" type="text/html" href="#{person.url}status_messages/#{self.id}"/>
+  <id>#{person.url}status_messages/#{self.id}</id>
   <published>#{self.created_at.xmlschema}</published>
   <updated>#{self.updated_at.xmlschema}</updated>
   </entry>
@@ -22,7 +22,7 @@ class StatusMessage < Post
   end
   
   def latest_hash
-    {:mine? => self.person == User.owner, :text => message}
+    { :text => message}
   end
 end
 
diff --git a/app/models/user.rb b/app/models/user.rb
index 730b2a0c87889325716f0ffa762440c694655a87..16a58862e66558dd4c358296de351e07091fc0af 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,109 +1,188 @@
-class User < Person
+class User
+  include MongoMapper::Document
 
   devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :trackable, :validatable
          
-  
+  key :friend_ids, Array
+  key :pending_request_ids, Array
+
+  one :person, :class_name => 'Person', :foreign_key => :owner_id
+
+  many :friends, :in => :friend_ids, :class_name => 'Person'
+  many :pending_requests, :in => :pending_request_ids, :class_name => 'Request'
+
+  many :groups, :class_name => 'Group'
+
   before_validation_on_create :assign_key
-  validates_presence_of :profile
-  
   before_validation :do_bad_things
- 
   
-  ######## Posting ########
+  ######## Making things work ########
 
-  def post(class_name, options = {})
-    options[:person] = self
-    model_class = class_name.to_s.camelize.constantize
-    post = model_class.instantiate(options)
+  key :email, String
+
+  def method_missing(method, *args)
+    self.person.send(method, *args)
   end
 
-  ######## Commenting  ########
-  def comment(text, options = {})
-    raise "must comment on something!" unless options[:on]
-    c = Comment.new(:person_id => self.id, :text => text, :post => options[:on])
-    if c.save
-      if mine?(c.post)
-        c.push_to(c.post.people_with_permissions)  # should return plucky query
-      else
-        c.push_to([c.post.person])
-      end
-      true
-    end
-    false
+
+  def real_name
+    "#{person.profile.first_name.to_s} #{person.profile.last_name.to_s}"
   end
   
-  ##profile
-  def update_profile(params)
-    if self.update_attributes(params)
-      puts self.profile.class
-      self.profile.notify_people!
-      true
-    else
-      false
-    end
+  ######### Groups ######################
+
+  def group( opts = {} )
+    opts[:user] = self
+    Group.create(opts)
   end
 
-  ######### Friend Requesting
-  def send_friend_request_to(friend_url)
-    unless Person.where(:url => friend_url).first
-      p = Request.instantiate(:to => friend_url, :from => self)
-      if p.save
-        p.push_to_url friend_url
+  ######### Friend Requesting ###########
+  def send_friend_request_to(friend_url, group_id)
+    unless self.friends.detect{ |x| x.receive_url == friend_url}
+      request = Request.instantiate(:to => friend_url, :from => self.person, :into => group_id)
+      if request.save
+        self.pending_requests << request
+        self.save
+
+        group = self.group_by_id(group_id)
+
+        group.requests << request
+        group.save
+        
+        request.push_to_url friend_url
       end
-      p
+      request
     end
   end 
 
-  def accept_friend_request(friend_request_id)
+  def accept_friend_request(friend_request_id, group_id)
     request = Request.where(:id => friend_request_id).first
-    request.activate_friend
-    request.person = self
-    request.exported_key = self.export_key
-    request.destination_url = request.callback_url
+    n = pending_requests.delete(request)
+    
+    activate_friend(request.person, group_by_id(group_id))
+
+    request.reverse self
+    request
+  end
+  
+  def dispatch_friend_acceptance(request)
     request.push_to_url(request.callback_url)
-    request.destroy
+    request.destroy unless request.callback_url.include? url
+  end 
+  
+  def accept_and_respond(friend_request_id, group_id)
+    dispatch_friend_acceptance(accept_friend_request(friend_request_id, group_id))
   end
 
   def ignore_friend_request(friend_request_id)
     request = Request.first(:id => friend_request_id)
     person = request.person
-    person.destroy unless person.active
+    person.user_refs -= 1
+    pending_requests.delete(request)
+    save
+    (person.user_refs > 0 || person.owner.nil? == false) ?  person.save : person.destroy
     request.destroy
   end
 
   def receive_friend_request(friend_request)
     Rails.logger.info("receiving friend request #{friend_request.to_json}")
-    friend_request.person.serialized_key = friend_request.exported_key
-    if Request.where(:callback_url => friend_request.callback_url).first
-      friend_request.activate_friend
+    if request_from_me?(friend_request)
+      group = self.group_by_id(friend_request.group_id)
+      activate_friend(friend_request.person, group)
+
+      Rails.logger.info("#{self.real_name}'s friend request has been accepted")
       friend_request.destroy
     else
+      friend_request.person.user_refs += 1
       friend_request.person.save
+      pending_requests << friend_request
+      save
+      Rails.logger.info("#{self.real_name} has received a friend request")
       friend_request.save
     end
   end
 
-  def unfriend(friend_id)
-    bad_friend  = Person.first(:id => friend_id, :active => true)
-    if bad_friend 
-       Retraction.for(self).push_to_url(bad_friend.url) 
-       bad_friend.destroy
-    end
+  def unfriend(bad_friend)
+    Rails.logger.info("#{self.real_name} is unfriending #{bad_friend.inspect}")
+    Retraction.for(self).push_to_url(bad_friend.receive_url) 
+    remove_friend(bad_friend)
+  end
+  
+  def remove_friend(bad_friend)
+    raise "Friend not deleted" unless self.friend_ids.delete( bad_friend.id )
+    groups.each{|g| g.person_ids.delete( bad_friend.id )}
+    self.save
+    bad_friend.user_refs -= 1
+    (bad_friend.user_refs > 0 || bad_friend.owner.nil? == false) ?  bad_friend.save : bad_friend.destroy
+  end
+
+  def unfriended_by(bad_friend)
+    Rails.logger.info("#{self.real_name} is being unfriended by #{bad_friend.inspect}")
+    remove_friend bad_friend
   end
 
-  def send_request(rel_hash)
+  def send_request(rel_hash, group)
     if rel_hash[:friend]
-      self.send_friend_request_to(rel_hash[:friend])
+      self.send_friend_request_to(rel_hash[:friend], group)
     else
       raise "you can't do anything to that url"
     end
   end
-
   
+  def activate_friend(person, group)
+    person.user_refs += 1
+    group.people << person
+    friends << person
+    person.save
+    group.save
+    save
+  end
+
+  def request_from_me?(request)
+    pending_requests.detect{|req| (req.callback_url == person.receive_url) && (req.destination_url == person.receive_url)}
+  end
+
+  ###### Receiving #######
+  def receive xml
+    object = Diaspora::Parser.from_xml(xml)
+    Rails.logger.debug("Receiving object:\n#{object.inspect}")
+
+    if object.is_a? Retraction
+      if object.type == 'Person' && object.signature_valid?
+
+        Rails.logger.info( "the person id is #{object.post_id} the friend found is #{friend_by_id(object.post_id).inspect}")
+        unfriended_by friend_by_id(object.post_id)
+
+      else
+        object.perform self.id
+      end
+    elsif object.is_a? Request
+      person = Diaspora::Parser.get_or_create_person_object_from_xml( xml )
+      person.serialized_key ||= object.exported_key
+      object.person = person
+      object.person.save
+      old_request =  Request.first(:id => object.id)
+      object.group_id = old_request.group_id if old_request
+      object.save
+      receive_friend_request(object)
+    elsif object.is_a? Profile
+      person = Diaspora::Parser.owner_id_from_xml xml
+      person.profile = object
+      person.save  
+    elsif object.verify_creator_signature == true 
+      Rails.logger.debug("Saving object: #{object}")
+      object.save
+      object.socket_to_uid( id) if (object.respond_to?(:socket_to_uid) && !self.owns?(object))
+      dispatch_comment object if object.is_a?(Comment) && !owns?(object)
+    end
+  end
+
   ###Helpers############
-  def mine?(post)
-    self == post.person
+  def self.instantiate( opts = {} )
+    opts[:person][:email] = opts[:email]
+    opts[:person][:serialized_key] = generate_key
+    User.create( opts)
   end
 
   def terse_url
@@ -117,18 +196,29 @@ class User < Person
     self.password_confirmation = self.password
   end
   
-  def self.owner
-    User.first
+  def friend_by_id( id )
+    friends.detect{|x| x.id == ensure_bson( id ) }
   end
-  
+
+  def group_by_id( id )
+    groups.detect{|x| x.id == ensure_bson( id ) }
+  end
+
   protected
   
   def assign_key
-    self.serialized_key ||= generate_key.export
+    self.person.serialized_key ||= generate_key.export
   end
 
   def generate_key
     OpenSSL::PKey::RSA::generate 1024 
   end
 
+  def self.generate_key
+    OpenSSL::PKey::RSA::generate 1024 
+  end
+
+  def ensure_bson id 
+    id.class == String ? BSON::ObjectID(id) : id 
+  end
 end
diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb
index e118e0f844453dffdd488cc93fe11b63b1f52f9f..2a55e30592e564c46ded16c6ea9b7c83f744cdc6 100644
--- a/app/uploaders/image_uploader.rb
+++ b/app/uploaders/image_uploader.rb
@@ -24,7 +24,7 @@ class ImageUploader < CarrierWave::Uploader::Base
   end
 
   version :thumb_large do
-    process :resize_to_fill => [300,200]
+    process :resize_to_fill => [300,300]
   end
 
   version :scaled_full do
diff --git a/app/views/albums/_album.html.haml b/app/views/albums/_album.html.haml
index d4a629ba0674788d9bab410007552fc15d759dfc..52cb7fe4aea4d276f43a2e4b49f0968ee01b796d 100644
--- a/app/views/albums/_album.html.haml
+++ b/app/views/albums/_album.html.haml
@@ -1,4 +1,4 @@
-.album{:id => post.id, :class => ("mine" if mine?(post))}
+.album{:id => post.id, :class => ("mine" if current_user.owns?(post))}
 
   %div.name
     = link_to post.name, object_path(post)
diff --git a/app/views/albums/_new_album.haml b/app/views/albums/_new_album.haml
index ae83e0e99e1d40204479d020be5c7a4bc18764d9..a52f0c9ec3fb13f23f81eb3516160cb30c137dcd 100644
--- a/app/views/albums/_new_album.haml
+++ b/app/views/albums/_new_album.haml
@@ -1,3 +1,5 @@
+%h1 Add a new album
+
 = form_for Album.new do |f|
   = f.error_messages
   %p
diff --git a/app/views/albums/edit.html.haml b/app/views/albums/edit.html.haml
index 3843685e0d6016b847c722527a2c1c59689be46c..b505cf76b626a02c3f369c54ac60d81250ec8098 100644
--- a/app/views/albums/edit.html.haml
+++ b/app/views/albums/edit.html.haml
@@ -1,6 +1,5 @@
+.back= link_to "⇧ #{@album.name}", @album
 %h1.big_text
-  .back
-    = link_to "⇧ #{@album.name}", @album
 
   = "Editing #{@album.name}"
 
@@ -12,6 +11,10 @@
   %p
     = a.text_field :name
 
+  %ul
+  - for photo in @album.photos
+    %li.photo_edit_block= image_tag photo.image.url(:thumb_large)
+
   #submit_block
     = link_to "Cancel", root_path
     or
diff --git a/app/views/albums/index.html.haml b/app/views/albums/index.html.haml
index 8f3816f3d20f888868222ee4194bd79db9e46662..47d2f68a953c18aa657c30a487e02fa46c24ad2b 100644
--- a/app/views/albums/index.html.haml
+++ b/app/views/albums/index.html.haml
@@ -1,17 +1,17 @@
+.back= link_to "⇧ home", root_path
 %h1.big_text
-  .back
-    = link_to "⇧ home", root_path
   Albums
-  .button.right#add_album_button
-    = link_to 'New Album', "#"
+  .right
+    = link_to 'New Album', '#new_album_pane', {:class => "button", :id => "add_album_button"}
 
-  #add_album_box.contextual_pane
+.yo{:style => "display:none;" }
+  #new_album_pane
     = render "albums/new_album"
 
 .sub_header
   %ul.button_set
-    %li.selected= friends_albums_link
-    %li= your_albums_link
+    %li{:class => ("selected" if params[:friends])}= friends_albums_link 
+    %li{:class => ("selected" if not params[:friends])}= your_albums_link
 
 %div
   - for album in @albums
diff --git a/app/views/albums/show.html.haml b/app/views/albums/show.html.haml
index 253d94d19792b666ba909a39765d8bf6cf03c21e..b63dea9de9afff13345f3b65eaf58ec7b78f6fc6 100644
--- a/app/views/albums/show.html.haml
+++ b/app/views/albums/show.html.haml
@@ -1,20 +1,22 @@
+.back= link_to '⇧ albums', albums_path
 %h1.big_text
-  .back
-    = link_to '⇧ albums', albums_path
 
   = @album.name 
 
-  -if mine? @album
-    .button.right#add_photos_button
-      = link_to 'Add Photos', '#'
+  -if current_user.owns? @album
+    .right
+      #add_photo_loader
+        = image_tag 'ajax-loader.gif'
+      = link_to 'Add Photos', '#new_photo_pane', :class => 'button', :id => "add_photo_button"
 
-    #add_photo_box.contextual_pane
+  .yo{:style => "display:none;"}
+    #new_photo_pane
       = render "photos/new_photo", :photo => @photo, :album => @album
 
 .sub_header
   ="updated #{how_long_ago(@album)}"
 
--unless mine? @album
+-unless current_user.owns? @album
   %h4= "by #{@album.person.real_name}"
 
 #thumbnails
@@ -25,6 +27,7 @@
 #content_bottom
   .back
     = link_to "⇧ albums", albums_path
-  -if mine? @album
-    .button.right
-      = link_to 'Edit Album', edit_album_path(@album)
+
+  -if current_user.owns? @album
+    .right
+      = link_to 'Edit Album', edit_album_path(@album), :class => 'button'
diff --git a/app/views/blogs/_blog.html.haml b/app/views/blogs/_blog.html.haml
index 79d0612b3a708f5df89bf1ce7ee590c549f1c19f..0896d7d6b08650b2f5024d0a97dfe4accb306d20 100644
--- a/app/views/blogs/_blog.html.haml
+++ b/app/views/blogs/_blog.html.haml
@@ -1,9 +1,9 @@
-%li.message{:id => post.id, :class => ("mine" if mine?(post))}
+%li.message{:id => post.id, :class => ("mine" if current_user.owns?(post))}
 
   = person_image_tag(post.person)
 
   %span.from
-    = link_to_person post.person
+    = link_to post.person.real_name, post.person
     %b wrote a new blog post
     %br
   %b= post.title
@@ -15,6 +15,6 @@
     = link_to "show comments (#{post.comments.count})", '#', :class => "show_post_comments"
   = render "comments/comments", :post => post 
 
-  - if mine?(post)
+  - if current_user.owns?(post)
     .destroy_link
       = link_to 'Delete', blog_path(post), :confirm => 'Are you sure?', :method => :delete, :remote=> true
diff --git a/app/views/bookmarks/_bookmark.html.haml b/app/views/bookmarks/_bookmark.html.haml
index 8356bf91d0ebbd46e45f57d1ce371663fa85bbcd..5df9f1a253d20b59a3a1bca79bd8885f7217448a 100644
--- a/app/views/bookmarks/_bookmark.html.haml
+++ b/app/views/bookmarks/_bookmark.html.haml
@@ -1,9 +1,9 @@
-%li.message{:id => post.id, :class => ("mine" if mine?(post))}
+%li.message{:id => post.id, :class => ("mine" if current_user.owns?(post))}
 
   = person_image_tag(post.person)
 
   %span.from
-    = link_to_person post.person
+    = link_to post.person.real_name, post.person
     %b shared a link
     %br
   = post.title
@@ -16,6 +16,6 @@
     = link_to "show comments (#{post.comments.count})", '#', :class => "show_post_comments"
   = render "comments/comments", :post => post 
 
-  - if mine?(post)
+  - if current_user.owns?(post)
     .destroy_link
       = link_to 'Delete', bookmark_path(post), :confirm => 'Are you sure?', :method => :delete, :remote => true
diff --git a/app/views/comments/_comment.html.haml b/app/views/comments/_comment.html.haml
index 8783b4502f23ac44e84c4c91ccf2ed878ee2d80e..0c7fe954d01d1a980b236bebcff4538afea28798 100644
--- a/app/views/comments/_comment.html.haml
+++ b/app/views/comments/_comment.html.haml
@@ -1,7 +1,7 @@
 %li.comment{:id => post.id} 
   = person_image_tag(post.person)
   %span.from
-    = link_to_person post.person
+    = link_to post.person.real_name, post.person
     = auto_link post.text
   %div.time
     = "#{time_ago_in_words(post.updated_at)} ago"
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index b03da351897847985d8258fe82d03e132a436548..8e268c9260c0b29fcd4ca5f832c9b12790b7e2aa 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -1,17 +1,29 @@
+= image_tag "http://needcoffee.cachefly.net/needcoffee/uploads/2009/02/predator-arnold-schwarzenegger.jpg"
+
+
 %h2 Sign up
 = form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
   = devise_error_messages!
   %p
     = f.label :email
-    %br/
     = f.text_field :email
   %p
     = f.label :password
-    %br/
     = f.password_field :password
   %p
     = f.label :password_confirmation
-    %br/
     = f.password_field :password_confirmation
+
+  = f.fields_for :person do |p|
+    = p.hidden_field :url, :value => "http://google.com/"
+
+    = p.fields_for :profile do |pr|
+      %p
+        = pr.label :first_name
+        = pr.text_field :first_name
+      %p
+        = pr.label :last_name
+        = pr.text_field :last_name
+
   %p= f.submit "Sign up"
 = render :partial => "devise/shared/links"
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index 96b9ca9c4e8c619ffe75a061fb825f1b955c4efb..a36917c7b7a40388023f88d22b7c4c42b3391416 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -1,12 +1,13 @@
 = form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
   %p
+    = f.text_field :email
+    %br
     = f.password_field :password
+  /%p
+  /- if devise_mapping.rememberable?
+  /  = f.check_box :remember_me
+  /  = f.label :remember_me
   %p
-    - if devise_mapping.rememberable?
-      /= f.check_box :remember_me
-      /= f.label :remember_me
-
-    = hidden_field_tag "user_email", "#{User.owner.email}", :name => "user[email]"
     = f.submit "Sign in"
-/= render :partial => "devise/shared/links"
+= render :partial => "devise/shared/links"
 
diff --git a/app/views/groups/_new_group.haml b/app/views/groups/_new_group.haml
new file mode 100644
index 0000000000000000000000000000000000000000..5ac136eae5d88aa9894f6f703481a147b7371833
--- /dev/null
+++ b/app/views/groups/_new_group.haml
@@ -0,0 +1,7 @@
+%h1 Add a new group
+= form_for Group.new do |f|
+  = f.error_messages
+  %p
+    = f.label :name
+    = f.text_field :name
+    = f.submit 'create', :class => 'button'
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..461bff1dba75673aa9eb2d4f1da00ba437ac3d73
--- /dev/null
+++ b/app/views/groups/edit.html.haml
@@ -0,0 +1,25 @@
+%h1.big_text
+  .back
+    = link_to "⇧ #{@group.name}", @group
+
+  = "Editing #{@group.name}"
+
+.sub_header
+  ="updated #{how_long_ago(@group)}"
+
+- form_for @group do |a|
+  = a.error_messages
+  %p
+    = a.text_field :name
+
+  #submit_block
+    = link_to "Cancel", root_path
+    or
+    = a.submit
+
+.button.delete
+  = link_to 'Delete Album', @group, :confirm => 'Are you sure?', :method => :delete
+
+#content_bottom
+  .back
+    = link_to "⇧ #{@group.name}", @group
diff --git a/app/views/groups/index.html.haml b/app/views/groups/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..b3b4d2acb8a7c1e83526135da400d964de4f23f7
--- /dev/null
+++ b/app/views/groups/index.html.haml
@@ -0,0 +1,11 @@
+%h1
+  welcome home,
+  = current_user.profile.first_name
+
+= render "shared/publisher"
+%ul#stream
+  - for post in @posts
+    = render type_partial(post), :post => post
+#pagination
+  = will_paginate @posts
+
diff --git a/app/views/albums/new.html.haml b/app/views/groups/new.html.haml
similarity index 50%
rename from app/views/albums/new.html.haml
rename to app/views/groups/new.html.haml
index 2f4450cd90550eb759cd798d629bfec651ff281a..c899fd9aec3bc675440e7edf07e096ce4b114719 100644
--- a/app/views/albums/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -1,9 +1,9 @@
 %h1.big_text
-  =link_to 'albums', albums_path
+  =link_to 'groups', groups_path 
   >>
-  new album
+  new group
 
-= form_for @album do |f|
+= form_for @group do |f|
   = f.error_messages
   %p
     = f.label :name
@@ -11,4 +11,4 @@
   %p
     = f.submit
 
-%p= link_to "Back to List", albums_path
+%p= link_to "Back to List", groups_path
diff --git a/app/views/dashboards/index.html.haml b/app/views/groups/show.html.haml
similarity index 100%
rename from app/views/dashboards/index.html.haml
rename to app/views/groups/show.html.haml
diff --git a/app/views/js/_websocket_js.haml b/app/views/js/_websocket_js.haml
index 768c03cb7a3d38329468ce4ba6f70dd6a16d2818..e6596276158dad5513da5f4251aa6774faf8c239 100644
--- a/app/views/js/_websocket_js.haml
+++ b/app/views/js/_websocket_js.haml
@@ -7,7 +7,9 @@
     $(document).ready(function(){
       function debug(str){ $("#debug").append("<p>" +  str); };
 
-      ws = new WebSocket("ws://#{request.host}:8080/");
+      ws = new WebSocket("ws://#{request.host}:8080/#{CGI::escape(current_user.id.to_s)}");
+
+    //Attach onmessage to websocket
       ws.onmessage = function(evt) {
         var obj = jQuery.parseJSON(evt.data);
         debug("got a " + obj['class']);
@@ -62,6 +64,7 @@
 
       function processStatusMessage(className, html, messageHash){
         processPost(className, html);
+        console.log(messageHash)
         if(messageHash['mine?']){
           updateMyLatestStatus(messageHash);
         }
@@ -76,7 +79,7 @@
         if (location.href.indexOf(photoHash['album_id']) == -1){
           return ;
         }
-        html =  "<div class=\'image_thumb\' id=\'"+photoHash['id']+"\'> \
+        html =  "<div class=\'image_thumb\' id=\'"+photoHash['id']+"\' style=\'padding-right:3px;\'> \
           <a href=\"/photos/"+ photoHash['id'] +"\"> \
           <img alt=\"New thumbnail\" src=\""+ photoHash['thumb_url'] +"\" /> \
           </a> </div>"  
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 4eb0281a4cbda35d3f0a01d0c68d3bc8f4725d09..62d0c4eb164723f8d00ec4148b7dee617285e83c 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -8,11 +8,17 @@
     
     = stylesheet_link_tag "blueprint/screen", :media => 'screen'
     = stylesheet_link_tag "application", "ui", 'bubble'
+
+    = stylesheet_link_tag "/../javascripts/fancybox/jquery.fancybox-1.3.1" 
+
     /= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
     = javascript_include_tag 'jquery142', 'rails', 'google'
-    = javascript_include_tag 'tiny_mce/tiny_mce', 'jquery.infieldlabel'
-    = javascript_include_tag 'jquery.cycle/jquery.cycle.min.js'
-    = javascript_include_tag 'view', 'publisher', 'image_picker'
+    = javascript_include_tag 'tiny_mce/tiny_mce'
+    = javascript_include_tag 'jquery.infieldlabel', 'jquery.cycle/jquery.cycle.min.js'
+    
+    = javascript_include_tag 'fancybox/jquery.fancybox-1.3.1.pack'
+
+    = javascript_include_tag 'view', 'publisher', 'image_picker', 'group_nav'
     = render 'js/websocket_js'
     
     = csrf_meta_tag
@@ -23,51 +29,31 @@
     = javascript_include_tag 'jquery.html5_upload'
 
   %body
+    - flash.each do |name, msg|
+      = content_tag :div, msg, :id => "flash_#{name}"
+
     %header
       .container
-        - flash.each do |name, msg|
-          = content_tag :div, msg, :id => "flash_#{name}"
-        #diaspora_text{:href => root_path}
-          = link_to "DIASPORA*", root_path
-          %span.sub_text
-            PREVIEW
-
         #session_action
           - if user_signed_in?
-            = link_to_person current_user
-            |
-            = link_to "requests (#{@request_count})", requests_path, :class => new_request(@request_count)
-            |
-            = link_to "logout", destroy_user_session_path
+            %ul#user_menu
+              %li.name= link_to current_user.real_name, current_user.person
+              %li= link_to "requests (#{@request_count})", requests_path, :class => new_request(@request_count)
+              %li= link_to "settings", edit_user_path(current_user)
+              %li= link_to "logout", destroy_user_session_path
           - else
             = link_to "login", new_user_session_path
 
-    .container
-      - if user_signed_in?
-        #user_name
-          = link_to(person_image_tag(current_user), root_path)
-          %h1
-            = link_to current_user.real_name, root_path
-            %span#latest_message
-              = my_latest_message
-            - unless @latest_status_message.nil?
-              %span{:style => "font-size: small", :id => 'latest_message_time'}
-                = " - #{how_long_ago @latest_status_message}"
+        #diaspora_text{:href => root_path}
+          = link_to "DIASPORA*", root_path
+          %span.sub_text
+            PREVIEW
+        = render "shared/group_nav"
 
-          %ul.nav
-            %li= link_to "home", root_path
-            %li= link_to "photos", albums_path
-            %li= "|"
-            %li= link_to "edit profile", edit_user_path(current_user)
+        = link_to "photos", albums_path
 
     .container
       .span-24.last
-        .span-20.append-1.last
-
-          = yield
-
-        .span-3.last
-          = render 'people/sidebar' if user_signed_in?
-
-        .span-24.last
-          = render "posts/debug"
+        = yield
+      .span-24.last
+        = render "posts/debug"
diff --git a/app/views/layouts/session_wall.html.haml b/app/views/layouts/session_wall.html.haml
index 3b85566bcd28bf9f5d4fb02568a980a724afebc6..95d0f7e3479a0dcfb8c4dea5502a24efabd83555 100644
--- a/app/views/layouts/session_wall.html.haml
+++ b/app/views/layouts/session_wall.html.haml
@@ -13,7 +13,7 @@
 
     :javascript
       $(document).ready(function(){
-        $("#user_password").focus(); 
+        $("#user_email").focus(); 
       });
   
     = csrf_meta_tag
@@ -40,18 +40,10 @@
         </div>
         <![endif]-->
     
-    
-    
       - flash.each do |name, msg|
         = content_tag :div, msg, :id => "flash_#{name}"
-      - if User.owner  
-        %div#huge_text
-          welcome back, 
-          %span
-            = User.owner.real_name.downcase
-        = yield
-      -else
-        %div#huge_text
-          %span
-            you need to add a user first!
-
+      %div#huge_text
+        diaspora
+      = yield
+      
+      /= link_to "signup", "/signup"
diff --git a/app/views/photos/_new_photo.haml b/app/views/photos/_new_photo.haml
index 23e4ad68c225087b367a64cd6627e66ebef47d5d..b577315967f91457c485f21d5f9071c9c61618da 100644
--- a/app/views/photos/_new_photo.haml
+++ b/app/views/photos/_new_photo.haml
@@ -4,45 +4,38 @@
       // WE INSERT ALBUM_ID PARAM HERE
       url: "/photos?album_id=#{album.id}",   
       sendBoundary: window.FormData || $.browser.mozilla,
-      onStart: function(event, total) {
-        return confirm("You are about to upload " + total + " photos. Are you sure?");
-      },
       setName: function(text) {
         $("#progress_report_name").text(text);
       },
-      setStatus: function(text) {
-        $("#progress_report_status").text(text);
-      },
-      setProgress: function(val) {
-        //$("#progress_report_bar").css('width', Math.ceil(val*100)+"%");
-      },
-      onFinishOne: function(event, response, name, number, total) {
-        //alert(response);
-      },
       onFinish: function(event, total){
-        $("#progress_report").delay(600).slideUp(200);
-        $("#add_photo_box").delay(600).fadeOut(200);
+        $("#add_photo_button").html( "Add Photos" );
+        $("#add_photo_loader").fadeOut(400);
+
+        $("#photo_title_status").text("Done!");
+        $("#progress_report").html("Great job!");
       },
       onStart: function(event, total){
-        $("#progress_report").slideDown(600);
+        $("#add_photo_button").html( "Uploading Photos" );
+        $("#add_photo_loader").fadeIn(400);
+
+        $("form").fadeOut(0);
+        $("#progress_report").fadeIn(0);
+        $("#photo_title_status").text("Uploading...");
         return true;
       }
     });
   });
 
-:css
-  #progress_report, #progress_report_name, #progress_report_status{
-    font-size: 12px;
-    padding: 0;
-    line-height: auto;
-  }
-
+%h1
+  %span{:id=>"photo_title_status"}
+    Add photos to
+    %i= album.name
 = form_for photo, :html => {:multipart => true} do |f|
   = f.error_messages
   = f.hidden_field :album_id, :value => album.id
   = f.file_field :image, :multiple => 'multiple'
 
-  #progress_report{ :style => "display:none;" }
-    = image_tag "loader.gif" 
-    #progress_report_name
-    #progress_report_status{ :style => "font-style: italic;" }
+#progress_report{ :style => "display:none;text-align:center;" }
+  = image_tag "ajax-loader.gif"
+  #progress_report_name
+  #progress_report_status
diff --git a/app/views/photos/_photo.haml b/app/views/photos/_photo.haml
index 9b663531a1f51cdca5158c5bbf2aa303a23b3f33..e6734639a40852c660961cec1bfd9c78c5a4ec14 100644
--- a/app/views/photos/_photo.haml
+++ b/app/views/photos/_photo.haml
@@ -2,7 +2,7 @@
   = person_image_tag(post.person)
 
   %span.from
-    = link_to_person post.person
+    = link_to post.person.real_name, post.person
     %b
       posted a new photo to
       = link_to post.album.name, object_path(post.album)
diff --git a/app/views/photos/edit.html.haml b/app/views/photos/edit.html.haml
index c849b43b7979ac84d3ad407169826164ad510bee..baeb82a3d81ad7787776ae7aff0b50e49f69e004 100644
--- a/app/views/photos/edit.html.haml
+++ b/app/views/photos/edit.html.haml
@@ -15,7 +15,7 @@
   #content_bottom
     .back
       = link_to "⇧ #{@album.name}", album_path(@album)
-    -if mine? @album
+    -if current_user.owns? @album
       .button.right
         = link_to 'Delete Photo', @photo, :confirm => 'Are you sure?', :method => :delete
 
diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml
index d0879065077476f5d9dc336acacace27cecbd8d5..05443591f847f29762c16bdb90d1ec204aa5e513 100644
--- a/app/views/photos/show.html.haml
+++ b/app/views/photos/show.html.haml
@@ -1,33 +1,30 @@
+.back= link_to "⇧ #{@album.name}", album_path(@album)
 %h1.big_text
-  .back
-    = link_to "⇧ #{@album.name}", album_path(@album)
   = @photo.image
 
-  .button.right
-    = link_to 'Edit Photo', edit_photo_path(@photo)
+  .right
+    = link_to 'Edit Photo', edit_photo_path(@photo), :class => "button"
 
 .sub_header
+  = link_to_prev @photo, @album
+  |
   = link_to "full size", @photo.image.url
+  |
+  = link_to_next @photo, @album
 
 %div{:id => @photo.id}
-
   #show_photo
     = linked_scaled_photo @photo, @album
-
     .caption
       = @photo.caption
 
-  #next_prev_links
-    = link_to_prev @photo, @album
-    |
-    = link_to_next @photo, @album
-
   #content_bottom
     .back
       = link_to "⇧ #{@album.name}", album_path(@album)
-    -if mine? @album
-      .button.right
-        = link_to 'Delete Photo', @photo, :confirm => 'Are you sure?', :method => :delete
+
+    -if current_user.owns? @album
+      .right
+        = link_to 'Delete Photo', @photo, :confirm => 'Are you sure?', :method => :delete, :class => 'button'
 
   %h4{:class => "show_post_comments"}
     = "comments (#{@photo.comments.count})"
diff --git a/app/views/publics/hcard.erb b/app/views/publics/hcard.erb
index 34f88866e3bcdd136eea0376fee7bb857b41a797..7cfbe56040daeee027bcbee132b235f184f50e50 100644
--- a/app/views/publics/hcard.erb
+++ b/app/views/publics/hcard.erb
@@ -1,24 +1,24 @@
 <div id="content"> 
-  <h1><%=@user.real_name%></h1> 
+  <h1><%=@person.real_name%></h1> 
   <div id="content_inner"> 
     <div id="i" class="entity_profile vcard author"> 
       <h2>User profile</h2> 
       <dl class="entity_nickname"> 
         <dt>Nickname</dt> 
         <dd> 
-        <a href="<%=@user.url%>" rel="me" class="nickname url uid"><%= @user.real_name%></a> 
+        <a href="<%=@person.url%>" rel="me" class="nickname url uid"><%= @person.real_name%></a> 
         </dd> 
       </dl> 
       <dl class="entity_fn"> 
         <dt>Full name</dt> 
         <dd> 
-        <span class="fn"><%= @user.real_name %></span> 
+        <span class="fn"><%= @person.real_name %></span> 
         </dd> 
       </dl> 
       <dl class="entity_url"> 
         <dt>URL</dt> 
         <dd> 
-        <a href="<%= @user.url%>" rel="me" class="url"><%= @user.url%></a> 
+        <a href="<%= @person.url%>" rel="me" class="url"><%= @person.url%></a> 
         </dd> 
       </dl> 
       <dl class="entity_note"> 
diff --git a/app/views/publics/host_meta.erb b/app/views/publics/host_meta.erb
index 53d8aeba49f64d7a588653fc1cb9dc6d633963cb..e28fb62117c7e719a8a23567499b1716f7643843 100644
--- a/app/views/publics/host_meta.erb
+++ b/app/views/publics/host_meta.erb
@@ -1,9 +1,9 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0' 
      xmlns:hm='http://host-meta.net/xrd/1.0'>
-     <hm:Host><%= @user.terse_url %></hm:Host>
+     <hm:Host><%= terse_url(root_url) %></hm:Host>
   <Link rel='lrdd' 
-        template='<%=@user.url%>webfinger?q={uri}'>
+        template='<%= root_url %>webfinger?q={uri}'>
     <Title>Resource Descriptor</Title>
   </Link>
 </XRD>
diff --git a/app/views/publics/webfinger.erb b/app/views/publics/webfinger.erb
index bafd58acb56e5d6e8a2cf6f5f8ae479efeaf0398..db4cd3a1cd069041cb0a5adbcb70040160eee29a 100644
--- a/app/views/publics/webfinger.erb
+++ b/app/views/publics/webfinger.erb
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
-  <Subject>acct:<%=@user.email%></Subject>
-  <Alias>"<%=@user.url%>hcard"</Alias>
-  <Link rel="http://microformats.org/profile/hcard" type="text/html" href="<%=@user.url%>hcard"/>
-  <Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="<%=@user.url%>status_messages.atom"/>
-  <Link rel="http://joindiaspora.com/seed_location" type = 'text/html' href="<%=@user.url%>"/>
+  <Subject>acct:<%=@person.email%></Subject>
+  <Alias>"<%= @person.url %>users/#{@user.id}/hcard"</Alias>
+  <Link rel="http://microformats.org/profile/hcard" type="text/html" href="<%=@person.url%>hcard"/>
+  <Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="<%=@person.url%>status_messages.atom"/>
+  <Link rel="http://joindiaspora.com/seed_location" type = 'text/html' href="<%=@person.receive_url%>"/>
 </XRD>
diff --git a/app/views/requests/_new_request.haml b/app/views/requests/_new_request.haml
index 714168fd23c80c2778951095f458269bebcee11c..42cd8b5e5cbc072928dc340d650420572ff05d96 100644
--- a/app/views/requests/_new_request.haml
+++ b/app/views/requests/_new_request.haml
@@ -1,8 +1,12 @@
-= form_for @request  do |f|
+%h1
+  Add a new friend to
+  %i= @group.name
+
+= form_for Request.new do |f|
   = f.error_messages
 
   Enter a Diaspora URL, Diaspora username, or random email address:  
-  .field_with_submit
-    = f.text_field :destination_url
-    = f.submit
+  = f.text_field :destination_url
+  = f.hidden_field :group, :value => @group.id
+  = f.submit
 
diff --git a/app/views/requests/_request.html.haml b/app/views/requests/_request.html.haml
index 03ab427f3b333a8990bee680e71b2f101ded5323..3cd2c398f78f9643e9125848af663293b6ddce83 100644
--- a/app/views/requests/_request.html.haml
+++ b/app/views/requests/_request.html.haml
@@ -1,8 +1,23 @@
+:javascript
+  $(document).ready(function(){
+    $(".group_selector").change( function() {
+      var id = $(this).children(":selected").val();
+      $(this).parent().children(".accept").html( "<a href=\"/requests/#{request.id}/?accept=true&group_id="+id+"\" data-method=\"delete\" rel=\"nofollow\" class=\"button\">Accept</a>");
+    });
+  });
+
+
 %li.message{:id => request.id}
 
   %span.from
     = link_to "#{request.person.real_name}", '#'
 
   %ul.request_buttons
-    %li= link_to 'Accept', request_path(request, :accept => true), :method => :delete 
-    %li= link_to 'Ignore', request_path(request), :confirm => 'Are you sure?', :method => :delete
+    %select{ :class => "group_selector", :style=>"display:inline;"}
+      %option Add to group
+      %option
+      - for group in current_user.groups
+        %option{:value => group.id}= group.name
+    %li.accept= link_to 'Accept', request_path(request, :accept => true), :method => :delete, :class => "button"
+    %li.ignore= link_to 'Ignore', request_path(request), :confirm => 'Are you sure?', :method => :delete, :class => "button"
+
diff --git a/app/views/requests/index.html.haml b/app/views/requests/index.html.haml
index 8278719ee5bc049290ca56134d9509d32dfbf80e..6ba3067c547fae77c60a230bbe6d8007eaf0dae5 100644
--- a/app/views/requests/index.html.haml
+++ b/app/views/requests/index.html.haml
@@ -3,10 +3,7 @@
     = link_to "⇧ home", root_path
   Requests
 
-= render "requests/new_request", :request => @request
-
 %h3= "currently #{@request_count} requests"
-
 %ul#stream
   - for request in @remote_requests
     = render "request", :request => request
diff --git a/app/views/shared/_group_nav.haml b/app/views/shared/_group_nav.haml
new file mode 100644
index 0000000000000000000000000000000000000000..66f4fa0bdeef9df0131649ba7650eb58ff2f7a0f
--- /dev/null
+++ b/app/views/shared/_group_nav.haml
@@ -0,0 +1,21 @@
+#group
+  %ul
+    - for group in @groups
+      %li{:class => ("selected" if group.id.to_s == params[:id])}
+        = link_to group.name, group
+
+    %li.new_group= link_to("NEW GROUP", "#add_group_pane", :id => "add_group_button")
+
+    .yo{ :style => "display:none;"}
+      #add_group_pane
+        = render "groups/new_group"
+
+  - if @group
+    #friend_pictures
+      - for friend in @group.people
+        = person_image_link(friend)
+      = link_to "+", "#add_request_pane", :id => 'add_request_button', :class => "add_new"
+
+      .yo{:style => 'display:none'}
+        #add_request_pane
+          = render "requests/new_request"
diff --git a/app/views/shared/_post_wrapper.haml b/app/views/shared/_post_wrapper.haml
index bdba9db700bd28e792e7a1f438c6136f9b532037..a65866a084736e2d91d28f8be2b5e17621e1415a 100644
--- a/app/views/shared/_post_wrapper.haml
+++ b/app/views/shared/_post_wrapper.haml
@@ -1,4 +1,4 @@
-%li.message{:id => post.id, :class => ("mine" if mine?(post))}
+%li.message{:id => post.id, :class => ("mine" if current_user.owns?(post))}
   = person_image_link(post.person)
   = yield post_yield_tag(post)
-  = = render type_partial(post), :post => post
\ No newline at end of file
+  = = render type_partial(post), :post => post
diff --git a/app/views/status_messages/_status_message.html.haml b/app/views/status_messages/_status_message.html.haml
index 5681e9753add2999173e990af088a7058e505073..c6099504e5018031c343056557f384c59da51c75 100644
--- a/app/views/status_messages/_status_message.html.haml
+++ b/app/views/status_messages/_status_message.html.haml
@@ -1,10 +1,10 @@
-%li.message{:id => post.id, :class => ("mine" if mine?(post))}
+%li.message{:id => post.id, :class => ("mine" if current_user.owns?(post))}
 
   = person_image_link(post.person)
 
   %span.from
     = link_to post.person.real_name, post.person 
-    = auto_link post.message
+    = auto_link sanitize post.message
     
   %div.time
     = link_to(how_long_ago(post), object_path(post))
@@ -12,6 +12,6 @@
     = link_to "show comments (#{post.comments.count})", '#', :class => "show_post_comments"
   = render   "comments/comments", :post => post 
 
-  - if mine?(post)
+  - if current_user.owns?(post)
     .destroy_link
-      = link_to 'Delete', status_message_path(post), :confirm => 'Are you sure?', :method => :delete, :remote => true
+      = link_to 'Delete', status_message_path(post), :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "delete"
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 9182161a31d2c63e87dcd017c8e782ad47a422f3..b678b43776639f8e94c990c6eb1d7796848918ac 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -6,6 +6,6 @@
   %p
     = @user.url
   %p
-    %b Key Fingerprint
+    %b Serialized Key
   %p
-    = @user.key_fingerprint
+    = @user.serialized_key
diff --git a/config/initializers/logging.rb b/config/initializers/logging.rb
new file mode 100644
index 0000000000000000000000000000000000000000..447ec5c17e2b0e423c7a042e3eb71f99b7a07c12
--- /dev/null
+++ b/config/initializers/logging.rb
@@ -0,0 +1,2 @@
+Rails.logger = Logger.new(
+  Rails.root.join("log",Rails.env + ".log"),3,5*1024*1024)
diff --git a/config/initializers/socket.rb b/config/initializers/socket.rb
index aebf023f3a92e2cb8865f5dc3653b76d51fa8af1..0f4e68f7b0e2990c9bc7b26335e59eb024f3061d 100644
--- a/config/initializers/socket.rb
+++ b/config/initializers/socket.rb
@@ -1,41 +1,21 @@
 require 'em-websocket'
 require 'eventmachine'
-
-module WebSocket
+require "lib/diaspora/websocket"
   EM.next_tick {
-    initialize_channel
+    Diaspora::WebSocket.initialize_channels
     
     EventMachine::WebSocket.start(
                   :host => "0.0.0.0", 
                   :port => APP_CONFIG[:socket_port],
                   :debug =>APP_CONFIG[:debug]) do |ws|
       ws.onopen {
-        @ws = ws
-        sid = @channel.subscribe{ |msg| ws.send msg }#SocketsController.new.new_subscriber
+        
+        sid = Diaspora::WebSocket.subscribe(ws.request['Path'].gsub('/',''), ws)
         
         ws.onmessage { |msg| SocketsController.new.incoming(msg) }#@channel.push msg; puts msg}
 
-        ws.onclose { SocketsController.new.delete_subscriber(sid) }
+        ws.onclose { Diaspora::WebSocket.unsubscribe(ws.request['Path'].gsub('/',''), sid) }
       }
     end
   }
 
-  def self.initialize_channel
-    @channel = EM::Channel.new
-  end
-  
-  def self.push_to_clients(html)
-    @channel.push(html)
-  end
-  
-  def self.unsubscribe(sid)
-    @channel.unsubscribe(sid)
-  end
-  
-  
-  def self.subscribe
-    @channel.subscribe{ |msg| ws.send msg }
-  end
-  
-end
-
diff --git a/config/routes.rb b/config/routes.rb
index 3726f5bf48f29cb3a1c993cadb0029c25b05391c..88c838d77c2aa9367160edaea28e7118a27883ea 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,28 +8,29 @@ Diaspora::Application.routes.draw do |map|
   resources :requests
   resources :photos
   resources :albums
+  resources :groups
 
   match "/images/files/*path" => "gridfs#serve"
   
-  match 'warzombie', :to => "dev_utilities#warzombie"
-  match 'zombiefriends', :to => "dev_utilities#zombiefriends"
+  match 'warzombie',          :to => "dev_utilities#warzombie"
+  match 'zombiefriends',      :to => "dev_utilities#zombiefriends"
   match 'zombiefriendaccept', :to => "dev_utilities#zombiefriendaccept"
+  match 'set_backer_number', :to => "dev_utilities#set_backer_number"
 
   #routes for devise, not really sure you will need to mess with this in the future, lets put default,
   #non mutable stuff in anohter file
-  devise_for :users, :path_names  => {:sign_up  => "signup", :sign_in  => "login", :sign_out  => "logout"}
-   match 'login', :to => 'devise/sessions#new', :as => "new_user_session"
-   match 'logout', :to  => 'devise/sessions#destroy', :as => "destroy_user_session"
-   #match 'signup', :to => 'devise/registrations#new', :as => "new_user_registration"
-  resources :users
-  
+  devise_for :users, :path_names  => {:sign_up  => "get_to_the_choppa", :sign_in  => "login", :sign_out  => "logout"}
+    match 'login',  :to => 'devise/sessions#new',      :as => "new_user_session"
+    match 'logout', :to => 'devise/sessions#destroy',  :as => "destroy_user_session"
+    match 'get_to_the_choppa', :to => 'devise/registrations#new', :as => "new_user_registration"
   
   #public routes
-  match 'receive',              :to => 'publics#receive'
-  match '.well-known/host-meta',:to => 'publics#host_meta'
-  match 'webfinger',            :to => 'publics#webfinger'
-  match 'hcard',                :to => 'publics#hcard'
-          
+  #
+  match 'webfinger', :to => 'publics#webfinger'
+  match 'users/:id/hcard',    :to => 'publics#hcard'
+
+  match '.well-known/host-meta',:to => 'publics#host_meta'        
+  match 'receive/users/:id',     :to => 'publics#receive'    
   #root
-  root :to => 'dashboards#index'
+  root :to => 'groups#index'
 end
diff --git a/db/seeds/backer.rb b/db/seeds/backer.rb
index f9f8ba3664996f4e8025d5cd8f1cb268f0f73bd3..bc5039aa16316821da29b2833d38fd1944ac0981 100644
--- a/db/seeds/backer.rb
+++ b/db/seeds/backer.rb
@@ -8,26 +8,21 @@
 
 require 'config/environment'
 
-def create(backer_number)
+def create
   config = YAML.load_file(File.dirname(__FILE__) + '/../../config/deploy_config.yml') 
   backer_info = config['servers']['backer']
 
-
+  backer_number = YAML.load_file(Rails.root.join('config','backer_number.yml'))[:seed_number].to_i
   # Create seed user
   username = backer_info[backer_number]['username'].gsub(/ /,'').downcase
   user = User.create( :email => "#{username}@#{username}.joindiaspora.com",
                      :password => "#{username+backer_info[backer_number]['pin'].to_s}",
-                     :profile => Profile.new( :first_name => backer_info[backer_number]['given_name'], :last_name => backer_info[backer_number]['family_name'] ),
-                    :url=> "#{username}.joindiaspora.com")
-
-  # Make connection with Diaspora Tom
-  #Person.create( :email => "tom@joindiaspora.com", :url => "http://tom.joindiaspora.com/", :active => true, :profile => Profile.new(:first_name => "Alexander", :last_name => "Hamiltom"))
-  # Make people
-  
-#  (0..10).each { |n|
-    #domain_name = backer_info[n][2].gsub(/ /,'').downcase
-    #url = "http://#{domain_name}.joindiaspora.com/"
-    #User.owner.send_friend_request_to(url)
-  #}
+                     :person => Person.new(
+                       :email => "#{username}@#{username}.joindiaspora.com",
+                       :profile => Profile.new( :first_name => backer_info[backer_number]['given_name'], :last_name => backer_info[backer_number]['family_name'] ),
+                       :url=> "http://#{username}.joindiaspora.com/")
+                    )
+  user.person.save
+  user.group(:name => "Presidents")
 end
 
diff --git a/db/seeds/dev.rb b/db/seeds/dev.rb
index 9bf7adb8008c012cd80c8a61b1c92395eab864a9..f13e27f4cd05c06745f105c31c41e4850604e8a3 100644
--- a/db/seeds/dev.rb
+++ b/db/seeds/dev.rb
@@ -9,5 +9,17 @@
 require 'config/environment'
 
 # Create seed user
-user = User.create( :email => "robert@joindiaspora.com", :password => "evankorth", :profile => Profile.new( :first_name => "bobert", :last_name => "brin" ))
+user = User.create( :email => "robert@joindiaspora.com", 
+                    :password => "evankorth", 
+                    :person => Person.new(
+                      :email => "robert@joindiaspora.com",
+                      :url => "http://localhost:3000/",
+                      :profile => Profile.new( 
+                        :first_name => "bobert", 
+                        :last_name => "brin" )))
 
+puts user.save
+puts user.person.save!
+puts user.save!
+puts user.person.inspect
+puts user.inspect
diff --git a/db/seeds/tom.rb b/db/seeds/tom.rb
index 4efae222d1afb013cff3525fd42b5946c46584b2..c8b1d41a6062d042bd97dcdc0889830a5503c63e 100644
--- a/db/seeds/tom.rb
+++ b/db/seeds/tom.rb
@@ -1,13 +1,27 @@
-#This file should contain all the record creation needed to seed the database with its default values.
-# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
-#
-# Examples:
-#
-#   cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
-#   Mayor.create(:name => 'Daley', :city => citie
-
 require 'config/environment'
 
+remote_url = "http://tom.joindiaspora.com/"
 # Create seed user
-user = User.create( :email => "tom@tom.joindiaspora.com", :password => "evankorth", :url => "http://tom.joindiaspora.com/", :profile => Profile.new( :first_name => "Alexander", :last_name => "Hamiltom" ))
+user = User.create!( :email => "tom@tom.joindiaspora.com",
+                    :password => "evankorth",
+                    :person => Person.new(
+                      :email => "tom@tom.joindiaspora.com",
+                      :url => remote_url,
+                      :profile => Profile.new( :first_name => "Alexander", :last_name => "Hamiltom" ))
+                  )
+user.person.save!
+
+user2 = User.create!( :email => "korth@tom.joindiaspora.com",
+                    :password => "evankorth",
+                    :person => Person.new( :email => "korth@tom.joindiaspora.com",
+                                          :url => remote_url, 
+                                          :profile => Profile.new( :first_name => "Evan",
+                                                                  :last_name => "Korth")))
+
+user2.person.save!
 
+# friending users
+group = user.group(:name => "other dudes")
+request = user.send_friend_request_to(user2.receive_url, group.id)
+reversed_request = user2.accept_friend_request( request.id, user2.group(:name => "presidents").id )
+user.receive reversed_request.to_diaspora_xml
diff --git a/lib/diaspora/parser.rb b/lib/diaspora/parser.rb
index 07439dbb90d96212f0827531209c8d3e8ed5430e..8835bd83bc57b96e22d255cb01fb81a339cf8dbb 100644
--- a/lib/diaspora/parser.rb
+++ b/lib/diaspora/parser.rb
@@ -1,57 +1,33 @@
 module Diaspora
   module Parser
-    def parse_owner_from_xml(xml)
+    def self.owner_id_from_xml(xml)
       doc = Nokogiri::XML(xml) { |cfg| cfg.noblanks }
-      email = doc.xpath("//person/email").text.to_s
-      Person.first(:email => email)
+      id = doc.xpath("//person_id").text.to_s
+      Person.first(:id => id)
     end
 
-    def parse_body_contents_from_xml(xml)
+    def self.get_or_create_person_object_from_xml(xml)
       doc = Nokogiri::XML(xml) { |cfg| cfg.noblanks }
-      doc.xpath("/XML/posts/post")
-    end
-    
-    def parse_owner_id_from_xml(doc)
-      id = doc.xpath("//person_id").text.to_s
-      Person.first(:id => id)
+      person_xml = doc.xpath("//request/person").to_s
+      person_id = doc.xpath("//request/person/_id").text.to_s
+      person = Person.first(:_id => person_id)
+      person ? person : Person.from_xml( person_xml)
     end
 
-    def parse_objects_from_xml(xml)
-      objects = []
-      body = parse_body_contents_from_xml(xml)
-      body.children.each do |post|
-        begin
-          object = post.name.camelize.constantize.from_xml post.to_s
-          if object.respond_to? :person  
-            object.person =  parse_owner_from_xml post.to_s 
-          elsif object.is_a? Profile
-            puts "got into parse objects from xml PROFILE"
-            person = parse_owner_id_from_xml post
-            person.profile = object
-            person.save  
-          end
-          objects << object
-        rescue
+    def self.from_xml(xml)
+
+      doc = Nokogiri::XML(xml) { |cfg| cfg.noblanks }
+      return unless body = doc.xpath("/XML/post").children.first
+
+      begin
+        body.name.camelize.constantize.from_xml body.to_s
+      rescue NameError => e
+        if e.message.include? 'wrong constant name'
           Rails.logger.info "Not a real type: #{object.to_s}"
         end
+        raise e
       end
-      objects
     end
 
-    def store_objects_from_xml(xml)
-      objects = parse_objects_from_xml(xml)
-      objects.each do |p|
-        Rails.logger.info("Receiving object:\n#{p.inspect}")
-        if p.is_a? Retraction
-          p.perform
-        elsif p.is_a? Request
-          User.owner.receive_friend_request(p)
-        elsif p.is_a? Profile
-          p.save
-        elsif p.respond_to?(:person) && !(p.person.nil?) && !(p.person.is_a? User) 
-          Rails.logger.info("Saving object with success: #{p.save}")
-        end
-      end
-    end
   end
 end
diff --git a/lib/diaspora/webhooks.rb b/lib/diaspora/webhooks.rb
index c6003e9578087734fc850a435f49ce10382f5c4f..dba3968e2161bb5ff504650bfc70f34604204e88 100644
--- a/lib/diaspora/webhooks.rb
+++ b/lib/diaspora/webhooks.rb
@@ -7,7 +7,7 @@ module Diaspora
         @@queue = MessageHandler.new
 
         def notify_people
-          if self.person_id == User.owner.id
+          unless self.person.owner.nil?
             push_to(people_with_permissions)
           end
         end
@@ -18,37 +18,37 @@ module Diaspora
 
         def push_to(recipients)
           unless recipients.empty?
-            recipients.map!{|x| x = x.url + "receive/"}  
-            xml = Post.build_xml_for(self)
-            Rails.logger.info("Adding xml for #{self} to message queue to #{recipients}")
+            recipients.map!{|x| x = x.receive_url }
+            xml = to_diaspora_xml
+            Rails.logger.debug("Adding xml for #{self} to message queue to #{recipients}")
             @@queue.add_post_request( recipients, xml )
           end
           @@queue.process
         end
 
         def push_to_url(url)
-          hook_url = url + "receive/"
-          xml = self.class.build_xml_for(self)
-          Rails.logger.info("Adding xml for #{self} to message queue to #{url}")
+          hook_url = url 
+          xml = to_diaspora_xml
+          Rails.logger.debug("Adding xml for #{self} to message queue to #{url}")
           @@queue.add_post_request( hook_url, xml )
           @@queue.process
         end
 
         def to_diaspora_xml
-          "<post>#{self.to_xml.to_s}</post>"
-        end
-
-        def people_with_permissions
-          Person.friends.all
-        end
-
-        def self.build_xml_for(posts)
           xml = "<XML>"
-          xml += "\n <posts>"
-          [*posts].each {|x| xml << x.to_diaspora_xml}
-          xml += "</posts>"
+          xml += "<post>#{self.to_xml.to_s}</post>"
           xml += "</XML>"
+        end
 
+        def people_with_permissions
+          begin
+          friends = self.person.owner.friends.all
+          Rails.logger.error("Dan is wrong!") if friends.nil?
+          friends ||= []
+          rescue
+            Rails.logger.fatal("Called people_with_permissions on a post from a remote user.  We need to implement this shit.")
+            []
+          end
         end
       end
     end
diff --git a/lib/diaspora/websocket.rb b/lib/diaspora/websocket.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bfbc69c2658656c2c696e5d3b5bb0dda3ea0d966
--- /dev/null
+++ b/lib/diaspora/websocket.rb
@@ -0,0 +1,43 @@
+module Diaspora
+  module WebSocket
+    def self.initialize_channels
+      @channels = {} 
+    end
+    
+    def self.push_to_user(uid, data)
+      Rails.logger.debug "Websocketing to #{uid}"
+      @channels[uid.to_s][0].push(data) if @channels[uid.to_s]
+    end
+    
+    def self.subscribe(uid, ws)
+      Rails.logger.debug "Subscribing socket to #{User.first(:id => uid).email}"
+      self.ensure_channel(uid)
+      @channels[uid][0].subscribe{ |msg| ws.send msg }
+      @channels[uid][1] += 1
+    end
+
+    def self.ensure_channel(uid)
+      @channels[uid] ||= [EM::Channel.new, 0 ]
+    end
+
+    def self.unsubscribe(uid,sid)
+      Rails.logger.debug "Unsubscribing socket #{sid} from #{uid}"
+      @channels[uid][0].unsubscribe(sid) if @channels[uid]
+      @channels[uid][1] -= 1
+      if @channels[uid][1] <= 0
+        @channels.delete(uid)
+      end
+    end
+  end
+
+  module Socketable
+    def socket_to_uid id
+      SocketsController.new.outgoing(id, self)
+    end
+    
+    def unsocket_from_uid id
+      SocketsController.new.outgoing(id, Retraction.for(self))
+    end
+
+  end
+end
diff --git a/lib/encryptable.rb b/lib/encryptable.rb
index 4d352971e8d502322d4c4d715a1fb17ccaf40950..850499bff889182ff8e94414bd8e6e62d08f3090 100644
--- a/lib/encryptable.rb
+++ b/lib/encryptable.rb
@@ -10,32 +10,26 @@
       if person.nil?
         Rails.logger.info("Verifying sig on #{signable_string} but no person is here")
         return false
-      elsif person.key.nil?
+      elsif person.encryption_key.nil?
         Rails.logger.info("Verifying sig on #{signable_string} but #{person.real_name} has no key")
         return false
       elsif signature.nil?
         Rails.logger.info("Verifying sig on #{signable_string} but #{person.real_name} did not sign")
         return false
       end
-      Rails.logger.info("Verifying sig on #{signable_string} from person #{person.real_name}")
-      validity = person.key.verify "SHA", Base64.decode64(signature), signable_string
-      Rails.logger.info("Validity: #{validity}")
+      Rails.logger.debug("Verifying sig on #{signable_string} from person #{person.real_name}")
+      validity = person.encryption_key.verify "SHA", Base64.decode64(signature), signable_string
+      Rails.logger.debug("Validity: #{validity}")
       validity
     end
     
     protected
     def sign_if_mine
-      if self.person == User.owner
-        self.creator_signature = sign
-      end
-    end
-
-    def sign
-      sign_with_key(User.owner.key)
+      self.creator_signature = sign_with_key(person.encryption_key) unless person.owner_id.nil?
     end
 
     def sign_with_key(key)
-      Rails.logger.info("Signing #{signable_string}")
+      Rails.logger.debug("Signing #{signable_string}")
       Base64.encode64(key.sign "SHA", signable_string)
       
     end
diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake
index 8c3bd23766a44742d398551e0ecc1bc15d524062..9b78b68555b95570ad2269ba687e3b957238bd44 100644
--- a/lib/tasks/db.rake
+++ b/lib/tasks/db.rake
@@ -11,10 +11,10 @@ namespace :db do
       require 'db/seeds/dev'
     end
 
-    task :backer, :num do |t, args|
+    task :backer do
       puts "Seeding the database for #{Rails.env}..."
       require 'db/seeds/backer'
-      create( Integer(args.num))
+      create
     end
   end
 
@@ -27,6 +27,9 @@ namespace :db do
     # Specifiy what models to remove
     # No!  Drop the fucking database.
    MongoMapper::connection.drop_database(MongoMapper::database.name) 
+
+   puts 'Deleting tmp folder...'
+   `rm -rf #{File.dirname(__FILE__)}/../../public/uploads/tmp`
   end
 
   desc 'Purge and seed the current RAILS_ENV database using information from db/seeds.rb'
diff --git a/public/images/ajax-loader.gif b/public/images/ajax-loader.gif
new file mode 100644
index 0000000000000000000000000000000000000000..e40f19a2818e4c81726bf965fc8dc108d52dc599
Binary files /dev/null and b/public/images/ajax-loader.gif differ
diff --git a/public/images/user/default.jpg b/public/images/user/default.jpg
index 788fd4f1d0d5a90933eb736a74c4f03c86049c97..b242c1e1c3ce1c06b7452a2fc93f74c05dea1950 100644
Binary files a/public/images/user/default.jpg and b/public/images/user/default.jpg differ
diff --git a/public/javascripts/fancybox/blank.gif b/public/javascripts/fancybox/blank.gif
new file mode 100644
index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66
Binary files /dev/null and b/public/javascripts/fancybox/blank.gif differ
diff --git a/public/javascripts/fancybox/fancy_close.png b/public/javascripts/fancybox/fancy_close.png
new file mode 100644
index 0000000000000000000000000000000000000000..07035307ad435f8f2f8eedf0bce50f7ec8a858c2
Binary files /dev/null and b/public/javascripts/fancybox/fancy_close.png differ
diff --git a/public/javascripts/fancybox/fancy_loading.png b/public/javascripts/fancybox/fancy_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..2503017960b3972499d3aa92f89953935ae40934
Binary files /dev/null and b/public/javascripts/fancybox/fancy_loading.png differ
diff --git a/public/javascripts/fancybox/fancy_nav_left.png b/public/javascripts/fancybox/fancy_nav_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..ebaa6a4fd34e51575a01da366312c20618985cbc
Binary files /dev/null and b/public/javascripts/fancybox/fancy_nav_left.png differ
diff --git a/public/javascripts/fancybox/fancy_nav_right.png b/public/javascripts/fancybox/fancy_nav_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..873294e969db9160f5ddd4e1ab498ff60b080e3f
Binary files /dev/null and b/public/javascripts/fancybox/fancy_nav_right.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_e.png b/public/javascripts/fancybox/fancy_shadow_e.png
new file mode 100644
index 0000000000000000000000000000000000000000..2eda0893649371f8d92b92976d8542cdd1b601ed
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_e.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_n.png b/public/javascripts/fancybox/fancy_shadow_n.png
new file mode 100644
index 0000000000000000000000000000000000000000..69aa10e233b039077e7dc600177ddb1eb46217e3
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_n.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_ne.png b/public/javascripts/fancybox/fancy_shadow_ne.png
new file mode 100644
index 0000000000000000000000000000000000000000..79f6980a3ba5c43de120d963dbba2516b8f27ac7
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_ne.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_nw.png b/public/javascripts/fancybox/fancy_shadow_nw.png
new file mode 100644
index 0000000000000000000000000000000000000000..7182cd938ae98e7e28c65a0bc55df576042ff9f5
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_nw.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_s.png b/public/javascripts/fancybox/fancy_shadow_s.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8858bfb78efb8d7268736920efa1eae8873f89c
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_s.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_se.png b/public/javascripts/fancybox/fancy_shadow_se.png
new file mode 100644
index 0000000000000000000000000000000000000000..541e3ffd3e88224b34a4d2097c66a780e6060aeb
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_se.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_sw.png b/public/javascripts/fancybox/fancy_shadow_sw.png
new file mode 100644
index 0000000000000000000000000000000000000000..b451689fa7b57b7432820e4c06d0864c143c79ab
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_sw.png differ
diff --git a/public/javascripts/fancybox/fancy_shadow_w.png b/public/javascripts/fancybox/fancy_shadow_w.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a4e4a887f18384a204563c0048c9cd1328f7faa
Binary files /dev/null and b/public/javascripts/fancybox/fancy_shadow_w.png differ
diff --git a/public/javascripts/fancybox/fancy_title_left.png b/public/javascripts/fancybox/fancy_title_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..6049223d1ec6af46e100499c01f6489c9e2c6240
Binary files /dev/null and b/public/javascripts/fancybox/fancy_title_left.png differ
diff --git a/public/javascripts/fancybox/fancy_title_main.png b/public/javascripts/fancybox/fancy_title_main.png
new file mode 100644
index 0000000000000000000000000000000000000000..8044271f29b5d4e4471570e75cdce90bf9a1497c
Binary files /dev/null and b/public/javascripts/fancybox/fancy_title_main.png differ
diff --git a/public/javascripts/fancybox/fancy_title_over.png b/public/javascripts/fancybox/fancy_title_over.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9f458f4bb8770466e44ba97dd8fe1f2936090db
Binary files /dev/null and b/public/javascripts/fancybox/fancy_title_over.png differ
diff --git a/public/javascripts/fancybox/fancy_title_right.png b/public/javascripts/fancybox/fancy_title_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..e36d9db2a7c6e570aec993d3665cbc13620115e2
Binary files /dev/null and b/public/javascripts/fancybox/fancy_title_right.png differ
diff --git a/public/javascripts/fancybox/fancybox-x.png b/public/javascripts/fancybox/fancybox-x.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2130f8698f682d68b1550bffedecfe19eaa1a81
Binary files /dev/null and b/public/javascripts/fancybox/fancybox-x.png differ
diff --git a/public/javascripts/fancybox/fancybox-y.png b/public/javascripts/fancybox/fancybox-y.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ef399b9908976fc36f760fad7876a4d9c38e006
Binary files /dev/null and b/public/javascripts/fancybox/fancybox-y.png differ
diff --git a/public/javascripts/fancybox/fancybox.png b/public/javascripts/fancybox/fancybox.png
new file mode 100644
index 0000000000000000000000000000000000000000..65e14f68fd83b87f75c22c0c074e7b20bf20a133
Binary files /dev/null and b/public/javascripts/fancybox/fancybox.png differ
diff --git a/public/javascripts/fancybox/jquery.easing-1.3.pack.js b/public/javascripts/fancybox/jquery.easing-1.3.pack.js
new file mode 100644
index 0000000000000000000000000000000000000000..9028179e7bde19e3c0fdbf9f422c35c4a0d95034
--- /dev/null
+++ b/public/javascripts/fancybox/jquery.easing-1.3.pack.js
@@ -0,0 +1,72 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ * 
+ * Open source under the BSD License. 
+ * 
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this list of 
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list 
+ * of conditions and the following disclaimer in the documentation and/or other materials 
+ * provided with the distribution.
+ * 
+ * Neither the name of the author nor the names of contributors may be used to endorse 
+ * or promote products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
+ * OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ * 
+ * Open source under the BSD License. 
+ * 
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice, this list of 
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list 
+ * of conditions and the following disclaimer in the documentation and/or other materials 
+ * provided with the distribution.
+ * 
+ * Neither the name of the author nor the names of contributors may be used to endorse 
+ * or promote products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
+ * OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+ */
diff --git a/public/javascripts/fancybox/jquery.fancybox-1.3.1.css b/public/javascripts/fancybox/jquery.fancybox-1.3.1.css
new file mode 100644
index 0000000000000000000000000000000000000000..28bbb132761d7d836df3fadd4572039bb3fd4cc3
--- /dev/null
+++ b/public/javascripts/fancybox/jquery.fancybox-1.3.1.css
@@ -0,0 +1,363 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ * 
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ *
+ * Version: 1.3.1 (05/03/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+	position: fixed;
+	top: 50%;
+	left: 50%;
+	height: 40px;
+	width: 40px;
+	margin-top: -20px;
+	margin-left: -20px;
+	cursor: pointer;
+	overflow: hidden;
+	z-index: 1104;
+	display: none;
+}
+
+* html #fancybox-loading {	/* IE6 */
+	position: absolute;
+	margin-top: 0;
+}
+
+#fancybox-loading div {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 40px;
+	height: 480px;
+	background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+	position: fixed;
+	top: 0;
+	left: 0;
+	bottom: 0;
+	right: 0;
+	background: #000;
+	z-index: 1100;
+	display: none;
+}
+
+* html #fancybox-overlay {	/* IE6 */
+	position: absolute;
+	width: 100%;
+}
+
+#fancybox-tmp {
+	padding: 0;
+	margin: 0;
+	border: 0;
+	overflow: auto;
+	display: none;
+}
+
+#fancybox-wrap {
+	position: absolute;
+	top: 0;
+	left: 0;
+	margin: 0;
+	padding: 20px;
+	z-index: 1101;
+	display: none;
+}
+
+#fancybox-outer {
+	position: relative;
+	width: 100%;
+	height: 100%;
+	background: #FFF;
+}
+
+#fancybox-inner {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 1px;
+	height: 1px;
+	padding: 0;
+	margin: 0;
+	outline: none;
+	overflow: hidden;
+}
+
+#fancybox-hide-sel-frame {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	background: transparent;
+}
+
+#fancybox-close {
+	position: absolute;
+	top: -15px;
+	right: -15px;
+	width: 30px;
+	height: 30px;
+	background-image: url('fancybox.png');
+	background-position: -40px 0px;
+	cursor: pointer;
+	z-index: 1103;
+	display: none;
+}
+
+#fancybox_error {
+	color: #444;
+	font: normal 12px/20px Arial;
+	padding: 7px;
+	margin: 0;
+}
+
+#fancybox-content {
+	height: auto;
+	width: auto;
+	padding: 0;
+	margin: 0;
+}
+
+#fancybox-img {
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
+	border: none;
+	outline: none;
+	line-height: 0;
+	vertical-align: top;
+	-ms-interpolation-mode: bicubic;
+}
+
+#fancybox-frame {
+	position: relative;
+	width: 100%;
+	height: 100%;
+	border: none;
+	display: block;
+}
+
+#fancybox-title {
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	font-family: Arial;
+	font-size: 12px;
+	z-index: 1102;
+}
+
+.fancybox-title-inside {
+	padding: 10px 0;
+	text-align: center;
+	color: #333;
+}
+
+.fancybox-title-outside {
+	padding-top: 5px;
+	color: #FFF;
+	text-align: center;
+	font-weight: bold;
+}
+
+.fancybox-title-over {
+	color: #FFF;
+	text-align: left;
+}
+
+#fancybox-title-over {
+	padding: 10px;
+	background-image: url('fancy_title_over.png');
+	display: block;
+}
+
+#fancybox-title-wrap {
+	display: inline-block;
+}
+
+#fancybox-title-wrap span {
+	height: 32px;
+	float: left;
+}
+
+#fancybox-title-left {
+	padding-left: 15px;
+	background-image: url('fancybox.png');
+	background-position: -40px -90px;
+	background-repeat: no-repeat;
+}
+
+#fancybox-title-main {
+	font-weight: bold;
+	line-height: 29px;
+	background-image: url('fancybox-x.png');
+	background-position: 0px -40px;
+	color: #FFF;
+}
+
+#fancybox-title-right {
+	padding-left: 15px;
+	background-image: url('fancybox.png');
+	background-position: -55px -90px;
+	background-repeat: no-repeat;
+}
+
+#fancybox-left, #fancybox-right {
+	position: absolute;
+	bottom: 0px;
+	height: 100%;
+	width: 35%;
+	cursor: pointer;
+	outline: none;
+	background-image: url('blank.gif');
+	z-index: 1102;
+	display: none;
+}
+
+#fancybox-left {
+	left: 0px;
+}
+
+#fancybox-right {
+	right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+	position: absolute;
+	top: 50%;
+	left: -9999px;
+	width: 30px;
+	height: 30px;
+	margin-top: -15px;
+	cursor: pointer;
+	z-index: 1102;
+	display: block;
+}
+
+#fancybox-left-ico {
+	background-image: url('fancybox.png');
+	background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+	background-image: url('fancybox.png');
+	background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+	visibility: visible;    /* IE6 */
+}
+
+#fancybox-left:hover span {
+	left: 20px;
+}
+
+#fancybox-right:hover span {
+	left: auto;
+	right: 20px;
+}
+
+.fancy-bg {
+	position: absolute;
+	padding: 0;
+	margin: 0;
+	border: 0;
+	width: 20px;
+	height: 20px;
+	z-index: 1001;
+}
+
+#fancy-bg-n {
+	top: -20px;
+	left: 0;
+	width: 100%;
+	background-image: url('fancybox-x.png');
+}
+
+#fancy-bg-ne {
+	top: -20px;
+	right: -20px;
+	background-image: url('fancybox.png');
+	background-position: -40px -162px;
+}
+
+#fancy-bg-e {
+	top: 0;
+	right: -20px;
+	height: 100%;
+	background-image: url('fancybox-y.png');
+	background-position: -20px 0px;
+}
+
+#fancy-bg-se {
+	bottom: -20px;
+	right: -20px;
+	background-image: url('fancybox.png');
+	background-position: -40px -182px; 
+}
+
+#fancy-bg-s {
+	bottom: -20px;
+	left: 0;
+	width: 100%;
+	background-image: url('fancybox-x.png');
+	background-position: 0px -20px;
+}
+
+#fancy-bg-sw {
+	bottom: -20px;
+	left: -20px;
+	background-image: url('fancybox.png');
+	background-position: -40px -142px;
+}
+
+#fancy-bg-w {
+	top: 0;
+	left: -20px;
+	height: 100%;
+	background-image: url('fancybox-y.png');
+}
+
+#fancy-bg-nw {
+	top: -20px;
+	left: -20px;
+	background-image: url('fancybox.png');
+	background-position: -40px -122px;
+}
+
+/* IE */
+
+#fancybox-loading.fancybox-ie div	{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-close		{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie #fancybox-title-over	{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie #fancybox-title-left	{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-title-main	{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-title-right	{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie #fancybox-left-ico		{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-right-ico	{ background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie .fancy-bg { background: transparent !important; }
+
+.fancybox-ie #fancy-bg-n	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-ne	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-e	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-se	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-s	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-sw	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-w	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancy-bg-nw	{ filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
diff --git a/public/javascripts/fancybox/jquery.fancybox-1.3.1.js b/public/javascripts/fancybox/jquery.fancybox-1.3.1.js
new file mode 100644
index 0000000000000000000000000000000000000000..688f93aa34a8b739cbaeaf23e3dbfbaac8c098a4
--- /dev/null
+++ b/public/javascripts/fancybox/jquery.fancybox-1.3.1.js
@@ -0,0 +1,1077 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ * 
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ *
+ * Version: 1.3.1 (05/03/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+(function($) {
+
+	var tmp, loading, overlay, wrap, outer, inner, close, nav_left, nav_right,
+
+		selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
+
+		ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
+
+		loadingTimer, loadingFrame = 1,
+
+		start_pos, final_pos, busy = false, shadow = 20, fx = $.extend($('<div/>')[0], { prop: 0 }), titleh = 0, 
+
+		isIE6 = !$.support.opacity && !window.XMLHttpRequest,
+
+		/*
+		 * Private methods 
+		 */
+
+		fancybox_abort = function() {
+			loading.hide();
+
+			imgPreloader.onerror = imgPreloader.onload = null;
+
+			if (ajaxLoader) {
+				ajaxLoader.abort();
+			}
+
+			tmp.empty();
+		},
+
+		fancybox_error = function() {
+			$.fancybox('<p id="fancybox_error">The requested content cannot be loaded.<br />Please try again later.</p>', {
+				'scrolling'		: 'no',
+				'padding'		: 20,
+				'transitionIn'	: 'none',
+				'transitionOut'	: 'none'
+			});
+		},
+
+		fancybox_get_viewport = function() {
+			return [ $(window).width(), $(window).height(), $(document).scrollLeft(), $(document).scrollTop() ];
+		},
+
+		fancybox_get_zoom_to = function () {
+			var view	= fancybox_get_viewport(),
+				to		= {},
+
+				margin = currentOpts.margin,
+				resize = currentOpts.autoScale,
+
+				horizontal_space	= (shadow + margin) * 2,
+				vertical_space		= (shadow + margin) * 2,
+				double_padding		= (currentOpts.padding * 2),
+				
+				ratio;
+
+			if (currentOpts.width.toString().indexOf('%') > -1) {
+				to.width = ((view[0] * parseFloat(currentOpts.width)) / 100) - (shadow * 2) ;
+				resize = false;
+
+			} else {
+				to.width = currentOpts.width + double_padding;
+			}
+
+			if (currentOpts.height.toString().indexOf('%') > -1) {
+				to.height = ((view[1] * parseFloat(currentOpts.height)) / 100) - (shadow * 2);
+				resize = false;
+
+			} else {
+				to.height = currentOpts.height + double_padding;
+			}
+
+			if (resize && (to.width > (view[0] - horizontal_space) || to.height > (view[1] - vertical_space))) {
+				if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
+					horizontal_space	+= double_padding;
+					vertical_space		+= double_padding;
+
+					ratio = Math.min(Math.min( view[0] - horizontal_space, currentOpts.width) / currentOpts.width, Math.min( view[1] - vertical_space, currentOpts.height) / currentOpts.height);
+
+					to.width	= Math.round(ratio * (to.width	- double_padding)) + double_padding;
+					to.height	= Math.round(ratio * (to.height	- double_padding)) + double_padding;
+
+				} else {
+					to.width	= Math.min(to.width,	(view[0] - horizontal_space));
+					to.height	= Math.min(to.height,	(view[1] - vertical_space));
+				}
+			}
+
+			to.top	= view[3] + ((view[1] - (to.height	+ (shadow * 2 ))) * 0.5);
+			to.left	= view[2] + ((view[0] - (to.width	+ (shadow * 2 ))) * 0.5);
+
+			if (currentOpts.autoScale === false) {
+				to.top	= Math.max(view[3] + margin, to.top);
+				to.left	= Math.max(view[2] + margin, to.left);
+			}
+
+			return to;
+		},
+
+		fancybox_format_title = function(title) {
+			if (title && title.length) {
+				switch (currentOpts.titlePosition) {
+					case 'inside':
+						return title;
+					case 'over':
+						return '<span id="fancybox-title-over">' + title + '</span>';
+					default:
+						return '<span id="fancybox-title-wrap"><span id="fancybox-title-left"></span><span id="fancybox-title-main">' + title + '</span><span id="fancybox-title-right"></span></span>';
+				}
+			}
+
+			return false;
+		},
+
+		fancybox_process_title = function() {
+			var title	= currentOpts.title,
+				width	= final_pos.width - (currentOpts.padding * 2),
+				titlec	= 'fancybox-title-' + currentOpts.titlePosition;
+				
+			$('#fancybox-title').remove();
+
+			titleh = 0;
+
+			if (currentOpts.titleShow === false) {
+				return;
+			}
+
+			title = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(title, currentArray, currentIndex, currentOpts) : fancybox_format_title(title);
+
+			if (!title || title === '') {
+				return;
+			}
+
+			$('<div id="fancybox-title" class="' + titlec + '" />').css({
+				'width'			: width,
+				'paddingLeft'	: currentOpts.padding,
+				'paddingRight'	: currentOpts.padding
+			}).html(title).appendTo('body');
+
+			switch (currentOpts.titlePosition) {
+				case 'inside':
+					titleh = $("#fancybox-title").outerHeight(true) - currentOpts.padding;
+					final_pos.height += titleh;
+				break;
+
+				case 'over':
+					$('#fancybox-title').css('bottom', currentOpts.padding);
+				break;
+
+				default:
+					$('#fancybox-title').css('bottom', $("#fancybox-title").outerHeight(true) * -1);
+				break;
+			}
+
+			$('#fancybox-title').appendTo( outer ).hide();
+		},
+
+		fancybox_set_navigation = function() {
+			$(document).unbind('keydown.fb').bind('keydown.fb', function(e) {
+				if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
+					e.preventDefault();
+					$.fancybox.close();
+
+				} else if (e.keyCode == 37) {
+					e.preventDefault();
+					$.fancybox.prev();
+
+				} else if (e.keyCode == 39) {
+					e.preventDefault();
+					$.fancybox.next();
+				}
+			});
+
+			if ($.fn.mousewheel) {
+				wrap.unbind('mousewheel.fb');
+
+				if (currentArray.length > 1) {
+					wrap.bind('mousewheel.fb', function(e, delta) {
+						e.preventDefault();
+
+						if (busy || delta === 0) {
+							return;
+						}
+
+						if (delta > 0) {
+							$.fancybox.prev();
+						} else {
+							$.fancybox.next();
+						}
+					});
+				}
+			}
+
+			if (!currentOpts.showNavArrows) { return; }
+
+			if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
+				nav_left.show();
+			}
+
+			if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
+				nav_right.show();
+			}
+		},
+
+		fancybox_preload_images = function() {
+			var href, 
+				objNext;
+				
+			if ((currentArray.length -1) > currentIndex) {
+				href = currentArray[ currentIndex + 1 ].href;
+
+				if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+					objNext = new Image();
+					objNext.src = href;
+				}
+			}
+
+			if (currentIndex > 0) {
+				href = currentArray[ currentIndex - 1 ].href;
+
+				if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+					objNext = new Image();
+					objNext.src = href;
+				}
+			}
+		},
+
+		_finish = function () {
+			inner.css('overflow', (currentOpts.scrolling == 'auto' ? (currentOpts.type == 'image' || currentOpts.type == 'iframe' || currentOpts.type == 'swf' ? 'hidden' : 'auto') : (currentOpts.scrolling == 'yes' ? 'auto' : 'visible')));
+
+			if (!$.support.opacity) {
+				inner.get(0).style.removeAttribute('filter');
+				wrap.get(0).style.removeAttribute('filter');
+			}
+
+			$('#fancybox-title').show();
+
+			if (currentOpts.hideOnContentClick)	{
+				inner.one('click', $.fancybox.close);
+			}
+			if (currentOpts.hideOnOverlayClick)	{
+				overlay.one('click', $.fancybox.close);
+			}
+
+			if (currentOpts.showCloseButton) {
+				close.show();
+			}
+
+			fancybox_set_navigation();
+
+			$(window).bind("resize.fb", $.fancybox.center);
+
+			if (currentOpts.centerOnScroll) {
+				$(window).bind("scroll.fb", $.fancybox.center);
+			} else {
+				$(window).unbind("scroll.fb");
+			}
+
+			if ($.isFunction(currentOpts.onComplete)) {
+				currentOpts.onComplete(currentArray, currentIndex, currentOpts);
+			}
+
+			busy = false;
+
+			fancybox_preload_images();
+		},
+
+		fancybox_draw = function(pos) {
+			var width	= Math.round(start_pos.width	+ (final_pos.width	- start_pos.width)	* pos),
+				height	= Math.round(start_pos.height	+ (final_pos.height	- start_pos.height)	* pos),
+
+				top		= Math.round(start_pos.top	+ (final_pos.top	- start_pos.top)	* pos),
+				left	= Math.round(start_pos.left	+ (final_pos.left	- start_pos.left)	* pos);
+
+			wrap.css({
+				'width'		: width		+ 'px',
+				'height'	: height	+ 'px',
+				'top'		: top		+ 'px',
+				'left'		: left		+ 'px'
+			});
+
+			width	= Math.max(width - currentOpts.padding * 2, 0);
+			height	= Math.max(height - (currentOpts.padding * 2 + (titleh * pos)), 0);
+
+			inner.css({
+				'width'		: width		+ 'px',
+				'height'	: height	+ 'px'
+			});
+
+			if (typeof final_pos.opacity !== 'undefined') {
+				wrap.css('opacity', (pos < 0.5 ? 0.5 : pos));
+			}
+		},
+
+		fancybox_get_obj_pos = function(obj) {
+			var pos		= obj.offset();
+
+			pos.top		+= parseFloat( obj.css('paddingTop') )	|| 0;
+			pos.left	+= parseFloat( obj.css('paddingLeft') )	|| 0;
+
+			pos.top		+= parseFloat( obj.css('border-top-width') )	|| 0;
+			pos.left	+= parseFloat( obj.css('border-left-width') )	|| 0;
+
+			pos.width	= obj.width();
+			pos.height	= obj.height();
+
+			return pos;
+		},
+
+		fancybox_get_zoom_from = function() {
+			var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
+				from = {},
+				pos,
+				view;
+
+			if (orig && orig.length) {
+				pos = fancybox_get_obj_pos(orig);
+
+				from = {
+					width	: (pos.width	+ (currentOpts.padding * 2)),
+					height	: (pos.height	+ (currentOpts.padding * 2)),
+					top		: (pos.top		- currentOpts.padding - shadow),
+					left	: (pos.left		- currentOpts.padding - shadow)
+				};
+				
+			} else {
+				view = fancybox_get_viewport();
+
+				from = {
+					width	: 1,
+					height	: 1,
+					top		: view[3] + view[1] * 0.5,
+					left	: view[2] + view[0] * 0.5
+				};
+			}
+
+			return from;
+		},
+
+		fancybox_show = function() {
+			loading.hide();
+
+			if (wrap.is(":visible") && $.isFunction(currentOpts.onCleanup)) {
+				if (currentOpts.onCleanup(currentArray, currentIndex, currentOpts) === false) {
+					$.event.trigger('fancybox-cancel');
+
+					busy = false;
+					return;
+				}
+			}
+
+			currentArray	= selectedArray;
+			currentIndex	= selectedIndex;
+			currentOpts		= selectedOpts;
+
+			inner.get(0).scrollTop	= 0;
+			inner.get(0).scrollLeft	= 0;
+
+			if (currentOpts.overlayShow) {
+				if (isIE6) {
+					$('select:not(#fancybox-tmp select)').filter(function() {
+						return this.style.visibility !== 'hidden';
+					}).css({'visibility':'hidden'}).one('fancybox-cleanup', function() {
+						this.style.visibility = 'inherit';
+					});
+				}
+
+				overlay.css({
+					'background-color'	: currentOpts.overlayColor,
+					'opacity'			: currentOpts.overlayOpacity
+				}).unbind().show();
+			}
+
+			final_pos = fancybox_get_zoom_to();
+
+			fancybox_process_title();
+
+			if (wrap.is(":visible")) {
+				$( close.add( nav_left ).add( nav_right ) ).hide();
+
+				var pos = wrap.position(),
+					equal;
+
+				start_pos = {
+					top		:	pos.top ,
+					left	:	pos.left,
+					width	:	wrap.width(),
+					height	:	wrap.height()
+				};
+
+				equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
+
+				inner.fadeOut(currentOpts.changeFade, function() {
+					var finish_resizing = function() {
+						inner.html( tmp.contents() ).fadeIn(currentOpts.changeFade, _finish);
+					};
+					
+					$.event.trigger('fancybox-change');
+
+					inner.empty().css('overflow', 'hidden');
+
+					if (equal) {
+						inner.css({
+							top			: currentOpts.padding,
+							left		: currentOpts.padding,
+							width		: Math.max(final_pos.width	- (currentOpts.padding * 2), 1),
+							height		: Math.max(final_pos.height	- (currentOpts.padding * 2) - titleh, 1)
+						});
+						
+						finish_resizing();
+
+					} else {
+						inner.css({
+							top			: currentOpts.padding,
+							left		: currentOpts.padding,
+							width		: Math.max(start_pos.width	- (currentOpts.padding * 2), 1),
+							height		: Math.max(start_pos.height	- (currentOpts.padding * 2), 1)
+						});
+						
+						fx.prop = 0;
+
+						$(fx).animate({ prop: 1 }, {
+							 duration	: currentOpts.changeSpeed,
+							 easing		: currentOpts.easingChange,
+							 step		: fancybox_draw,
+							 complete	: finish_resizing
+						});
+					}
+				});
+
+				return;
+			}
+
+			wrap.css('opacity', 1);
+
+			if (currentOpts.transitionIn == 'elastic') {
+				start_pos = fancybox_get_zoom_from();
+
+				inner.css({
+						top			: currentOpts.padding,
+						left		: currentOpts.padding,
+						width		: Math.max(start_pos.width	- (currentOpts.padding * 2), 1),
+						height		: Math.max(start_pos.height	- (currentOpts.padding * 2), 1)
+					})
+					.html( tmp.contents() );
+
+				wrap.css(start_pos).show();
+
+				if (currentOpts.opacity) {
+					final_pos.opacity = 0;
+				}
+
+				fx.prop = 0;
+
+				$(fx).animate({ prop: 1 }, {
+					 duration	: currentOpts.speedIn,
+					 easing		: currentOpts.easingIn,
+					 step		: fancybox_draw,
+					 complete	: _finish
+				});
+
+			} else {
+				inner.css({
+						top			: currentOpts.padding,
+						left		: currentOpts.padding,
+						width		: Math.max(final_pos.width	- (currentOpts.padding * 2), 1),
+						height		: Math.max(final_pos.height	- (currentOpts.padding * 2) - titleh, 1)
+					})
+					.html( tmp.contents() );
+
+				wrap.css( final_pos ).fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
+			}
+		},
+
+		fancybox_process_inline = function() {
+			tmp.width(	selectedOpts.width );
+			tmp.height(	selectedOpts.height );
+
+			if (selectedOpts.width	== 'auto') {
+				selectedOpts.width = tmp.width();
+			}
+			if (selectedOpts.height	== 'auto') {
+				selectedOpts.height	= tmp.height();
+			}
+
+			fancybox_show();
+		},
+		
+		fancybox_process_image = function() {
+			busy = true;
+
+			selectedOpts.width	= imgPreloader.width;
+			selectedOpts.height	= imgPreloader.height;
+
+			$("<img />").attr({
+				'id'	: 'fancybox-img',
+				'src'	: imgPreloader.src,
+				'alt'	: selectedOpts.title
+			}).appendTo( tmp );
+
+			fancybox_show();
+		},
+
+		fancybox_start = function() {
+			fancybox_abort();
+
+			var obj	= selectedArray[ selectedIndex ],
+				href, 
+				type, 
+				title,
+				str,
+				emb,
+				selector,
+				data;
+
+			selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
+			title = obj.title || $(obj).title || selectedOpts.title || '';
+			
+			if (obj.nodeName && !selectedOpts.orig) {
+				selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
+			}
+
+			if (title === '' && selectedOpts.orig) {
+				title = selectedOpts.orig.attr('alt');
+			}
+
+			if (obj.nodeName && (/^(?:javascript|#)/i).test(obj.href)) {
+				href = selectedOpts.href || null;
+			} else {
+				href = selectedOpts.href || obj.href || null;
+			}
+
+			if (selectedOpts.type) {
+				type = selectedOpts.type;
+
+				if (!href) {
+					href = selectedOpts.content;
+				}
+				
+			} else if (selectedOpts.content) {
+				type	= 'html';
+
+			} else if (href) {
+				if (href.match(imgRegExp)) {
+					type = 'image';
+
+				} else if (href.match(swfRegExp)) {
+					type = 'swf';
+
+				} else if ($(obj).hasClass("iframe")) {
+					type = 'iframe';
+
+				} else if (href.match(/#/)) {
+					obj = href.substr(href.indexOf("#"));
+
+					type = $(obj).length > 0 ? 'inline' : 'ajax';
+				} else {
+					type = 'ajax';
+				}
+			} else {
+				type = 'inline';
+			}
+
+			selectedOpts.type	= type;
+			selectedOpts.href	= href;
+			selectedOpts.title	= title;
+
+			if (selectedOpts.autoDimensions && selectedOpts.type !== 'iframe' && selectedOpts.type !== 'swf') {
+				selectedOpts.width		= 'auto';
+				selectedOpts.height		= 'auto';
+			}
+
+			if (selectedOpts.modal) {
+				selectedOpts.overlayShow		= true;
+				selectedOpts.hideOnOverlayClick	= false;
+				selectedOpts.hideOnContentClick	= false;
+				selectedOpts.enableEscapeButton	= false;
+				selectedOpts.showCloseButton	= false;
+			}
+
+			if ($.isFunction(selectedOpts.onStart)) {
+				if (selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts) === false) {
+					busy = false;
+					return;
+				}
+			}
+
+			tmp.css('padding', (shadow + selectedOpts.padding + selectedOpts.margin));
+
+			$('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
+				$(this).replaceWith(inner.children());
+			});
+
+			switch (type) {
+				case 'html' :
+					tmp.html( selectedOpts.content );
+					fancybox_process_inline();
+				break;
+
+				case 'inline' :
+					$('<div class="fancybox-inline-tmp" />').hide().insertBefore( $(obj) ).bind('fancybox-cleanup', function() {
+						$(this).replaceWith(inner.children());
+					}).bind('fancybox-cancel', function() {
+						$(this).replaceWith(tmp.children());
+					});
+
+					$(obj).appendTo(tmp);
+
+					fancybox_process_inline();
+				break;
+
+				case 'image':
+					busy = false;
+
+					$.fancybox.showActivity();
+
+					imgPreloader = new Image();
+
+					imgPreloader.onerror = function() {
+						fancybox_error();
+					};
+
+					imgPreloader.onload = function() {
+						imgPreloader.onerror = null;
+						imgPreloader.onload = null;
+						fancybox_process_image();
+					};
+
+					imgPreloader.src = href;
+		
+				break;
+
+				case 'swf':
+					str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
+					emb = '';
+					
+					$.each(selectedOpts.swf, function(name, val) {
+						str += '<param name="' + name + '" value="' + val + '"></param>';
+						emb += ' ' + name + '="' + val + '"';
+					});
+
+					str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
+
+					tmp.html(str);
+
+					fancybox_process_inline();
+				break;
+
+				case 'ajax':
+					selector	= href.split('#', 2);
+					data		= selectedOpts.ajax.data || {};
+
+					if (selector.length > 1) {
+						href = selector[0];
+
+						if (typeof data == "string") {
+							data += '&selector=' + selector[1];
+						} else {
+							data.selector = selector[1];
+						}
+					}
+
+					busy = false;
+					$.fancybox.showActivity();
+
+					ajaxLoader = $.ajax($.extend(selectedOpts.ajax, {
+						url		: href,
+						data	: data,
+						error	: fancybox_error,
+						success : function(data, textStatus, XMLHttpRequest) {
+							if (ajaxLoader.status == 200) {
+								tmp.html( data );
+								fancybox_process_inline();
+							}
+						}
+					}));
+
+				break;
+
+				case 'iframe' :
+					$('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" scrolling="' + selectedOpts.scrolling + '" src="' + selectedOpts.href + '"></iframe>').appendTo(tmp);
+					fancybox_show();
+				break;
+			}
+		},
+
+		fancybox_animate_loading = function() {
+			if (!loading.is(':visible')){
+				clearInterval(loadingTimer);
+				return;
+			}
+
+			$('div', loading).css('top', (loadingFrame * -40) + 'px');
+
+			loadingFrame = (loadingFrame + 1) % 12;
+		},
+
+		fancybox_init = function() {
+			if ($("#fancybox-wrap").length) {
+				return;
+			}
+
+			$('body').append(
+				tmp			= $('<div id="fancybox-tmp"></div>'),
+				loading		= $('<div id="fancybox-loading"><div></div></div>'),
+				overlay		= $('<div id="fancybox-overlay"></div>'),
+				wrap		= $('<div id="fancybox-wrap"></div>')
+			);
+
+			if (!$.support.opacity) {
+				wrap.addClass('fancybox-ie');
+				loading.addClass('fancybox-ie');
+			}
+
+			outer = $('<div id="fancybox-outer"></div>')
+				.append('<div class="fancy-bg" id="fancy-bg-n"></div><div class="fancy-bg" id="fancy-bg-ne"></div><div class="fancy-bg" id="fancy-bg-e"></div><div class="fancy-bg" id="fancy-bg-se"></div><div class="fancy-bg" id="fancy-bg-s"></div><div class="fancy-bg" id="fancy-bg-sw"></div><div class="fancy-bg" id="fancy-bg-w"></div><div class="fancy-bg" id="fancy-bg-nw"></div>')
+				.appendTo( wrap );
+
+			outer.append(
+				inner		= $('<div id="fancybox-inner"></div>'),
+				close		= $('<a id="fancybox-close"></a>'),
+
+				nav_left	= $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
+				nav_right	= $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
+			);
+
+			close.click($.fancybox.close);
+			loading.click($.fancybox.cancel);
+
+			nav_left.click(function(e) {
+				e.preventDefault();
+				$.fancybox.prev();
+			});
+
+			nav_right.click(function(e) {
+				e.preventDefault();
+				$.fancybox.next();
+			});
+
+			if (isIE6) {
+				overlay.get(0).style.setExpression('height',	"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'");
+				loading.get(0).style.setExpression('top',		"(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'");
+
+				outer.prepend('<iframe id="fancybox-hide-sel-frame" src="javascript:\'\';" scrolling="no" frameborder="0" ></iframe>');
+			}
+		};
+
+	/*
+	 * Public methods 
+	 */
+
+	$.fn.fancybox = function(options) {
+		$(this)
+			.data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
+			.unbind('click.fb').bind('click.fb', function(e) {
+				e.preventDefault();
+
+				if (busy) {
+					return;
+				}
+
+				busy = true;
+
+				$(this).blur();
+
+				selectedArray	= [];
+				selectedIndex	= 0;
+
+				var rel = $(this).attr('rel') || '';
+
+				if (!rel || rel == '' || rel === 'nofollow') {
+					selectedArray.push(this);
+
+				} else {
+					selectedArray	= $("a[rel=" + rel + "], area[rel=" + rel + "]");
+					selectedIndex	= selectedArray.index( this );
+				}
+
+				fancybox_start();
+
+				return false;
+			});
+
+		return this;
+	};
+
+	$.fancybox = function(obj) {
+		if (busy) {
+			return;
+		}
+
+		busy = true;
+
+		var opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
+
+		selectedArray	= [];
+		selectedIndex	= opts.index || 0;
+
+		if ($.isArray(obj)) {
+			for (var i = 0, j = obj.length; i < j; i++) {
+				if (typeof obj[i] == 'object') {
+					$(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
+				} else {
+					obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
+				}
+			}
+
+			selectedArray = jQuery.merge(selectedArray, obj);
+
+		} else {
+			if (typeof obj == 'object') {
+				$(obj).data('fancybox', $.extend({}, opts, obj));
+			} else {
+				obj = $({}).data('fancybox', $.extend({content : obj}, opts));
+			}
+
+			selectedArray.push(obj);
+		}
+
+		if (selectedIndex > selectedArray.length || selectedIndex < 0) {
+			selectedIndex = 0;
+		}
+
+		fancybox_start();
+	};
+
+	$.fancybox.showActivity = function() {
+		clearInterval(loadingTimer);
+
+		loading.show();
+		loadingTimer = setInterval(fancybox_animate_loading, 66);
+	};
+
+	$.fancybox.hideActivity = function() {
+		loading.hide();
+	};
+
+	$.fancybox.next = function() {
+		return $.fancybox.pos( currentIndex + 1);
+	};
+	
+	$.fancybox.prev = function() {
+		return $.fancybox.pos( currentIndex - 1);
+	};
+
+	$.fancybox.pos = function(pos) {
+		if (busy) {
+			return;
+		}
+
+		pos = parseInt(pos, 10);
+
+		if (pos > -1 && currentArray.length > pos) {
+			selectedIndex = pos;
+			fancybox_start();
+		}
+
+		if (currentOpts.cyclic && currentArray.length > 1 && pos < 0) {
+			selectedIndex = currentArray.length - 1;
+			fancybox_start();
+		}
+
+		if (currentOpts.cyclic && currentArray.length > 1 && pos >= currentArray.length) {
+			selectedIndex = 0;
+			fancybox_start();
+		}
+
+		return;
+	};
+
+	$.fancybox.cancel = function() {
+		if (busy) {
+			return;
+		}
+
+		busy = true;
+
+		$.event.trigger('fancybox-cancel');
+
+		fancybox_abort();
+
+		if (selectedOpts && $.isFunction(selectedOpts.onCancel)) {
+			selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
+		}
+
+		busy = false;
+	};
+
+	// Note: within an iframe use - parent.$.fancybox.close();
+	$.fancybox.close = function() {
+		if (busy || wrap.is(':hidden')) {
+			return;
+		}
+
+		busy = true;
+
+		if (currentOpts && $.isFunction(currentOpts.onCleanup)) {
+			if (currentOpts.onCleanup(currentArray, currentIndex, currentOpts) === false) {
+				busy = false;
+				return;
+			}
+		}
+
+		fancybox_abort();
+
+		$(close.add( nav_left ).add( nav_right )).hide();
+
+		$('#fancybox-title').remove();
+
+		wrap.add(inner).add(overlay).unbind();
+
+		$(window).unbind("resize.fb scroll.fb");
+		$(document).unbind('keydown.fb');
+
+		function _cleanup() {
+			overlay.fadeOut('fast');
+
+			wrap.hide();
+
+			$.event.trigger('fancybox-cleanup');
+
+			inner.empty();
+
+			if ($.isFunction(currentOpts.onClosed)) {
+				currentOpts.onClosed(currentArray, currentIndex, currentOpts);
+			}
+
+			currentArray	= selectedOpts	= [];
+			currentIndex	= selectedIndex	= 0;
+			currentOpts		= selectedOpts	= {};
+
+			busy = false;
+		}
+
+		inner.css('overflow', 'hidden');
+
+		if (currentOpts.transitionOut == 'elastic') {
+			start_pos = fancybox_get_zoom_from();
+
+			var pos = wrap.position();
+
+			final_pos = {
+				top		:	pos.top ,
+				left	:	pos.left,
+				width	:	wrap.width(),
+				height	:	wrap.height()
+			};
+
+			if (currentOpts.opacity) {
+				final_pos.opacity = 1;
+			}
+
+			fx.prop = 1;
+
+			$(fx).animate({ prop: 0 }, {
+				 duration	: currentOpts.speedOut,
+				 easing		: currentOpts.easingOut,
+				 step		: fancybox_draw,
+				 complete	: _cleanup
+			});
+
+		} else {
+			wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
+		}
+	};
+
+	$.fancybox.resize = function() {
+		var c, h;
+		
+		if (busy || wrap.is(':hidden')) {
+			return;
+		}
+
+		busy = true;
+
+		c = inner.wrapInner("<div style='overflow:auto'></div>").children();
+		h = c.height();
+
+		wrap.css({height:	h + (currentOpts.padding * 2) + titleh});
+		inner.css({height:	h});
+
+		c.replaceWith(c.children());
+
+		$.fancybox.center();
+	};
+
+	$.fancybox.center = function() {
+		busy = true;
+
+		var view	= fancybox_get_viewport(),
+			margin	= currentOpts.margin,
+			to		= {};
+
+		to.top	= view[3] + ((view[1] - ((wrap.height() - titleh) + (shadow * 2 ))) * 0.5);
+		to.left	= view[2] + ((view[0] - (wrap.width() + (shadow * 2 ))) * 0.5);
+
+		to.top	= Math.max(view[3] + margin, to.top);
+		to.left	= Math.max(view[2] + margin, to.left);
+
+		wrap.css(to);
+
+		busy = false;
+	};
+
+	$.fn.fancybox.defaults = {
+		padding				:	10,
+		margin				:	20,
+		opacity				:	false,
+		modal				:	false,
+		cyclic				:	false,
+		scrolling			:	'auto',	// 'auto', 'yes' or 'no'
+
+		width				:	560,
+		height				:	340,
+
+		autoScale			:	true,
+		autoDimensions		:	true,
+		centerOnScroll		:	false,
+
+		ajax				:	{},
+		swf					:	{ wmode: 'transparent' },
+
+		hideOnOverlayClick	:	true,
+		hideOnContentClick	:	false,
+
+		overlayShow			:	true,
+		overlayOpacity		:	0.3,
+		overlayColor		:	'#666',
+
+		titleShow			:	true,
+		titlePosition		:	'outside',	// 'outside', 'inside' or 'over'
+		titleFormat			:	null,
+
+		transitionIn		:	'fade',	// 'elastic', 'fade' or 'none'
+		transitionOut		:	'fade',	// 'elastic', 'fade' or 'none'
+
+		speedIn				:	300,
+		speedOut			:	300,
+
+		changeSpeed			:	300,
+		changeFade			:	'fast',
+
+		easingIn			:	'swing',
+		easingOut			:	'swing',
+
+		showCloseButton		:	true,
+		showNavArrows		:	true,
+		enableEscapeButton	:	true,
+
+		onStart				:	null,
+		onCancel			:	null,
+		onComplete			:	null,
+		onCleanup			:	null,
+		onClosed			:	null
+	};
+
+	$(document).ready(function() {
+		fancybox_init();
+	});
+
+})(jQuery);
\ No newline at end of file
diff --git a/public/javascripts/fancybox/jquery.fancybox-1.3.1.pack.js b/public/javascripts/fancybox/jquery.fancybox-1.3.1.pack.js
new file mode 100644
index 0000000000000000000000000000000000000000..8421d53a6d1e1770e3995009feea599375909718
--- /dev/null
+++ b/public/javascripts/fancybox/jquery.fancybox-1.3.1.pack.js
@@ -0,0 +1,44 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ * 
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ *
+ * Version: 1.3.1 (05/03/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+(function(b){var m,u,x,g,D,i,z,A,B,p=0,e={},q=[],n=0,c={},j=[],E=null,s=new Image,G=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,S=/[^\.]\.(swf)\s*$/i,H,I=1,k,l,h=false,y=b.extend(b("<div/>")[0],{prop:0}),v=0,O=!b.support.opacity&&!window.XMLHttpRequest,J=function(){u.hide();s.onerror=s.onload=null;E&&E.abort();m.empty()},P=function(){b.fancybox('<p id="fancybox_error">The requested content cannot be loaded.<br />Please try again later.</p>',{scrolling:"no",padding:20,transitionIn:"none",transitionOut:"none"})},
+K=function(){return[b(window).width(),b(window).height(),b(document).scrollLeft(),b(document).scrollTop()]},T=function(){var a=K(),d={},f=c.margin,o=c.autoScale,t=(20+f)*2,w=(20+f)*2,r=c.padding*2;if(c.width.toString().indexOf("%")>-1){d.width=a[0]*parseFloat(c.width)/100-40;o=false}else d.width=c.width+r;if(c.height.toString().indexOf("%")>-1){d.height=a[1]*parseFloat(c.height)/100-40;o=false}else d.height=c.height+r;if(o&&(d.width>a[0]-t||d.height>a[1]-w))if(e.type=="image"||e.type=="swf"){t+=r;
+w+=r;o=Math.min(Math.min(a[0]-t,c.width)/c.width,Math.min(a[1]-w,c.height)/c.height);d.width=Math.round(o*(d.width-r))+r;d.height=Math.round(o*(d.height-r))+r}else{d.width=Math.min(d.width,a[0]-t);d.height=Math.min(d.height,a[1]-w)}d.top=a[3]+(a[1]-(d.height+40))*0.5;d.left=a[2]+(a[0]-(d.width+40))*0.5;if(c.autoScale===false){d.top=Math.max(a[3]+f,d.top);d.left=Math.max(a[2]+f,d.left)}return d},U=function(a){if(a&&a.length)switch(c.titlePosition){case "inside":return a;case "over":return'<span id="fancybox-title-over">'+
+a+"</span>";default:return'<span id="fancybox-title-wrap"><span id="fancybox-title-left"></span><span id="fancybox-title-main">'+a+'</span><span id="fancybox-title-right"></span></span>'}return false},V=function(){var a=c.title,d=l.width-c.padding*2,f="fancybox-title-"+c.titlePosition;b("#fancybox-title").remove();v=0;if(c.titleShow!==false){a=b.isFunction(c.titleFormat)?c.titleFormat(a,j,n,c):U(a);if(!(!a||a==="")){b('<div id="fancybox-title" class="'+f+'" />').css({width:d,paddingLeft:c.padding,
+paddingRight:c.padding}).html(a).appendTo("body");switch(c.titlePosition){case "inside":v=b("#fancybox-title").outerHeight(true)-c.padding;l.height+=v;break;case "over":b("#fancybox-title").css("bottom",c.padding);break;default:b("#fancybox-title").css("bottom",b("#fancybox-title").outerHeight(true)*-1);break}b("#fancybox-title").appendTo(D).hide()}}},W=function(){b(document).unbind("keydown.fb").bind("keydown.fb",function(a){if(a.keyCode==27&&c.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if(a.keyCode==
+37){a.preventDefault();b.fancybox.prev()}else if(a.keyCode==39){a.preventDefault();b.fancybox.next()}});if(b.fn.mousewheel){g.unbind("mousewheel.fb");j.length>1&&g.bind("mousewheel.fb",function(a,d){a.preventDefault();h||d===0||(d>0?b.fancybox.prev():b.fancybox.next())})}if(c.showNavArrows){if(c.cyclic&&j.length>1||n!==0)A.show();if(c.cyclic&&j.length>1||n!=j.length-1)B.show()}},X=function(){var a,d;if(j.length-1>n){a=j[n+1].href;if(typeof a!=="undefined"&&a.match(G)){d=new Image;d.src=a}}if(n>0){a=
+j[n-1].href;if(typeof a!=="undefined"&&a.match(G)){d=new Image;d.src=a}}},L=function(){i.css("overflow",c.scrolling=="auto"?c.type=="image"||c.type=="iframe"||c.type=="swf"?"hidden":"auto":c.scrolling=="yes"?"auto":"visible");if(!b.support.opacity){i.get(0).style.removeAttribute("filter");g.get(0).style.removeAttribute("filter")}b("#fancybox-title").show();c.hideOnContentClick&&i.one("click",b.fancybox.close);c.hideOnOverlayClick&&x.one("click",b.fancybox.close);c.showCloseButton&&z.show();W();b(window).bind("resize.fb",
+b.fancybox.center);c.centerOnScroll?b(window).bind("scroll.fb",b.fancybox.center):b(window).unbind("scroll.fb");b.isFunction(c.onComplete)&&c.onComplete(j,n,c);h=false;X()},M=function(a){var d=Math.round(k.width+(l.width-k.width)*a),f=Math.round(k.height+(l.height-k.height)*a),o=Math.round(k.top+(l.top-k.top)*a),t=Math.round(k.left+(l.left-k.left)*a);g.css({width:d+"px",height:f+"px",top:o+"px",left:t+"px"});d=Math.max(d-c.padding*2,0);f=Math.max(f-(c.padding*2+v*a),0);i.css({width:d+"px",height:f+
+"px"});if(typeof l.opacity!=="undefined")g.css("opacity",a<0.5?0.5:a)},Y=function(a){var d=a.offset();d.top+=parseFloat(a.css("paddingTop"))||0;d.left+=parseFloat(a.css("paddingLeft"))||0;d.top+=parseFloat(a.css("border-top-width"))||0;d.left+=parseFloat(a.css("border-left-width"))||0;d.width=a.width();d.height=a.height();return d},Q=function(){var a=e.orig?b(e.orig):false,d={};if(a&&a.length){a=Y(a);d={width:a.width+c.padding*2,height:a.height+c.padding*2,top:a.top-c.padding-20,left:a.left-c.padding-
+20}}else{a=K();d={width:1,height:1,top:a[3]+a[1]*0.5,left:a[2]+a[0]*0.5}}return d},N=function(){u.hide();if(g.is(":visible")&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){b.event.trigger("fancybox-cancel");h=false;return}j=q;n=p;c=e;i.get(0).scrollTop=0;i.get(0).scrollLeft=0;if(c.overlayShow){O&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});
+x.css({"background-color":c.overlayColor,opacity:c.overlayOpacity}).unbind().show()}l=T();V();if(g.is(":visible")){b(z.add(A).add(B)).hide();var a=g.position(),d;k={top:a.top,left:a.left,width:g.width(),height:g.height()};d=k.width==l.width&&k.height==l.height;i.fadeOut(c.changeFade,function(){var f=function(){i.html(m.contents()).fadeIn(c.changeFade,L)};b.event.trigger("fancybox-change");i.empty().css("overflow","hidden");if(d){i.css({top:c.padding,left:c.padding,width:Math.max(l.width-c.padding*
+2,1),height:Math.max(l.height-c.padding*2-v,1)});f()}else{i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)});y.prop=0;b(y).animate({prop:1},{duration:c.changeSpeed,easing:c.easingChange,step:M,complete:f})}})}else{g.css("opacity",1);if(c.transitionIn=="elastic"){k=Q();i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).html(m.contents());g.css(k).show();if(c.opacity)l.opacity=
+0;y.prop=0;b(y).animate({prop:1},{duration:c.speedIn,easing:c.easingIn,step:M,complete:L})}else{i.css({top:c.padding,left:c.padding,width:Math.max(l.width-c.padding*2,1),height:Math.max(l.height-c.padding*2-v,1)}).html(m.contents());g.css(l).fadeIn(c.transitionIn=="none"?0:c.speedIn,L)}}},F=function(){m.width(e.width);m.height(e.height);if(e.width=="auto")e.width=m.width();if(e.height=="auto")e.height=m.height();N()},Z=function(){h=true;e.width=s.width;e.height=s.height;b("<img />").attr({id:"fancybox-img",
+src:s.src,alt:e.title}).appendTo(m);N()},C=function(){J();var a=q[p],d,f,o,t,w;e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));o=a.title||b(a).title||e.title||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(o===""&&e.orig)o=e.orig.attr("alt");d=a.nodeName&&/^(?:javascript|#)/i.test(a.href)?e.href||null:e.href||a.href||null;if(e.type){f=e.type;if(!d)d=e.content}else if(e.content)f="html";else if(d)if(d.match(G))f=
+"image";else if(d.match(S))f="swf";else if(b(a).hasClass("iframe"))f="iframe";else if(d.match(/#/)){a=d.substr(d.indexOf("#"));f=b(a).length>0?"inline":"ajax"}else f="ajax";else f="inline";e.type=f;e.href=d;e.title=o;if(e.autoDimensions&&e.type!=="iframe"&&e.type!=="swf"){e.width="auto";e.height="auto"}if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=false;e.enableEscapeButton=false;e.showCloseButton=false}if(b.isFunction(e.onStart))if(e.onStart(q,p,e)===false){h=false;
+return}m.css("padding",20+e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(i.children())});switch(f){case "html":m.html(e.content);F();break;case "inline":b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(i.children())}).bind("fancybox-cancel",function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();
+s=new Image;s.onerror=function(){P()};s.onload=function(){s.onerror=null;s.onload=null;Z()};s.src=d;break;case "swf":t='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+d+'"></param>';w="";b.each(e.swf,function(r,R){t+='<param name="'+r+'" value="'+R+'"></param>';w+=" "+r+'="'+R+'"'});t+='<embed src="'+d+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+w+"></embed></object>";m.html(t);
+F();break;case "ajax":a=d.split("#",2);f=e.ajax.data||{};if(a.length>1){d=a[0];if(typeof f=="string")f+="&selector="+a[1];else f.selector=a[1]}h=false;b.fancybox.showActivity();E=b.ajax(b.extend(e.ajax,{url:d,data:f,error:P,success:function(r){if(E.status==200){m.html(r);F()}}}));break;case "iframe":b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" scrolling="'+e.scrolling+'" src="'+e.href+'"></iframe>').appendTo(m);N();break}},$=function(){if(u.is(":visible")){b("div",
+u).css("top",I*-40+"px");I=(I+1)%12}else clearInterval(H)},aa=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),u=b('<div id="fancybox-loading"><div></div></div>'),x=b('<div id="fancybox-overlay"></div>'),g=b('<div id="fancybox-wrap"></div>'));if(!b.support.opacity){g.addClass("fancybox-ie");u.addClass("fancybox-ie")}D=b('<div id="fancybox-outer"></div>').append('<div class="fancy-bg" id="fancy-bg-n"></div><div class="fancy-bg" id="fancy-bg-ne"></div><div class="fancy-bg" id="fancy-bg-e"></div><div class="fancy-bg" id="fancy-bg-se"></div><div class="fancy-bg" id="fancy-bg-s"></div><div class="fancy-bg" id="fancy-bg-sw"></div><div class="fancy-bg" id="fancy-bg-w"></div><div class="fancy-bg" id="fancy-bg-nw"></div>').appendTo(g);
+D.append(i=b('<div id="fancybox-inner"></div>'),z=b('<a id="fancybox-close"></a>'),A=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),B=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));z.click(b.fancybox.close);u.click(b.fancybox.cancel);A.click(function(a){a.preventDefault();b.fancybox.prev()});B.click(function(a){a.preventDefault();b.fancybox.next()});if(O){x.get(0).style.setExpression("height",
+"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'");u.get(0).style.setExpression("top","(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'");D.prepend('<iframe id="fancybox-hide-sel-frame" src="javascript:\'\';" scrolling="no" frameborder="0" ></iframe>')}}};
+b.fn.fancybox=function(a){b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(d){d.preventDefault();if(!h){h=true;b(this).blur();q=[];p=0;d=b(this).attr("rel")||"";if(!d||d==""||d==="nofollow")q.push(this);else{q=b("a[rel="+d+"], area[rel="+d+"]");p=q.index(this)}C();return false}});return this};b.fancybox=function(a,d){if(!h){h=true;d=typeof d!=="undefined"?d:{};q=[];p=d.index||0;if(b.isArray(a)){for(var f=0,o=a.length;f<o;f++)if(typeof a[f]==
+"object")b(a[f]).data("fancybox",b.extend({},d,a[f]));else a[f]=b({}).data("fancybox",b.extend({content:a[f]},d));q=jQuery.merge(q,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},d,a));else a=b({}).data("fancybox",b.extend({content:a},d));q.push(a)}if(p>q.length||p<0)p=0;C()}};b.fancybox.showActivity=function(){clearInterval(H);u.show();H=setInterval($,66)};b.fancybox.hideActivity=function(){u.hide()};b.fancybox.next=function(){return b.fancybox.pos(n+1)};b.fancybox.prev=function(){return b.fancybox.pos(n-
+1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a,10);if(a>-1&&j.length>a){p=a;C()}if(c.cyclic&&j.length>1&&a<0){p=j.length-1;C()}if(c.cyclic&&j.length>1&&a>=j.length){p=0;C()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");J();e&&b.isFunction(e.onCancel)&&e.onCancel(q,p,e);h=false}};b.fancybox.close=function(){function a(){x.fadeOut("fast");g.hide();b.event.trigger("fancybox-cleanup");i.empty();b.isFunction(c.onClosed)&&c.onClosed(j,n,c);j=e=[];n=p=0;c=e={};h=false}
+if(!(h||g.is(":hidden"))){h=true;if(c&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){h=false;return}J();b(z.add(A).add(B)).hide();b("#fancybox-title").remove();g.add(i).add(x).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");i.css("overflow","hidden");if(c.transitionOut=="elastic"){k=Q();var d=g.position();l={top:d.top,left:d.left,width:g.width(),height:g.height()};if(c.opacity)l.opacity=1;y.prop=1;b(y).animate({prop:0},{duration:c.speedOut,easing:c.easingOut,
+step:M,complete:a})}else g.fadeOut(c.transitionOut=="none"?0:c.speedOut,a)}};b.fancybox.resize=function(){var a,d;if(!(h||g.is(":hidden"))){h=true;a=i.wrapInner("<div style='overflow:auto'></div>").children();d=a.height();g.css({height:d+c.padding*2+v});i.css({height:d});a.replaceWith(a.children());b.fancybox.center()}};b.fancybox.center=function(){h=true;var a=K(),d=c.margin,f={};f.top=a[3]+(a[1]-(g.height()-v+40))*0.5;f.left=a[2]+(a[0]-(g.width()+40))*0.5;f.top=Math.max(a[3]+d,f.top);f.left=Math.max(a[2]+
+d,f.left);g.css(f);h=false};b.fn.fancybox.defaults={padding:10,margin:20,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.3,overlayColor:"#666",titleShow:true,titlePosition:"outside",titleFormat:null,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",
+easingIn:"swing",easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,onStart:null,onCancel:null,onComplete:null,onCleanup:null,onClosed:null};b(document).ready(function(){aa()})})(jQuery);
\ No newline at end of file
diff --git a/public/javascripts/fancybox/jquery.mousewheel-3.0.2.pack.js b/public/javascripts/fancybox/jquery.mousewheel-3.0.2.pack.js
new file mode 100644
index 0000000000000000000000000000000000000000..b950db1a20304f828afb2bc025358ff4760b51d9
--- /dev/null
+++ b/public/javascripts/fancybox/jquery.mousewheel-3.0.2.pack.js
@@ -0,0 +1,13 @@
+/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ *
+ * Version: 3.0.2
+ * 
+ * Requires: 1.2.2+
+ */
+
+(function(b){function d(a){var f=[].slice.call(arguments,1),e=0;a=b.event.fix(a||window.event);a.type="mousewheel";if(a.wheelDelta)e=a.wheelDelta/120;if(a.detail)e=-a.detail/3;f.unshift(a,e);return b.event.handle.apply(this,f)}var c=["DOMMouseScroll","mousewheel"];b.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],d,false);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],
+d,false);else this.onmousewheel=null}};b.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
\ No newline at end of file
diff --git a/public/javascripts/group_nav.js b/public/javascripts/group_nav.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3d9600bb3550a0b191647c2036cf3b86bf8eb2e
--- /dev/null
+++ b/public/javascripts/group_nav.js
@@ -0,0 +1,16 @@
+$(document).ready( function() {
+
+  var vars = [], hash;
+  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
+  for(var i = 0; i < hashes.length; i++)
+  {
+      hash = hashes[i].split('=');
+      vars.push(hash[0]);
+      vars[hash[0]] = hash[1];
+  }
+
+  $("."+vars['g']).addClass('selected');
+
+  $("#group img").load(function(){$(this).fadeIn("slow");});
+  
+});
diff --git a/public/javascripts/publisher.js b/public/javascripts/publisher.js
index f8e0f369dc1c72a3045ceb6093841639b63ff2b1..28d902098d14d2b132dea0a45299be78e9d2b291 100644
--- a/public/javascripts/publisher.js
+++ b/public/javascripts/publisher.js
@@ -1,24 +1,20 @@
-  $(document).ready( function() {
+$(document).ready( function() {
 
-    $("#publisher_content_pickers .status_message").click(selectPublisherTab);
-    $("#publisher_content_pickers .bookmark").click(selectPublisherTab);
-    $("#publisher_content_pickers .blog").click(selectPublisherTab);
-    $("#publisher_content_pickers .photo").click(selectPublisherTab);
-	
-	$("#new_status_message").submit(function() {
-		
-	});
+  $("#publisher_content_pickers .status_message").click(selectPublisherTab);
+  $("#publisher_content_pickers .bookmark").click(selectPublisherTab);
+  $("#publisher_content_pickers .blog").click(selectPublisherTab);
+  $("#publisher_content_pickers .photo").click(selectPublisherTab);
 
-    function selectPublisherTab(evt){
-      evt.preventDefault();
-      var form_id = "#new_" + this.className
-      if( $(form_id).css("display") == "none" ) {
-        $("#publisher_content_pickers").children("li").removeClass("selected");
-        $("#publisher_form form").fadeOut(50);
+  function selectPublisherTab(evt){
+    evt.preventDefault();
+    var form_id = "#new_" + this.className
+    if( $(form_id).css("display") == "none" ) {
+      $("#publisher_content_pickers").children("li").removeClass("selected");
+      $("#publisher_form form").fadeOut(50);
 
-        $(this).toggleClass("selected");
-        $(form_id).delay(50).fadeIn(200);
-      }
+      $(this).toggleClass("selected");
+      $(form_id).delay(50).fadeIn(200);
     }
+  }
 
-  });
+});
diff --git a/public/javascripts/view.js b/public/javascripts/view.js
index 5da7a9f9e6bb8ef3a6be76d8f59c00bade700bf9..6648c171480d2f08e0b2cd88e7bb281e710353a2 100644
--- a/public/javascripts/view.js
+++ b/public/javascripts/view.js
@@ -21,15 +21,7 @@ $(document).ready(function(){
 			var show_comments_toggle = $(this).parent().prev().children(".show_post_comments");
 			show_comments_toggle.html("hide comments ("+ ($(this).children().length - 1) + ")");
 		};
-	  });
-
-	$('a').hover(function(){
-    if( $(this).children("img").length < 1 )
-      $(this).fadeTo(60, 0.5);
-	}, function(){
-    if( $(this).children("img").length < 1 )
-      $(this).fadeTo(80, 1);
-	});
+  });
 
 	$('#debug_info').click(function() {
 		$('#debug_more').toggle('fast', function() {
@@ -89,21 +81,14 @@ $(document).ready(function(){
   });
 
   //buttons//////
-  $("#add_photos_button").toggle(
-    function(){
-      $("#add_photo_box").fadeIn(300);
-    },function(){
-      $("#add_photo_box").fadeOut(200);
-    }
-  );
+  
 
-  $("#add_album_button").toggle(
-    function(){
-      $("#add_album_box").fadeIn(300);
-    },function(){
-      $("#add_album_box").fadeOut(200);
-    }
-  );
+  $("#add_album_button").fancybox();
+  $("#add_group_button").fancybox();
+  $("#add_request_button").fancybox();
+  $("#add_photo_button").fancybox();
+
+  //pane_toggler_button("photo");
 
   $("input[type='submit']").addClass("button");
 
@@ -115,5 +100,22 @@ $(document).ready(function(){
     $(this).fadeIn("slow");
   });
 
+  $(".delete").hover(function(){
+    $(this).toggleClass("button");
+  });
 
 });//end document ready
+
+
+function pane_toggler_button( name ) {
+  
+    $("#add_" + name + "_button").toggle(
+    function(evt){
+      evt.preventDefault();
+      $("#add_" + name + "_pane").fadeIn(300);
+    },function(evt){
+      evt.preventDefault();
+      $("#add_" + name +"_pane").fadeOut(200);
+    }
+  );
+}
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 9335a088faac8923f566dec4cfb062f274bf79e4..0d8edc7da480790048d55942cb24734dae2514e5 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -12,10 +12,12 @@ body {
 
 a {
   color: #018790;
-  text-decoration: none;
-  font-weight: bold; }
+  color: #556270;
+  text-decoration: none; }
   a:hover {
-    color: #018790; }
+    color: white;
+    background-color: #018790;
+    background-color: #556270; }
 
 #flash_notice,
 #flash_error,
@@ -64,34 +66,30 @@ a {
 header {
   position: relative;
   margin: -2em;
-    margin-bottom: 30px;
+    margin-bottom: 20px;
   color: #555555;
   background-color: #2b2726;
+  background-color: black;
   border-bottom: 3px solid #333333;
   padding: 6px 0;
     padding-top: 0; }
   header #diaspora_text {
+    margin-bottom: 1em;
     font-family: "BrandonGrotesqueLightRegular";
-    font-size: 24px;
-    position: absolute;
+    font-size: 16px;
     border: none;
     color: white;
     text-shadow: 0 2px 0 black; }
     header #diaspora_text a {
       color: #666666; }
     header #diaspora_text span.sub_text {
-      color: black;
       text-shadow: none; }
   header #session_action {
     float: right;
-    margin-top: 9px;
     text-shadow: 0 1px 0 black;
     padding-right: 10px; }
-    header #session_action a {
-      color: #777777;
-      border: none; }
-      header #session_action a.new_requests {
-        color: #df0101; }
+    header #session_action a.new_requests {
+      color: #df0101; }
 
 #show_filters {
   z-index: 100;
@@ -108,13 +106,12 @@ header {
 
 ul#stream, ul#friend_stream {
   margin: 0;
-  padding: 0;
-  color: #666666; }
+  padding: 0; }
   ul#stream > li, ul#friend_stream > li {
     list-style: none;
     padding: 15px 0;
-    border-bottom: 1px solid #f1f1f1;
-    margin-bottom: 5px; }
+    margin-bottom: 5px;
+    border-bottom: 1px solid #eeeeee; }
 
 ul#friend_stream > li {
   padding: 0.2em 0; }
@@ -144,10 +141,9 @@ h1 {
   font-size: 21px;
   font-weight: bold;
   line-height: 36px; }
-  h1 p.description, h1 span.description {
+  h1 p.description, h1 span.description, h1 .description {
     font-weight: 200;
-    color: #999999;
-    padding: 0.1em; }
+    color: #999999; }
 
 h3 {
   position: relativex;
@@ -155,9 +151,10 @@ h3 {
   font-weight: bold; }
 
 form {
+  position: relative;
   font-size: 120%;
   margin: 1em;
-  margin-left: 0em; }
+    margin-left: 0em; }
 
 #user_name {
   margin-bottom: 20px; }
@@ -300,7 +297,8 @@ label {
   color: #999999;
   position: absolute;
   top: 3px;
-  left: 0.48em; }
+  left: 0.48em;
+  font-weight: normal; }
 
 #publisher {
   background-color: rgba(10, 81, 109, 0.05);
@@ -350,12 +348,12 @@ ul#publisher_content_pickers li {
 /* cycle it! */
 .album {
   position: relative;
-  height: 200px;
+  height: 300px;
   width: 300px;
   display: inline-block; }
   .album .name {
     position: absolute;
-    z-index: 600;
+    z-index: 6;
     padding: 1em;
     background: rgba(0, 0, 0, 0.8);
     bottom: 20px;
@@ -375,17 +373,20 @@ ul#publisher_content_pickers li {
 h1.big_text {
   position: relative;
   line-height: auto;
-  border-top: 2px solid #666666;
-  border-bottom: 1px solid #666666;
-  text-align: center; }
+  border-bottom: 1px solid #666666; }
+  h1.big_text .right {
+    top: -6px; }
+
+#content_bottom .right {
+  top: -5px; }
 
 .right {
-  float: right;
-  margin-top: 6px; }
+  display: inline;
+  float: right; }
 
 .back {
-  position: absolute;
-  font-size: 12px; }
+  font-size: 12px;
+  font-weight: normal; }
 
 #content_bottom {
   position: relative;
@@ -400,15 +401,12 @@ h1.big_text {
   width: 100%; }
 
 .sub_header {
+  position: relative;
   text-align: center;
   font-style: italic;
-  margin-top: -5px;
   margin-bottom: 20px;
   color: #999999; }
 
-#next_prev_links {
-  text-align: center; }
-
 .image_thumb {
   display: inline-block;
   width: 100px;
@@ -417,8 +415,58 @@ h1.big_text {
   min-height: 100px; }
   .image_thumb img {
     display: none; }
-    .image_thumb img:hover {
-      border-bottom: 2px solid #666666; }
 
 .image_cycle img {
   display: none; }
+
+#group {
+  color: #333333; }
+  #group ul {
+    margin: 0;
+    padding: 0;
+    font-size: 14px; }
+    #group ul > li {
+      display: inline;
+      margin-right: 10px; }
+      #group ul > li.selected, #group ul > li.selected a {
+        color: white;
+        font-weight: bold;
+        font-size: 18px; }
+  #group a {
+    color: #333333;
+    font-weight: normal; }
+  #group #friend_pictures .add_new {
+    position: relative;
+    display: inline-block;
+    height: 40px;
+    width: 40px;
+    background-color: #222222;
+    text-align: center;
+    font-size: 40px;
+    line-height: 33px;
+    top: -9px; }
+    #group #friend_pictures .add_new:hover {
+      background: #999999;
+      color: black; }
+  #group #friend_pictures img {
+    display: none;
+    height: 40px; }
+
+#add_photo_loader {
+  position: absolute;
+  display: none;
+  left: -25px;
+  top: 4px; }
+
+#user_menu {
+  background: #333333;
+  padding: 5px;
+  margin: 0;
+  list-style: none; }
+  #user_menu a {
+    color: #999999; }
+  #user_menu > li {
+    display: inline;
+    margin-right: 1em; }
+    #user_menu > li:last-child {
+      margin-right: 0; }
diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass
index 0225b383a0da8b0cb3e51335545f2d27b5b3a4d9..9ef450368b97eafd1223f1ee14d260569a4d752c 100644
--- a/public/stylesheets/sass/application.sass
+++ b/public/stylesheets/sass/application.sass
@@ -11,12 +11,14 @@ body
   :margin 0
 a
   :color #018790
+  :color #556270
   :text
     :decoration none
-  :font-weight bold
   &:hover
-    :color #018790
-
+    :color #fff
+    :background
+      :color #018790
+      :color #556270
 
 #flash_notice,
 #flash_error,
@@ -68,20 +70,22 @@ a
 header
   :position relative
   :margin -2em
-    :bottom 30px
+    :bottom 20px
   :color #555
   :background
     :color #2B2726
+    :color #000
   :border
     :bottom 3px solid #333
   :padding 6px 0
     :top 0
 
   #diaspora_text
+    :margin
+      :bottom 1em
     :font
       :family 'BrandonGrotesqueLightRegular'
-      :size 24px
-    :position absolute
+      :size 16px
     :border none
     :color #fff
     :text
@@ -90,18 +94,13 @@ header
       :color #666
 
     span.sub_text
-      :color #000
       :text
         :shadow none
       
   #session_action
     :float right
-    :margin
-      :top 9px
     :text-shadow 0 1px 0 #000
     a
-      :color #777
-      :border none
       &.new_requests
         :color #DF0101
     :padding-right 10px
@@ -121,13 +120,12 @@ header
 ul#stream, ul#friend_stream
   :margin 0
   :padding 0
-  :color #666
   > li
     :list-style none
     :padding 15px 0
-    :border
-      :bottom 1px solid #f1f1f1
     :margin-bottom 5px
+    :border
+      :bottom 1px solid #eee
 
 ul#friend_stream
   > li
@@ -168,11 +166,10 @@ h1
     :weight bold
   :line-height 36px
 
-  p.description, span.description
+  p.description, span.description, .description
     :font
       :weight 200
     :color #999
-    :padding 0.1em
 
 h3
   :position relativex
@@ -181,11 +178,11 @@ h3
     :weight bold
 
 form
+  :position relative
   :font
     :size 120%
   :margin 1em
-  :margin-left 0em
-
+    :left 0em
   
 #user_name
   :margin
@@ -366,6 +363,8 @@ label
   :position absolute
   :top 3px
   :left 0.48em
+  :font
+    :weight normal
 
 #publisher
   :background
@@ -430,13 +429,13 @@ ul#publisher_content_pickers li
 
 .album
   :position relative
-  :height 200px
+  :height 300px
   :width 300px
   :display inline-block
 
   .name
     :position absolute
-    :z-index 600
+    :z-index 6 
     :padding 1em
     :background rgba(0,0,0,0.8)
     :bottom 20px
@@ -465,20 +464,23 @@ h1.big_text
   :position relative
   :line-height auto
   :border
-    :top 2px solid #666
     :bottom 1px solid #666
-  :text
-    :align center
+
+  .right
+    :top -6px
+
+#content_bottom
+  .right
+    :top -5px
 
 .right
+  :display inline
   :float right
-  :margin
-    :top 6px
 
 .back
-  :position absolute
   :font
     :size 12px
+    :weight normal
 
 #content_bottom
   :position relative
@@ -498,19 +500,15 @@ h1.big_text
   :width 100%
 
 .sub_header
+  :position relative
   :text
     :align center
   :font
     :style italic
   :margin
-    :top -5px
     :bottom 20px
   :color #999
 
-#next_prev_links
-  :text-align center
-
-
 .image_thumb
   :display inline-block
   :width 100px
@@ -521,10 +519,76 @@ h1.big_text
   img
     :display none
 
-    &:hover
-      :border
-        :bottom 2px solid #666
-
 .image_cycle
   img
     :display none
+
+#group
+  :color #333
+  ul
+    :margin 0
+    :padding 0
+    :font
+      :size 14px
+    > li
+      :display inline
+      :margin
+        :right 10px
+      
+      &.selected, &.selected a
+        :color #fff
+        :font
+          :weight bold
+          :size 18px
+
+  a
+    :color #333
+    :font
+      :weight normal
+
+  #friend_pictures
+    .add_new
+      :position relative
+      :display inline-block
+      :height 40px
+      :width 40px
+      :background
+        :color #222
+      :text-align center
+      :font-size 40px
+      :line-height 33px
+      :top -9px
+
+      &:hover
+        :background #999
+        :color #000
+
+    img
+      :display none
+      :height 40px
+
+#add_photo_loader
+  :position absolute
+  :display none
+  :left -25px
+  :top 4px
+
+#user_menu
+  :background #333
+  :padding 5px 
+  :margin 0
+  :list-style none
+
+  a
+    :color #999
+
+  > li
+    :display inline
+    :margin
+      :right 1em
+
+    &:last-child
+      :margin
+        :right 0
+
+
diff --git a/public/stylesheets/sass/ui.sass b/public/stylesheets/sass/ui.sass
index 50000a8d3b27af930231adce67ce8d766d80699e..ee01e08bc5d203f09d6408725eaa4b3a9ccca153 100644
--- a/public/stylesheets/sass/ui.sass
+++ b/public/stylesheets/sass/ui.sass
@@ -5,21 +5,22 @@
 
   :display inline
 
-  :color #777
+  :padding 4px
+
   :font-size 12px
   :line-height 100%
 
   :text-shadow 0 1px 0 #fff
 
-  :min-height 14px
+  :min-height 10px
 
-  :background -webkit-gradient(linear, 0% 29%, 0% 85%, from(#FAFAFA), to(#E0E0E0))
-  :background -moz-linear-gradient(top, #FAFAFA, #E0E0E0)
+  :background -webkit-gradient(linear, 0% 29%, 0% 85%, from(#FCFCFC), to(#F6F6F6))
+  :background -moz-linear-gradient(top, #FCFCFC, #F6F6F6)
 
-  :border 1px solid #ccc
-    :bottom 1px solid #666
-    :left 1px solid #999
-    :right 1px solid #999
+  :border 1px solid #EEE
+    :bottom 1px solid #999
+    :left 1px solid #ccc
+    :right 1px solid #ccc
 
   :border-radius 3px
   :-moz-border-radius 3px
@@ -27,28 +28,32 @@
 
   :cursor pointer
 
+  :box-shadow 0 1px 1px #eee
+  :-webkit-box-shadow 0 1px 1px #eee
+  :-moz-box-shadow 0 1px 1px #eee
 
-  :box-shadow 0 1px 1px #ccc
-  :-webkit-box-shadow 0 1px 1px #ccc
-  :-moz-box-shadow 0 1px 1px #ccc
-
-  a
-    :font-weight normal
-    :color #777
+  :font-weight normal
 
+  :color #666
 
-.button
-  :padding 5px
+  &:hover
+    :color #666
+    :background -webkit-gradient(linear, 0% 29%, 0% 85%, from(#FAFAFA), to(#F0F0F0))
+    :background -moz-linear-gradient(top, #FAFAFA, #F0F0F0)
 
   &:active
-    :box-shadow 0 0px 2px #000
-    :-webkit-box-shadow 0 0px 2px #000
-    :-moz-box-shadow 0 0px 2px #000
-    :color #555
+    :color #666
+    :background -webkit-gradient(linear, 0% 29%, 0% 85%, from(#F0F0F0), to(#FAFAFA))
+    :background -moz-linear-gradient(top, #F0F0F0, #FAFAFA)
+    :border
+      :top 1px solid #ccc
+
 
 ul.button_set
 
-  :padding 5px 0
+  :padding
+    :left 0
+    :right 0
 
   > li
     :padding 5px
@@ -75,8 +80,8 @@ ul.button_set
         :right none
 
 .button .selected, .button_set .selected
-  :background -webkit-gradient(linear, 0% 29%, 0% 85%, from(#E0E0E0), to(#FAFAFA))
-  :background -moz-linear-gradient(top, #e0e0e0, #fafafa)
+  :background -webkit-gradient(linear, 0% 29%, 0% 85%, from(#F0F0F0), to(#FAFAFA))
+  :background -moz-linear-gradient(top, #F0F0F0, #fafafa)
 
   :border
     :top 1px solid #aaa
@@ -94,33 +99,17 @@ ul.button_set
 
   :display none
 
-  :right 0
   :background
-    :color rgba( 30,30,30,0.95 )
+    :color #fff
 
-  :border 2px solid #999
+  :border 4px solid #000
 
-  :border-radius 5px
-  :-moz-border-radius 5px
-  :-webkit-border-radius 5px
+  :border-radius 3px
+  :-moz-border-radius 3px
+  :-webkit-border-radius 3px
 
-  :color #999
+  :box-shadow 0 0 5px #000
+  :-webkit-box-shadow 0 0 10px #000
+
+  :padding 2em
 
-  :font
-    :size 12px
-    :weight normal
-
-  :line-height auto
-
-  form
-    :margin 0
-    :padding 10px
-    :color #999
-    
-    input[type='text']
-      :width 80%
-      :display block
-
-    p
-      :padding 10px
-      :display inline
diff --git a/public/stylesheets/ui.css b/public/stylesheets/ui.css
index 63c8dc0cccd78c40ce087a1282e4c92e2e44f3f7..dd791bafb2974a21fc21fcd4d28520e50977235c 100644
--- a/public/stylesheets/ui.css
+++ b/public/stylesheets/ui.css
@@ -2,38 +2,39 @@
   font-family: "Lucida Grande", sans-serif;
   font-style: normal;
   display: inline;
-  color: #777777;
+  padding: 4px;
   font-size: 12px;
   line-height: 100%;
   text-shadow: 0 1px 0 white;
-  min-height: 14px;
-  background: -webkit-gradient(linear, 0% 29%, 0% 85%, from(#fafafa), to(#e0e0e0));
-  background: -moz-linear-gradient(top, #fafafa, #e0e0e0);
-  border: 1px solid #cccccc;
-    border-bottom: 1px solid #666666;
-    border-left: 1px solid #999999;
-    border-right: 1px solid #999999;
+  min-height: 10px;
+  background: -webkit-gradient(linear, 0% 29%, 0% 85%, from(#fcfcfc), to(#f6f6f6));
+  background: -moz-linear-gradient(top, #fcfcfc, #f6f6f6);
+  border: 1px solid #eeeeee;
+    border-bottom: 1px solid #999999;
+    border-left: 1px solid #cccccc;
+    border-right: 1px solid #cccccc;
   border-radius: 3px;
   -moz-border-radius: 3px;
   -webkit-border-radius: 3px;
   cursor: pointer;
-  box-shadow: 0 1px 1px #cccccc;
-  -webkit-box-shadow: 0 1px 1px #cccccc;
-  -moz-box-shadow: 0 1px 1px #cccccc; }
-  .button a, .button_set a {
-    font-weight: normal;
-    color: #777777; }
-
-.button {
-  padding: 5px; }
-  .button:active {
-    box-shadow: 0 0px 2px black;
-    -webkit-box-shadow: 0 0px 2px black;
-    -moz-box-shadow: 0 0px 2px black;
-    color: #555555; }
+  box-shadow: 0 1px 1px #eeeeee;
+  -webkit-box-shadow: 0 1px 1px #eeeeee;
+  -moz-box-shadow: 0 1px 1px #eeeeee;
+  font-weight: normal;
+  color: #666666; }
+  .button:hover, .button_set:hover {
+    color: #666666;
+    background: -webkit-gradient(linear, 0% 29%, 0% 85%, from(#fafafa), to(#f0f0f0));
+    background: -moz-linear-gradient(top, #fafafa, #f0f0f0); }
+  .button:active, .button_set:active {
+    color: #666666;
+    background: -webkit-gradient(linear, 0% 29%, 0% 85%, from(#f0f0f0), to(#fafafa));
+    background: -moz-linear-gradient(top, #f0f0f0, #fafafa);
+    border-top: 1px solid #cccccc; }
 
 ul.button_set {
-  padding: 5px 0; }
+  padding-left: 0;
+  padding-right: 0; }
   ul.button_set > li {
     padding: 5px;
     display: inline;
@@ -50,8 +51,8 @@ ul.button_set {
       border-right: none; }
 
 .button .selected, .button_set .selected {
-  background: -webkit-gradient(linear, 0% 29%, 0% 85%, from(#e0e0e0), to(#fafafa));
-  background: -moz-linear-gradient(top, #e0e0e0, #fafafa);
+  background: -webkit-gradient(linear, 0% 29%, 0% 85%, from(#f0f0f0), to(#fafafa));
+  background: -moz-linear-gradient(top, #f0f0f0, #fafafa);
   border-top: 1px solid #aaaaaa; }
 
 .right {
@@ -63,23 +64,11 @@ ul.button_set {
   z-index: 20;
   position: absolute;
   display: none;
-  right: 0;
-  background-color: rgba(30, 30, 30, 0.95);
-  border: 2px solid #999999;
-  border-radius: 5px;
-  -moz-border-radius: 5px;
-  -webkit-border-radius: 5px;
-  color: #999999;
-  font-size: 12px;
-  font-weight: normal;
-  line-height: auto; }
-  .contextual_pane form {
-    margin: 0;
-    padding: 10px;
-    color: #999999; }
-    .contextual_pane form input[type='text'] {
-      width: 80%;
-      display: block; }
-    .contextual_pane form p {
-      padding: 10px;
-      display: inline; }
+  background-color: white;
+  border: 4px solid black;
+  border-radius: 3px;
+  -moz-border-radius: 3px;
+  -webkit-border-radius: 3px;
+  box-shadow: 0 0 5px black;
+  -webkit-box-shadow: 0 0 10px black;
+  padding: 2em; }
diff --git a/spec/controllers/dashboards_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
similarity index 65%
rename from spec/controllers/dashboards_controller_spec.rb
rename to spec/controllers/groups_controller_spec.rb
index b05603fb613dd21abe799870d3b25cbf69aa476f..6bfce5434d36baa8dac2feb6d79ccf0d438fec7c 100644
--- a/spec/controllers/dashboards_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -1,9 +1,11 @@
 require File.dirname(__FILE__) + '/../spec_helper'
- 
-describe DashboardsController do
+include ApplicationHelper 
+describe GroupsController do
  render_views
   before do
-    @user = Factory.create(:user, :profile => Profile.new( :first_name => "bob", :last_name => "smith"))
+    @user = Factory.create(:user)
+    @user.person.save
+    @person = Factory.create(:person)
     request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user)
   end
 
@@ -11,7 +13,7 @@ describe DashboardsController do
     sign_in :user, @user   
     Factory.create :person
     get :index
-    assigns[:friends].should == Person.friends.all
+    assigns[:friends].should == @user.friends
   end
 
 end
diff --git a/spec/controllers/publics_controller_spec.rb b/spec/controllers/publics_controller_spec.rb
index 132210e6673735c728b3ff67744071fb8562ffbb..8ef2a30c866366661eb30937027ff0d4784f9f46 100644
--- a/spec/controllers/publics_controller_spec.rb
+++ b/spec/controllers/publics_controller_spec.rb
@@ -4,20 +4,59 @@ describe PublicsController do
  render_views
   
   before do
-    @user = Factory.create(:user, :profile => Profile.new( :first_name => "bob", :last_name => "smith"))
+    @user = Factory.create(:user)
+    @user.person.save
     request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user)
   end
 
   describe 'receive endpoint' do
-
-    it 'should accept a post from anohter node and save the information' do
-      
+    it 'should have a and endpoint and return a 200 on successful receipt of a request' do
+      post :receive, :id =>@user.person.id
+      response.code.should == '200'
+    end
+    
+    it 'should accept a post from another node and save the information' do
+      pending
       person = Factory.create(:person)
       message = StatusMessage.new(:message => 'foo', :person => person)
-      StatusMessage.all.count.should == 0
-      post :receive, {:xml => Post.build_xml_for(message)}
-      StatusMessage.all.count.should == 1
+      StatusMessage.all.count.should be 0
+      post :receive, :id => @user.person.id, :xml => message.to_diaspora_xml(message)
+      StatusMessage.all.count.should be 1
     end
   end
 
+
+  describe 'friend requests' do
+    before do
+      @user2 = Factory.create(:user)
+      @user2.person.save
+      group = @user2.group(:name => 'disciples')
+
+      @user3 = Factory.create(:user)
+      @user3.person.save
+
+      req = @user2.send_friend_request_to(@user.person.url, group.id)
+
+      @xml = req.to_diaspora_xml
+  
+      req.delete
+      @user2.reload
+      @user2.pending_requests.count.should be 1
+    end
+
+    it 'should add the pending request to the right user if the target person exists locally' do 
+      @user2.delete
+      post :receive, :id => @user.person.id, :xml => @xml
+      
+      assigns(:user).should eq(@user)
+    end
+
+    it 'should add the pending request to the right user if the target person does not exist locally' do 
+      @user2.person.delete
+      @user2.delete
+      post :receive, :id => @user.person.id, :xml => @xml
+
+      assigns(:user).should eq(@user)
+    end
+  end
 end
diff --git a/spec/controllers/sockets_controller_spec.rb b/spec/controllers/sockets_controller_spec.rb
index a5109e356b6096aa4f4090d6b13c75a2e0082bdf..19673cb243b96784afafb31a74701eaf25c18f47 100644
--- a/spec/controllers/sockets_controller_spec.rb
+++ b/spec/controllers/sockets_controller_spec.rb
@@ -7,32 +7,36 @@ describe 'SocketsController' do
     SocketsController.unstub!(:new)
     #EventMachine::WebSocket.stub!(:start)
     @controller = SocketsController.new
+    @controller.request = mock_model(Request, :env =>
+      {'warden' => mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user)})
     stub_sockets_controller
   end
 
   it 'should unstub the websockets' do
-      WebSocket.initialize_channel
+      WebSocket.initialize_channels
       @controller.class.should == SocketsController
   end
   
-  it 'should add a new subscriber to the websockets channel' do
-      WebSocket.initialize_channel
-      @controller.new_subscriber.should == 1
-  end
   describe 'actionhash' do
     before do
-      @message = Factory.create(:status_message, :person => @user)
+      @message = @user.post :status_message, :message => "post through user for victory"
     end
 
     it 'should actionhash posts' do
-      json = @controller.action_hash(@message)
+      class SocketsController
+        def url_options
+          {:host => ""}
+        end
+      end
+
+      json = @controller.action_hash(@user.id, @message)
       json.include?(@message.message).should be_true
       json.include?('status_message').should be_true
     end
 
     it 'should actionhash retractions' do
       retraction = Retraction.for @message
-      json = @controller.action_hash(retraction)
+      json = @controller.action_hash(@user.id, retraction)
       json.include?('retraction').should be_true
       json.include?("html\":null").should be_true
     end
diff --git a/spec/factories.rb b/spec/factories.rb
index bd098ec7c5f9ec3797f8fe500f880eaa1cbe436f..88f34e1f691794568f7a50472cbd715fdd6b1481 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -9,25 +9,27 @@ Factory.define :profile do |p|
 end
 
 Factory.define :person do |p|
-  p.email "bob-person@aol.com"
-  p.active true
-  p.sequence(:url)  {|n|"http://google-#{n}.com/"}
+  p.sequence(:email) {|n| "bob-person-#{n}@aol.com"}
+  p.sequence(:url)  {|n| "http://google-#{n}.com/"}
+  p.profile Factory.create(:profile)
+
   p.serialized_key OpenSSL::PKey::RSA.generate(1024).public_key.export
-  p.profile Profile.new( :first_name => "Robert", :last_name => "Grimm" )
 end
 
 Factory.define :person_with_private_key, :parent => :person do |p|
   p.serialized_key OpenSSL::PKey::RSA.generate(1024).export
 end
 
+Factory.define :person_with_user, :parent => :person_with_private_key do |p|
+end
+
 Factory.define :user do |u|
   u.sequence(:email) {|n| "bob#{n}@aol.com"}
   u.password "bluepin7"
   u.password_confirmation "bluepin7"
-  u.url  "www.example.com/"
-  u.serialized_key OpenSSL::PKey::RSA::generate(1024).export 
-  u.profile Profile.new( :first_name => "Bob", :last_name => "Smith" )
+  u.person { |a| Factory.create(:person_with_user, :owner_id => a._id)} 
 end
+
 Factory.define :status_message do |m|
   m.sequence(:message) {|n| "jimmy's #{n} whales"}
   m.person
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index f4785626515364ee476bebbd57377aa66e4bce82..bb886bd8341b7a22e8311aa38b2ea61f630bd998 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -1,22 +1,12 @@
 require File.dirname(__FILE__) + '/../spec_helper'
 
 include ApplicationHelper 
-
 describe ApplicationHelper do
   before do
     @user = Factory.create(:user)
     @person = Factory.create(:person)
   end
 
-  it "should specifiy if a post is not owned user" do
-    p = Factory.create(:post, :person => @person)
-    mine?(p).should be false
-  end
-
-  it "should specifiy if a post is owned current user" do
-    p = Factory.create(:post, :person => @user)
-    mine?(p).should be true
-  end
 
   it "should provide a correct show path for a given person" do
     person_url(@person).should == "/people/#{@person.id}"
@@ -25,4 +15,5 @@ describe ApplicationHelper do
   it "should provide a correct show path for a given user" do
     person_url(@user).should == "/users/#{@user.id}"
   end
+
 end
diff --git a/spec/helpers/publics_helper_spec.rb b/spec/helpers/publics_helper_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bdc9c8250a63c6df30c4429fe97519cb7bd06c4b
--- /dev/null
+++ b/spec/helpers/publics_helper_spec.rb
@@ -0,0 +1,15 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+include PublicsHelper 
+describe PublicsHelper do
+  before do
+    @user = Factory.create(:user)
+    @person = Factory.create(:person)
+  end
+
+  it 'should be able to give me the terse url for webfinger' do
+     @user.person.url = "http://example.com/"
+
+      terse_url( @user.person.url ).should == 'example.com'
+  end
+end
diff --git a/spec/helpers/requests_helper_spec.rb b/spec/helpers/requests_helper_spec.rb
index 6f5b37442b3a8c3e22a4a807a82565def21874d0..8419bd566c362ed7eb8d12010d09aa94888ceb4d 100644
--- a/spec/helpers/requests_helper_spec.rb
+++ b/spec/helpers/requests_helper_spec.rb
@@ -20,7 +20,7 @@ describe RequestsHelper do
     end
 
     it 'should return the correct tag and url for a given address' do
-      relationship_flow('tom@tom.joindiaspora.com')[:friend].should == 'http://tom.joindiaspora.com/'
+      relationship_flow('tom@tom.joindiaspora.com')[:friend].include?("receive/user").should ==  true
     end
 
   end
diff --git a/spec/lib/diaspora_parser_spec.rb b/spec/lib/diaspora_parser_spec.rb
index 10f02f6ef353653af992a862f5fb37a1cd340ced..3e4344a64ad8e856a3db63d79913ec1b44559791 100644
--- a/spec/lib/diaspora_parser_spec.rb
+++ b/spec/lib/diaspora_parser_spec.rb
@@ -3,98 +3,79 @@ require File.dirname(__FILE__) + '/../spec_helper'
 include ApplicationHelper 
 include Diaspora::Parser
 
+
+
 describe Diaspora::Parser do
   before do
     @user = Factory.create(:user, :email => "bob@aol.com")
-    @person = Factory.create(:person, :email => "bill@gates.com")
+    @group = @user.group(:name => 'spies')
+    @person = Factory.create(:person_with_private_key, :email => "bill@gates.com")
+    @user2 = Factory.create(:user)
   end
 
-  it "should not store posts from me" do
-    status_messages = []
-    10.times { status_messages << Factory.build(:status_message, :person => @user)}
-    xml = Post.build_xml_for(status_messages) 
-    store_objects_from_xml(xml) 
-    StatusMessage.count.should == 0
-  end
-  
-  it "should reject xml with no sender" do
-    xml = "<XML>
-    <head>
-    </head><posts>
-      <post><status_message>\n  <message>Here is another message</message>\n  <owner>a@a.com</owner>\n  <snippet>a@a.com</snippet>\n  <source>a@a.com</source>\n</status_message></post>
-      <post><person></person></post>
-      <post><status_message>\n  <message>HEY DUDE</message>\n  <owner>a@a.com</owner>\n  <snippet>a@a.com</snippet>\n  <source>a@a.com</source>\n</status_message></post>
-      </posts></XML>"
-    store_objects_from_xml(xml)
-    Post.count.should == 0
 
-  end
-  
-  it "should reject xml with a sender not in the database" do
-    xml = "<XML>
-    <head>
-      <sender>
-        <email>foo@example.com</email>
-      </sender>
-    </head><posts>
-      <post><status_message>\n  <message>Here is another message</message>\n  <owner>a@a.com</owner>\n  <snippet>a@a.com</snippet>\n  <source>a@a.com</source>\n</status_message></post>
-      <post><person></person></post>
-      <post><status_message>\n  <message>HEY DUDE</message>\n  <owner>a@a.com</owner>\n  <snippet>a@a.com</snippet>\n  <source>a@a.com</source>\n</status_message></post>
-      </posts></XML>"
-    store_objects_from_xml(xml)
-    Post.count.should == 0
-  end
-  
-  it 'should discard types which are not of type post' do
-    xml = "<XML>
-    <head>
-      <sender>
-        <email>#{Person.first.email}</email>
-      </sender>
-    </head>
-    <posts>
-      <post><person></person></post>
-    </posts></XML>"
-    
-    store_objects_from_xml(xml)
-    Post.count.should == 0
+  it "should associate the post with a group" do
+    @user.activate_friend(@person, @group)
+
+    status_message = Factory.build(:status_message, :message => "hey!", :person => @person)
+    @user.receive status_message.to_diaspora_xml
+
+
+    # mongomapper doesn't support joins, meaning we can't do a query
+    # on user.groups.
+    # should this code below be a function of a user?
+    # something like self.find_group_for(friend_id) ?
+    groups = @user.groups
+    groups.shift while not groups[0].person_ids.include?(@person.id)
+    group = groups[0]
+    ####
+
+    @group.posts.count.should == 1
   end
 
 
-  describe "parsing compliant XML object" do 
+
+  describe 'with encryption' do
     before do
-      @status_messages = []
-      10.times { @status_messages << Factory.build(:status_message)}
-      @xml = Post.build_xml_for(@status_messages) 
+      unstub_mocha_stubs
     end
-
-    it 'should be able to parse the body\'s contents' do
-      body = parse_body_contents_from_xml(@xml).to_s
-      body.should_not include "<head>"
-      body.should_not include "</head>"
-      body.should_not include "<posts>"
-      body.should_not include "</posts>"
-      body.should include "<post>"
-      body.should include "</post>"
+    after do
+      stub_signature_verification
+    end
+    it "should not store posts from me" do
+      10.times { 
+        message = Factory.build(:status_message, :person => @user)
+        xml = message.to_diaspora_xml
+        @user.receive xml 
+        }
+      StatusMessage.count.should == 0
+    end
+    
+    it "should reject xml with no sender" do
+      xml = "<XML>
+      <head>
+      </head>
+        <post><status_message>\n  <message>Here is another message</message>\n  <owner>a@a.com</owner>\n  <snippet>a@a.com</snippet>\n  <source>a@a.com</source>\n</status_message></post>
+        <post><person></person></post>
+        <post><status_message>\n  <message>HEY DUDE</message>\n  <owner>a@a.com</owner>\n  <snippet>a@a.com</snippet>\n  <source>a@a.com</source>\n</status_message></post>
+        </XML>"
+      @user.receive xml
+      Post.count.should == 0
     end
+  end 
 
-    it 'should be able to extract all posts to an array' do
-      posts = parse_objects_from_xml(@xml)
-      posts.is_a?(Array).should be true
-      posts.count.should == 10
+  describe "parsing compliant XML object" do 
+    before do
+      @xml = Factory.build(:status_message).to_diaspora_xml 
     end
     
     it 'should be able to correctly handle comments' do
       person = Factory.create(:person, :email => "test@testing.com")
-      post = Factory.create(:status_message)
+      post = Factory.create(:status_message, :person => @user.person)
       comment = Factory.build(:comment, :post => post, :person => person, :text => "Freedom!")
-      xml = "<XML>
-      <posts>
-        <post>#{comment.to_xml}</post>
-      </posts></XML>"
+      xml = comment.to_diaspora_xml 
 
-      objects = parse_objects_from_xml(xml)
-      comment = objects.first
+      comment = Diaspora::Parser.from_xml(xml)
       comment.text.should == "Freedom!"
       comment.person.should == person
       comment.post.should == post
@@ -104,53 +85,95 @@ describe Diaspora::Parser do
       person = Factory.create(:person)
       message = Factory.create(:status_message, :person => person)
       retraction = Retraction.for(message)
-      request = Post.build_xml_for( [retraction] )
+      request = retraction.to_diaspora_xml
 
       StatusMessage.count.should == 1
-      store_objects_from_xml( request )
+      @user.receive request
       StatusMessage.count.should == 0
     end
     
     it "should create a new person upon getting a person request" do
+      person_count = Person.all.count
       request = Request.instantiate(:to =>"http://www.google.com/", :from => @person)
       
       original_person_id = @person.id
-      xml = Request.build_xml_for [request]
-
+      xml = request.to_diaspora_xml 
+      
       @person.destroy
-      Person.all.count.should be 1
-      store_objects_from_xml(xml)
-      Person.all.count.should be 2
+      Person.all.count.should == person_count -1
+      @user.receive xml
+      Person.all.count.should == person_count
 
-      Person.where(:url => request.callback_url).first.id.should == original_person_id
+      Person.first(:_id => original_person_id).serialized_key.include?("PUBLIC").should be true
+      url = "http://" + request.callback_url.split("/")[2] + "/"
+      Person.where(:url => url).first.id.should == original_person_id
     end
     
+    it "should not create a new person if the person is already here" do
+      person_count = Person.all.count
+      request = Request.instantiate(:to =>"http://www.google.com/", :from => @user2.person)
+      
+      original_person_id = @user2.person.id
+      xml = request.to_diaspora_xml
+      
+      
+      Person.all.count.should be person_count
+      @user.receive xml
+      Person.all.count.should be person_count
+      
+      @user2.reload
+      @user2.person.reload
+      @user2.person.serialized_key.include?("PRIVATE").should be true
+
+      url = "http://" + request.callback_url.split("/")[2] + "/"
+      Person.where(:url => url).first.id.should == original_person_id
+    end
 
     it "should activate the Person if I initiated a request to that url" do 
-      request = Request.instantiate(:to => @person.url, :from => @user).save
-      
-      request_remote = Request.new
-      request_remote.destination_url = @user.url
-      request_remote.callback_url = @user.url
-      request_remote.person = @person
-      request_remote.exported_key = @person.export_key
+      request = @user.send_friend_request_to( @user2.receive_url, @group.id)
+
+      request.reverse @user2 
 
-      xml = Request.build_xml_for [request_remote]
+      xml = request.to_diaspora_xml 
+
+      @user2.person.destroy
+      @user2.destroy
+
+      @user.receive xml
+      new_person = Person.first(:url => @user2.person.url)
+      new_person.nil?.should be false
       
-      @person.destroy
-      request_remote.destroy
-      store_objects_from_xml(xml)
-      Person.first(:url => @person.url).active.should be true
+      @user.reload
+      @group.reload
+      @group.people.include?(new_person).should be true
+      @user.friends.include?(new_person).should be true
     end
 
 
-    it 'should marshal a retraction for a person' do
-      retraction = Retraction.for(@user)
-      request = Retraction.build_xml_for( [retraction] )
+    it 'should process retraction for a person' do
+      person_count = Person.all.count
+      request = @user.send_friend_request_to( @user2.receive_url, @group.id)
+      request.reverse @user2 
+      xml = request.to_diaspora_xml 
+
+      retraction = Retraction.for(@user2)
+      retraction_xml = retraction.to_diaspora_xml
+      
+      @user2.person.destroy
+      @user2.destroy
+      @user.receive xml
+      
+      @group.reload
+      group_people_count = @group.people.size
+      #They are now friends
+
+
+      Person.count.should == person_count
+      @user.receive retraction_xml
+      Person.count.should == person_count-1
 
-      Person.count.should == 2
-      store_objects_from_xml( request )
-      Person.count.should == 1
+      @group.reload
+      @group.people.size.should == group_people_count -1
     end
     
     it 'should marshal a profile for a person' do
@@ -165,26 +188,24 @@ describe Diaspora::Parser do
       old_profile.first_name.should == 'bob'
 
       #Build xml for profile, clear profile
-      xml = Post.build_xml_for(person.profile)
-      reloaded_person = Person.first(:id => id)
+      xml = person.profile.to_diaspora_xml
+      reloaded_person = Person.first(:id => id)            
       reloaded_person.profile = nil
-      reloaded_person.save
+      reloaded_person.save(:validate => false)
 
       #Make sure profile is cleared
-      Person.first(:id=> id).profile.should be nil    
+      Person.first(:id => id).profile.should be nil    
       old_profile.first_name.should == 'bob'
 
       #Marshal profile
-      store_objects_from_xml xml
+      @user.receive xml
       
       #Check that marshaled profile is the same as old profile
       person = Person.first(:id => person.id)
       person.profile.should_not be nil 
-      person.profile.first_name.should  == old_profile.first_name
+      person.profile.first_name.should == old_profile.first_name
       person.profile.last_name.should  == old_profile.last_name
       person.profile.image_url.should  == old_profile.image_url
-      
-
       end
   end
 end
diff --git a/spec/lib/message_handler_spec.rb b/spec/lib/message_handler_spec.rb
index 553135b9672e972ceed22abebe9c2e809d498412..ba13f8fef0390d97db01e5806b7183098050117c 100644
--- a/spec/lib/message_handler_spec.rb
+++ b/spec/lib/message_handler_spec.rb
@@ -138,7 +138,6 @@ class FakeHttpRequest
     @callback = callback_wanted
   end
   def response 
-    "NOTE YOU ARE IN FAKE HTTP"
   end
 
   def post; end
diff --git a/spec/lib/socket_renderer_spec.rb b/spec/lib/socket_renderer_spec.rb
deleted file mode 100644
index 009de8b78ab416718060708fd1a793c5ff34b145..0000000000000000000000000000000000000000
--- a/spec/lib/socket_renderer_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-=begin
-  require File.dirname(__FILE__) + '/../spec_helper'
-
-describe SocketRenderer do
-  before do
-    SocketRenderer.instantiate_view
-    @user = Factory.create(:user, :email => "bob@jones.com")
-    @user.profile = Factory.create(:profile, :person => @user)
-  end
-
-  it 'should render a partial for a status message' do
-    message = Factory.create(:status_message, :person => @user)
-    html = SocketRenderer.view_for message
-    html.include? message.message
-  end
-
-  it 'should prepare a class/view hash' do
-      message = Factory.create(:status_message, :person => @user)
-
-      hash = SocketRenderer.view_hash(message)
-      hash[:class].should == "status_messages"
-  end
-end
-=end
diff --git a/spec/lib/web_hooks_spec.rb b/spec/lib/web_hooks_spec.rb
index d1819980f9e54104f29410f054d3819b575d8508..63739f636106366c5ca76f24faa5c9dda25b969d 100644
--- a/spec/lib/web_hooks_spec.rb
+++ b/spec/lib/web_hooks_spec.rb
@@ -7,12 +7,13 @@ describe Diaspora do
   describe Webhooks do
     before do
       @user = Factory.create(:user, :email => "bob@aol.com")
+      @user.person.save
       @person = Factory.create(:person)
     end
 
     describe "body" do
       before do
-        @post = Factory.create(:status_message, :person => @user)
+        @post = Factory.build(:status_message, :person => @user.person)
       end
 
       it "should add the following methods to Post on inclusion" do
@@ -21,46 +22,36 @@ describe Diaspora do
         @post.respond_to?(:people_with_permissions).should be true
       end
 
-      it "should convert an object to a proper diaspora entry" do
-        @post.to_diaspora_xml.should == "<post>#{@post.to_xml.to_s}</post>"
-      end
-
       it "should retrieve all valid person endpoints" do
-        Factory.create(:person, :url => "http://www.bob.com/")
-        Factory.create(:person, :url => "http://www.alice.com/")
-        Factory.create(:person, :url => "http://www.jane.com/")
+        @user.friends << Factory.create(:person, :url => "http://www.bob.com/")
+        @user.friends << Factory.create(:person, :url => "http://www.alice.com/")
+        @user.friends << Factory.create(:person, :url => "http://www.jane.com/")
+        @user.save
 
-        non_users = Person.where( :_type => "Person" ).all
-        @post.people_with_permissions.should == non_users
+        @post.person.owner.reload
+                
+        @post.people_with_permissions.should == @user.friends
       end
 
       it "should send an owners post to their people" do
-        q = Post.send(:class_variable_get, :@@queue)
-        q.should_receive :process
-        @post.save
+        message_queue.should_receive :process
+        @user.post :status_message, :message => "hi" 
       end
     
       it "should check that it does not send a person's post to an owners people" do
-        Post.stub(:build_xml_for).and_return(true) 
-        Post.should_not_receive(:build_xml_for)
-        
+        message_queue.should_not_receive(:add_post_request) 
         Factory.create(:status_message, :person => Factory.create(:person))
       end
 
       it "should ensure one url is created for every person" do
-        5.times {Factory.create(:person)}
-        @post.people_with_permissions.size.should == 6
+        5.times {@user.friends << Factory.create(:person)}
+        @user.save
+        
+        @post.person.owner.reload
+        
+        @post.people_with_permissions.size.should == 5
       end
 
-      it "should build an xml object containing multiple Post types" do
-        Factory.create(:status_message)
-        Factory.create(:bookmark)
-
-        stream = Post.stream
-        xml = Post.build_xml_for(stream)
-        xml.should include "<status_message>"
-        xml.should include "<bookmark>"
-      end
     end
   end
 
diff --git a/spec/misc_spec.rb b/spec/misc_spec.rb
index 773b8c6d9c20f1771008efde0190bd60bd82ebb1..9e9d61efaf95203d39536295bc2ff699b6de1bfd 100644
--- a/spec/misc_spec.rb
+++ b/spec/misc_spec.rb
@@ -12,6 +12,11 @@ describe 'making sure the spec runner works' do
     User.count.should == 0
   end
   
+  it 'should factory create a user with a person saved' do
+    user = Factory.create(:user)
+    loaded_user = User.first(:id => user.id)
+    loaded_user.person.owner_id.should == user.id
+  end
   describe 'testing a before do block' do
     before do
       Factory.create(:user)
diff --git a/spec/models/album_spec.rb b/spec/models/album_spec.rb
index b93de4888c7e5a40e29573f7ea81fb9a13261995..f5038ec1c1a86cf888e13748c35fed4b1057d130 100644
--- a/spec/models/album_spec.rb
+++ b/spec/models/album_spec.rb
@@ -4,7 +4,8 @@ describe Album do
   before do
     @fixture_name = File.dirname(__FILE__) + '/../fixtures/bp.jpeg'
     @user = Factory.create(:user)
-    @album = Album.new(:name => "test collection", :person => @user)
+    @user.person.save
+    @album = Album.new(:name => "test collection", :person => @user.person)
   end
 
   it 'should belong to a person' do
@@ -26,8 +27,8 @@ describe Album do
   end
 
   it 'should contain photos' do
-    album = Album.create(:name => "test collection", :person => @user)
-    photo = Factory.build(:photo, :person => @user)
+    album = Album.create(:name => "test collection", :person => @user.person)
+    photo = Factory.build(:photo, :person => @user.person)
 
     album.photos << photo
     album.photos.count.should == 1
@@ -36,7 +37,7 @@ describe Album do
   it 'should remove all photos on album delete' do
       photos = []
       1.upto 3 do
-        photo =   Photo.new(:person => @user, :album => @album, :created_at => Time.now)
+        photo =   Photo.new(:person => @user.person, :album => @album, :created_at => Time.now)
         photo.image.store! File.open @fixture_name
         photos << photo
       end
@@ -51,7 +52,7 @@ describe Album do
     before do
       @photos = []
       1.upto 3 do |n|
-        photo =   Photo.new(:person => @user, :album => @album, :created_at => Time.now + n)
+        photo =   Photo.new(:person => @user.person, :album => @album, :created_at => Time.now + n)
         photo.image.store! File.open @fixture_name
         @photos << photo
       end
diff --git a/spec/models/blogs_spec.rb b/spec/models/blogs_spec.rb
index 270339a85cc52f6ed4982f1825ebacdfde44cea6..9be9db74b7989376bb1b31cdc58cfb0329728f64 100644
--- a/spec/models/blogs_spec.rb
+++ b/spec/models/blogs_spec.rb
@@ -18,7 +18,7 @@ describe Blog do
  
   describe "XML" do
     it 'should serialize to XML' do
-      body = Factory.create(:blog, :title => "yessir", :body => "penguins")
+      body = Factory.create(:blog, :title => "yessir", :body => "penguins", :person => @user.person)
       body.to_xml.to_s.should include "<title>yessir</title>"
       body.to_xml.to_s.should include "<body>penguins</body>"
     end
diff --git a/spec/models/bookmark_spec.rb b/spec/models/bookmark_spec.rb
index 879408430dd88f7a995d046cf56cd2850a0fdf07..ae4567bc1ec155e0d1f18fce7ff541792b592963 100644
--- a/spec/models/bookmark_spec.rb
+++ b/spec/models/bookmark_spec.rb
@@ -10,34 +10,6 @@ describe Bookmark do
   
   it 'should validate its link' do
     bookmark = Factory.build(:bookmark)
-
-    #links changed valid
-    bookmark.link = "google.com"
-    bookmark.valid?.should == true 
-    bookmark.link.should == "http://google.com/"
-
-    bookmark.link = "www.google.com"
-    bookmark.valid?.should == true
-    bookmark.link.should == "http://www.google.com/"
-
-    bookmark.link = "google.com/"
-    bookmark.valid?.should == true
-    bookmark.link.should == "http://google.com/"
-
-    bookmark.link = "www.google.com/"
-    bookmark.valid?.should == true
-    bookmark.link.should == "http://www.google.com/"
-
-    bookmark.link = "http://google.com"
-    bookmark.valid?.should == true
-    bookmark.link.should == "http://google.com/"
-
-    bookmark.link = "http://www.google.com"
-    bookmark.valid?.should == true
-    
-    #bookmark.link = "http://babycakes.sofaer.net:3000"
-    #bookmark.valid?.should == true
-
     #invalid links
     bookmark.link = "zsdvzxdg"
     bookmark.valid?.should == false
@@ -54,11 +26,29 @@ describe Bookmark do
     bookmark.link = "http:///www.asodij.com/"
     bookmark.valid?.should == false
   end
+  
+  it 'should clean links' do
+    bad_links = [
+      "google.com",
+      "www.google.com",
+      "google.com/",
+      "www.google.com/",
+      "http://google.com",
+      "http://www.google.com"
+    ]
+
+    bad_links.each{ |link|
+       Bookmark.clean_link(link).should satisfy{ |link|
+         /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix.match(link)
+       }
+    }
+    
+  end
 
   describe "XML" do
     it 'should serialize to XML' do
-      Factory.create(:user)
-      message = Factory.create(:bookmark, :title => "Reddit", :link => "http://reddit.com/")
+      u = Factory.create(:user)
+      message = Factory.create(:bookmark, :title => "Reddit", :link => "http://reddit.com/", :person => u.person)
       message.to_xml.to_s.should include "<title>Reddit</title>"
       message.to_xml.to_s.should include "<link>http://reddit.com/</link>"
     end
@@ -71,4 +61,20 @@ describe Bookmark do
       parsed.valid?.should be_true
     end
   end
+
+  describe 'with encryption' do
+    before do
+      unstub_mocha_stubs
+      @user = Factory.create(:user)
+    end
+
+    after do
+      stub_signature_verification
+    end
+
+    it 'should save a signed bookmark' do
+      bookmark = @user.post(:bookmark, :title => "I love cryptography", :link => "http://pgp.mit.edu/")
+      bookmark.created_at.should_not be nil
+    end
+  end
 end 
diff --git a/spec/models/comments_spec.rb b/spec/models/comments_spec.rb
index 4f5b79115df6ed347f023c3d227db67765faca9f..3be39564486b9d8579cf80a7f62564a993fd76a5 100644
--- a/spec/models/comments_spec.rb
+++ b/spec/models/comments_spec.rb
@@ -4,9 +4,10 @@ describe Comment do
   describe "user" do
     before do
       @user = Factory.create :user
+      @user.person.save
     end
     it "should be able to comment on his own status" do
-      status = Factory.create(:status_message, :person => @user)
+      status = Factory.create(:status_message, :person => @user.person)
       status.comments.should == []
 
       @user.comment "Yeah, it was great", :on => status
@@ -19,42 +20,48 @@ describe Comment do
       @user.comment "sup dog", :on => status
       
       StatusMessage.first.comments.first.text.should == "sup dog"
-      StatusMessage.first.comments.first.person.should == @user
+      StatusMessage.first.comments.first.person.should == @user.person
     end
 
     it 'should not send out comments when we have no people' do
-      status = Factory.create(:status_message, :person => @user)
-      Comment.send(:class_variable_get, :@@queue).should_not_receive(:add_post_request)
+      status = Factory.create(:status_message, :person => @user.person)
+      message_queue.should_not_receive(:add_post_request)
       @user.comment "sup dog", :on => status
     end
 
     describe 'comment propagation' do
       before do
         @person = Factory.create(:person)
-        @person_two = Factory.create(:person)
-        @person_status = Factory.create(:status_message, :person => @person)
-        @user_status = Factory.create(:status_message, :person => @user)
+        @user.friends << Factory.create(:person)
+        @user.save
+        @person2 = Factory.create(:person) 
+        @person_status = Factory.build(:status_message, :person => @person)
+        @user_status = Factory.build(:status_message, :person => @user.person)
       end
     
       it "should send a user's comment on a person's post to that person" do
-        Comment.send(:class_variable_get, :@@queue).should_receive(:add_post_request)
+        message_queue.should_receive(:add_post_request)
         @user.comment "yo", :on => @person_status
       end
     
       it 'should send a user comment on his own post to lots of people' do
-        allowed_urls = @user_status.people_with_permissions.map!{|x| x = x.url + "receive/"}
-        Comment.send(:class_variable_get, :@@queue).should_receive(:add_post_request).with(allowed_urls, anything )
+        allowed_urls = @user_status.people_with_permissions.map{|x| x = x.receive_url}
+        message_queue.should_receive(:add_post_request).with(allowed_urls, anything)
         @user.comment "yo", :on => @user_status
       end
     
       it 'should send a comment a person made on your post to all people' do
-        Comment.send(:class_variable_get, :@@queue).should_receive(:add_post_request)
-        com = Comment.create(:person => @person, :text => "balls", :post => @user_status)
+        message_queue.should_receive(:add_post_request)
+        @person.comment "balls", :on => @user_status
       end
     
+      it 'should not send a comment a person made on his own post to anyone' do
+        message_queue.should_not_receive(:add_post_request)
+        @person.comment "balls", :on => @person_status
+      end
       it 'should not send a comment a person made on a person post to anyone' do
-        Comment.send(:class_variable_get, :@@queue).should_not_receive(:add_post_request)
-        com = Comment.create(:person => @person, :text => "balls", :post => @person_status)  
+        message_queue.should_not_receive(:add_post_request)
+        @person2.comment "balls", :on => @person_status
       end
     end
   end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1d0f400d5f9541231681aab49ad1f67f529853c4
--- /dev/null
+++ b/spec/models/group_spec.rb
@@ -0,0 +1,55 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Group do
+  before do
+    @user = Factory.create(:user)
+    @friend = Factory.create(:person)
+    @user2 = Factory.create(:user)
+    @friend_2 = Factory.create(:person)
+  end
+
+  describe 'creation' do
+    it 'should have a name' do
+      group = @user.group(:name => 'losers')
+      group.name.should == "losers"
+    end
+
+    it 'should be able to have people' do
+      group = @user.group(:name => 'losers', :people => [@friend, @friend_2])
+      group.people.size.should == 2
+    end
+
+    it 'should be able to have other users' do
+      group = @user.group(:name => 'losers', :people => [@user2.person])
+      group.people.include?(@user.person).should be false
+      group.people.include?(@user2.person).should be true 
+      group.people.size.should == 1
+    end   
+
+    it 'should be able to have users and people' do
+      group = @user.group(:name => 'losers', :people => [@user2.person, @friend_2])
+      group.people.include?(@user.person).should be false
+      group.people.include?(@user2.person).should be true 
+      group.people.include?(@friend_2).should be true 
+      group.people.size.should == 2
+    end
+
+  end
+  
+  describe 'querying' do
+    before do
+      @group = @user.group(:name => 'losers', :people => [@friend])
+    end
+
+    it 'belong to a user' do
+      @group.user.id.should == @user.id
+      @user.groups.size.should == 1
+      @user.groups.first.id.should == @group.id
+    end
+
+    it 'should have people' do
+      @group.people.all.include?(@friend).should be true
+      @group.people.size.should == 1
+    end
+  end
+end
diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb
index 1660371b6ba4ad31bb0675921a1731d3c04a53cc..c062d396b65222007c77b7acd38e779902ae5585 100644
--- a/spec/models/person_spec.rb
+++ b/spec/models/person_spec.rb
@@ -1,54 +1,54 @@
 require File.dirname(__FILE__) + '/../spec_helper'
 
 describe Person do
-  it 'should not allow two people with the same url' do
-    person_one = Factory.create(:person)
-    person_two = Factory.build(:person, :url => person_one.url)
-    person_two.valid?.should == false
-  end
-  
-  it 'should not allow a person with the same url as the user' do
-    user = Factory.create(:user)
-    person = Factory.build(:person, :url => user.url)
-    person.valid?.should == false
+  before do
+    @user = Factory.create(:user)
+    @user2 = Factory.create(:user)
+    @person = Factory.create(:person)
+    @group = @user.group(:name => "Dudes")
+    @group2 = @user2.group(:name => "Abscence of Babes")
   end
 
-  it 'should serialize to xml' do
-    person = Factory.create(:person)
-    xml = person.to_xml.to_s
-    (xml.include? "person").should == true
-  end
 
-  it 'should have a profile in its xml' do
-    person = Factory.create(:person)
-    xml = person.to_xml.to_s
-    (xml.include? "first_name").should == true
+  it 'should not allow two people with the same email' do
+    person_two = Factory.build(:person, :url => @person.email)
+    person_two.valid?.should == false
   end
 
-  it 'should only return active friends' do
-    Factory.create(:person)
-    Factory.create(:person, :active => false)
-    Factory.create(:person, :active => false)
+  describe 'xml' do
+    before do 
+      @xml = @person.to_xml.to_s
+    end
+    it 'should serialize to xml' do
+      (@xml.include? "person").should == true
+    end
 
-    Person.friends.all.count.should == 1
+    it 'should have a profile in its xml' do
+      (@xml.include? "first_name").should == true
+    end
   end
+  
+  it 'should know when a post belongs to it' do
+    person_message = Factory.create(:status_message, :person => @person)
+    person_two = Factory.create(:person)
 
+    @person.owns?(person_message).should be true
+    person_two.owns?(person_message).should be false
+  end
 
   it 'should delete all of user except comments upon user deletion' do
-    Factory.create(:user)
-
     f = Factory.create(:person)
-    p = Factory.create(:person)
+
     Factory.create(:status_message, :person => f)
     Factory.create(:blog, :person => f)
     Factory.create(:bookmark, :person => f)
     Factory.create(:status_message, :person => f)
-    s = Factory.create(:status_message, :person => p)
+    s = Factory.create(:status_message, :person => @person)
    
     Factory.create(:comment, :person_id => f.id, :text => "yes i do", :post => s)
     Factory.create(:comment, :person_id => f.id, :text => "i love you", :post => s)
     Factory.create(:comment, :person_id => f.id, :text => "hello", :post => s)
-    Factory.create(:comment, :person_id => p.id, :text => "you are creepy", :post => s)
+    Factory.create(:comment, :person_id => @person.id, :text => "you are creepy", :post => s)
 
     f.destroy
 
@@ -57,15 +57,44 @@ describe Person do
     s.comments.count.should == 4
   end
 
-  it 'should let a user unfriend another user' do
-    u = Factory.create(:user)
+  describe "unfriending" do
+    it 'should delete an orphaned friend' do
+      
+      request = @user.send_friend_request_to @person.receive_url, @group.id
+
+      @user.activate_friend(@person, @group) 
+      @user.reload
+      
+      Person.all.count.should == 3
+      @user.friends.count.should == 1
+      @user.unfriend(@person)
+      @user.reload
+      @user.friends.count.should == 0
+      Person.all.count.should == 2
+    end
+
+    it 'should not delete an un-orphaned friend' do
+      request = @user.send_friend_request_to @person.receive_url, @group.id
+      request2 = @user2.send_friend_request_to @person.receive_url, @group2.id
+
+      @user.activate_friend(@person, @group) 
+      @user2.activate_friend(@person, @group2)
+
+      @user.reload
+      @user2.reload
+      
+      Person.all.count.should == 3
+      @user.friends.count.should == 1
+      @user2.friends.count.should == 1
 
-    f = Factory.create(:person, :active => true)
+      @user.unfriend(@person)
+      @user.reload
+      @user2.reload
+      @user.friends.count.should == 0
+      @user2.friends.count.should == 1
 
-    Person.friends.all.count.should == 1
-    u.unfriend(f.id)
-    Person.friends.all.count.should == 0
-    Person.all.count.should == 1
+      Person.all.count.should == 3
+    end
   end
 
 end
diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb
index 3920d83b2d22b276cec4c51afad8a44085e960cb..3091ed74a76df149eeebc07ce2f194ec6b1742f3 100644
--- a/spec/models/photo_spec.rb
+++ b/spec/models/photo_spec.rb
@@ -3,22 +3,23 @@ require File.dirname(__FILE__) + '/../spec_helper'
 describe Photo do
   before do
     @user = Factory.create(:user)
+    @user.person.save
+
     @fixture_filename = 'bp.jpeg'
     @fixture_name = File.dirname(__FILE__) + '/../fixtures/bp.jpeg'
     @fail_fixture_name = File.dirname(__FILE__) + '/../fixtures/msg.xml'
-    @album = Album.create(:name => "foo", :person => @user)
-    @photo = Photo.new(:person => @user, :album => @album)
+    @album = Album.create(:name => "foo", :person => @user.person)
+    @photo = Photo.new(:person => @user.person, :album => @album)
   end
 
   it 'should have a constructor' do
     image = File.open(@fixture_name)    
-    photo = Photo.instantiate(:person => @user, :album => @album, :user_file => [image]) 
+    photo = Photo.instantiate(:person => @user.person, :album => @album, :user_file => [image]) 
     photo.created_at.nil?.should be false
-  
     photo.image.read.nil?.should be false
   end
 
-  it 'should save a @photo to GridFS' do
+  it 'should save a photo to GridFS' do
     @photo.image.store! File.open(@fixture_name)
     @photo.save.should == true
     binary = @photo.image.read
@@ -27,11 +28,11 @@ describe Photo do
   end
 
   it 'must have an album' do
-    photo = Photo.new(:person => @user)
+    photo = Photo.new(:person => @user.person)
     photo.image = File.open(@fixture_name)
     photo.save
     photo.valid?.should be false
-    photo.album = Album.create(:name => "foo", :person => @user)
+    photo.album = Album.create(:name => "foo", :person => @user.person)
     photo.save
     Photo.first.album.name.should == 'foo'
   end
@@ -49,6 +50,7 @@ describe Photo do
 
     @user.profile.image_url = @photo.image.url(:thumb_medium)
     @user.save
+    @user.person.save
 
     User.first.profile.image_url.should == @photo.image.url(:thumb_medium)
     @photo.destroy
@@ -56,8 +58,8 @@ describe Photo do
   end
 
   it 'should not use the imported filename as the url' do
+    pending "Until this passes, duplicate photos will cause errors"
     @photo.image.store! File.open(@fixture_name)
-    puts @photo.image.url(:thumb_medium)
     @photo.image.url.include?(@fixture_filename).should be false
     @photo.image.url(:thumb_medium).include?("/" + @fixture_filename).should be false
   end
@@ -71,13 +73,6 @@ describe Photo do
       }.should raise_error
     end
 
-    it 'should not save' do
-      pending "We need to figure out the difference between us and the example app"
-      file = File.open(@fail_fixture_name)
-      @photo.image.should_receive(:check_whitelist!)
-      @photo.image = file
-      @photo.save.should == false
-    end
   end
   
   describe 'with encryption' do
@@ -90,8 +85,8 @@ describe Photo do
       stub_signature_verification
     end
 
-    it 'should save a signed @photo to GridFS' do
-      photo  = Photo.create(:person => @user, :album => @album, :image => File.open(@fixture_name))
+    it 'should save a signed photo to GridFS' do
+      photo  = Photo.create(:person => @user.person, :album => @album, :image => File.open(@fixture_name))
       photo.save.should == true
       photo.verify_creator_signature.should be true
     end
diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb
index aac4898aa01c5f54d74c37c5daeacfe13e87e1bd..a20ffb504b14837d3e5a4ccefa3b78ea537a55fa 100644
--- a/spec/models/post_spec.rb
+++ b/spec/models/post_spec.rb
@@ -3,17 +3,7 @@ require File.dirname(__FILE__) + '/../spec_helper'
 describe Post do
   before do
     @user = Factory.create(:user, :email => "bob@aol.com")
-  end
-
-  describe 'defaults' do
-    before do
-      WebSocket.stub!(:update_clients)
-      @post = Factory.create(:post, :person => nil)
-    end
-
-    it "should associate the owner if none is present" do
-      @post.person.should == User.owner
-    end
+    @user.person.save
   end
 
   describe "newest" do
@@ -21,28 +11,21 @@ describe Post do
       @person_one = Factory.create(:person, :email => "some@dudes.com")
       @person_two = Factory.create(:person, :email => "other@dudes.com")
       (2..4).each {|n| Blog.create(:title => "title #{n}", :body => "test #{n}", :person => @person_one)}
-      (5..8).each { |n| Blog.create(:title => "title #{n}",:body => "test #{n}", :person => @user)}
+      (5..8).each { |n| Blog.create(:title => "title #{n}",:body => "test #{n}", :person => @user.person)}
       (9..11).each { |n| Blog.create(:title => "title #{n}",:body => "test #{n}", :person => @person_two)}
 
-      Factory.create(:status_message)
-      Factory.create(:bookmark)
+      Factory.create(:status_message, :person => @user)
+      Factory.create(:bookmark, :person => @user)
     end
   
     it "should give the most recent blog title and body from owner" do
-      blog = Blog.my_newest()
-      blog.person.email.should == @user.email
+      blog = Blog.newest_for(@user.person)
+      blog.person.email.should == @user.person.email
       blog.class.should == Blog
       blog.title.should == "title 8"
       blog.body.should == "test 8"
     end
-    
-    it "should give the most recent blog body for a given email" do
-      blog = Blog.newest_by_email("some@dudes.com")
-      blog.person.email.should == @person_one.email
-      blog.class.should == Blog
-      blog.title.should == "title 4"
-      blog.body.should == "test 4"
-    end
+
   end
  
   describe "stream" do 
@@ -51,10 +34,10 @@ describe Post do
       @person_one = Factory.create(:person, :email => "some@dudes.com")
       @person_two = Factory.create(:person, :email => "other@dudes.com")
 
-      Factory.create(:status_message, :message => "puppies", :created_at => Time.now+1, :person => @owner)
+      Factory.create(:status_message, :message => "puppies", :created_at => Time.now+1, :person => @owner.person)
       Factory.create(:bookmark, :title => "Reddit", :link => "http://reddit.com", :created_at => Time.now+2, :person => @person_one)
       Factory.create(:status_message, :message => "kittens", :created_at => Time.now+3, :person => @person_two)
-      Factory.create(:blog, :title => "Bears", :body => "Bear's body", :created_at => Time.now+4, :person => @owner)
+      Factory.create(:blog, :title => "Bears", :body => "Bear's body", :created_at => Time.now+4, :person => @owner.person)
       Factory.create(:bookmark, :title => "Google", :link => "http://google.com", :created_at => Time.now+5, :person => @person_two)
     end
 
@@ -78,15 +61,15 @@ describe Post do
   end
   describe 'xml' do
     it 'should serialize to xml with its person' do
-      message = Factory.create(:status_message, :person => @user)
-      (message.to_xml.to_s.include? @user.email).should == true
+      message = Factory.create(:status_message, :person => @user.person)
+      (message.to_xml.to_s.include? @user.person.email).should == true
     end
   end
 
   describe 'deletion' do
     it 'should delete a posts comments on delete' do
-      post = Factory.create(:status_message, :person => @user)
-      @user.comment "hey", :on=> post
+      post = Factory.create(:status_message, :person => @user.person)
+      @user.comment "hey", :on => post
       post.destroy
       Post.all(:id => post.id).empty?.should == true
       Comment.all(:text => "hey").empty?.should == true
diff --git a/spec/models/request_spec.rb b/spec/models/request_spec.rb
index 788b7aee5451794a0ba57b94642231bb49a853f4..c5b49cc64290a04c02750e249852bbfa9fcfe056 100644
--- a/spec/models/request_spec.rb
+++ b/spec/models/request_spec.rb
@@ -1,7 +1,10 @@
 require File.dirname(__FILE__) + '/../spec_helper'
 
 describe Request do 
-
+  before do
+    @user = Factory.create(:user)
+    @group = @user.group(:name => "dudes")
+  end
   it 'should require a destination and callback url' do
     person_request = Request.new
     person_request.valid?.should be false
@@ -11,49 +14,26 @@ describe Request do
   end
 
   it 'should generate xml for the User as a Person' do 
-    user = Factory.create(:user)
 
-    user.profile.save
-    
-    request = Request.instantiate(:to => "http://www.google.com/", :from => user)
+    request = @user.send_friend_request_to "http://www.google.com/", @group.id
 
     xml = request.to_xml.to_s
 
-    xml.include?(user.email).should be true
-    xml.include?(user.url).should be true
-    xml.include?(user.profile.first_name).should be true
-    xml.include?(user.profile.last_name).should be true
-  end
-
-
-  it "should should activate a user" do
-    remote_person = Factory.create(:person, :email => "robert@grimm.com", :url => "http://king.com/")
-    f = Request.create(:destination_url => remote_person.url, :person => remote_person)
-    f.activate_friend
-    Person.where(:id => remote_person.id).first.active.should be true
+    xml.include?(@user.person.email).should be true
+    xml.include?(@user.url).should be true
+    xml.include?(@user.profile.first_name).should be true
+    xml.include?(@user.profile.last_name).should be true
   end
 
-
   it 'should allow me to see only friend requests sent to me' do 
-    user = Factory.create(:user)
-    remote_person = Factory.build(:user, :email => "robert@grimm.com", :url => "http://king.com/")
+    remote_person = Factory.build(:person, :email => "robert@grimm.com", :url => "http://king.com/")
     
-    Request.instantiate(:from => user, :to => remote_person.url).save
-    Request.instantiate(:from => user, :to => remote_person.url).save
-    Request.instantiate(:from => user, :to => remote_person.url).save
-    Request.instantiate(:from => remote_person, :to => user.url).save
+    Request.instantiate(:into => @group.id, :from => @user.person, :to => remote_person.receive_url).save
+    Request.instantiate(:into => @group.id, :from => @user.person, :to => remote_person.receive_url).save
+    Request.instantiate(:into => @group.id, :from => @user.person, :to => remote_person.receive_url).save
+    Request.instantiate(:into => @group.id, :from => remote_person, :to => @user.receive_url).save
       
-    Request.for_user(user).all.count.should == 1
-  end
-
-  it 'should allow me to see only friend requests sent by me' do 
-    user = Factory.create(:user)
-    remote_person = Factory.build(:user, :email => "robert@grimm.com", :url => "http://king.com/")
-
-    Request.instantiate(:from => user, :to => remote_person.url).save
-    Request.instantiate(:from => user, :to => remote_person.url).save
-    Request.instantiate(:from => user, :to => remote_person.url).save
-    Request.instantiate(:from => remote_person, :to => user.url).save
+    Request.for_user(@user).all.count.should == 1
   end
 
 end
diff --git a/spec/models/retraction_spec.rb b/spec/models/retraction_spec.rb
index 276a74cb60638b59d3d35fb1bbf47b24902402aa..5c8695feaadacbdf0cdfcf0806c274a8649743b3 100644
--- a/spec/models/retraction_spec.rb
+++ b/spec/models/retraction_spec.rb
@@ -1,23 +1,27 @@
 require File.dirname(__FILE__) + '/../spec_helper'
 
 describe Retraction do
-  describe "posts" do
     before do
       @user = Factory.create(:user)
-      @post = Factory.create(:status_message, :person => @user)
+      @post = @user.post(:status_message, :message => "Destroy!")
+      @person = Factory.create(:person)
+      @user.friends << @person
+      @user.save
     end
-
+  describe 'serialization' do
     it 'should have a post id after serialization' do
       retraction = Retraction.for(@post)
       xml = retraction.to_xml.to_s
       xml.include?(@post.id.to_s).should == true
     end
-
+  end
+  describe 'dispatching' do
     it 'should dispatch a message on delete' do
       Factory.create(:person)
-      Post.send(:class_variable_get, :@@queue).should_receive(:add_post_request)
+      message_queue.should_receive(:add_post_request)
       @post.destroy
     end
-
   end
+
+
 end
diff --git a/spec/models/status_message_spec.rb b/spec/models/status_message_spec.rb
index 4bab96af292a0bfcdf881ac9bd314f4988c00626..e4d5b0f500240dcee0ae00ca7ac8f1d5a253ff78 100644
--- a/spec/models/status_message_spec.rb
+++ b/spec/models/status_message_spec.rb
@@ -18,7 +18,7 @@ describe StatusMessage do
 
   describe "XML" do
     it 'should serialize to XML' do
-      message = Factory.create(:status_message, :message => "I hate WALRUSES!")
+      message = Factory.create(:status_message, :message => "I hate WALRUSES!", :person => @user.person)
       message.to_xml.to_s.should include "<message>I hate WALRUSES!</message>"
     end
   
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 1431b1cd5bda46b915444d680a3998229d56a21e..eb77b1f05dc675e007220c0d13eed07c5d41c917 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1,35 +1,54 @@
 require File.dirname(__FILE__) + '/../spec_helper'
 
 describe User do
-  it "should be a person" do
-    n = Person.count
-    Factory.create(:user)
-    Person.count.should == n+1
+   before do
+      @user = Factory.create(:user)
+      @group = @user.group(:name => 'heroes')
+   end
+
+  it 'should instantiate with a person and be valid' do
+    user = User.instantiate(:email => "bob@bob.com",
+                            :password => "password",
+                            :password_confirmation => "password",
+                            :person => 
+                              {:profile => {
+                                :first_name => "bob",
+                                :last_name => "grimm"}})
+
+    user.save.should be true
+    user.person.should_not be nil
+    user.person.profile.should_not be nil
   end
 
   describe 'friend requesting' do
-    before do
-      @user = Factory.create(:user)
+    it "should assign a request to a group" do
+      friend = Factory.create(:person)
+      group = @user.group(:name => "Dudes")
+      group.requests.size.should == 0
+
+      @user.send_friend_request_to(friend.receive_url, group.id)
+
+      group.reload
+      group.requests.size.should == 1
     end
 
-    it "should be able to accept a pending friend request" do
-      friend = Factory.create(:person, :active => false)
-      r = Request.instantiate(:to => @user.url, :from => friend)
+
+     it "should be able to accept a pending friend request" do
+      friend = Factory.create(:person)
+      r = Request.instantiate(:to => @user.receive_url, :from => friend)
       r.save
       Person.all.count.should == 2
       Request.for_user(@user).all.count.should == 1
-      @user.accept_friend_request(r.id)
+      @user.accept_friend_request(r.id, @group.id)
       Request.for_user(@user).all.count.should == 0
-      Person.where(:id => friend.id).first.active.should == true
     end
 
     it 'should be able to ignore a pending friend request' do
-      friend = Factory.create(:person, :active => false)
-      r = Request.instantiate(:to => @user.url, :from => friend)
+      friend = Factory.create(:person)
+      r = Request.instantiate(:to => @user.receive_url, :from => friend)
       r.save
 
       Person.count.should == 2
-      friend.active.should == false
 
       @user.ignore_friend_request(r.id)
 
@@ -39,25 +58,218 @@ describe User do
 
     it 'should not be able to friend request an existing friend' do
       friend = Factory.create(:person)
+      
+      @user.friends << friend
+      @user.save
+
+
+      @user.send_friend_request_to( friend.receive_url, @group.id ).should be nil
+    end
+
+
+
+    describe 'multiple users accepting/rejecting the same person' do
+      before do
+        @person_one = Factory.create :person
+        @person_one.save
+      
+        @user2 = Factory.create :user
+        @group2 = @user2.group(:name => "group two")
+
+        @user.pending_requests.empty?.should be true
+        @user.friends.empty?.should be true
+        @user2.pending_requests.empty?.should be true
+        @user2.friends.empty?.should be true
+
+        @request = Request.instantiate(:to => @user.receive_url, :from => @person_one)
+        @request_two = Request.instantiate(:to => @user2.receive_url, :from => @person_one)
+        @request_three =  Request.instantiate(:to => @user2.receive_url, :from => @user.person)
+
+        @req_xml = @request.to_diaspora_xml
+        @req_two_xml = @request_two.to_diaspora_xml
+        @req_three_xml = @request_three.to_diaspora_xml
+
+        @request.destroy
+        @request_two.destroy
+        @request_three.destroy
+      end
+
+      it 'should befriend the user other user on the same pod' do
+
+        @user2.receive @req_three_xml
+        @user2.pending_requests.size.should be 1
+        @user2.accept_friend_request @request_three.id, @group2.id
+        @user2.friends.include?(@user.person).should be true  
+        Person.all.count.should be 3
+      end
+
+      it 'should not delete the ignored user on the same pod' do
+
+        @user2.receive @req_three_xml
+        @user2.pending_requests.size.should be 1
+        @user2.ignore_friend_request @request_three.id
+        @user2.friends.include?(@user.person).should be false  
+        Person.all.count.should be 3
+      end
+      
+      it 'should both users should befriend the same person' do
+
+        @user.receive @req_xml
+        @user.pending_requests.size.should be 1
+        @user.accept_friend_request @request.id, @group.id
+        @user.friends.include?(@person_one).should be true  
+
+        @user2.receive @req_two_xml
+        @user2.pending_requests.size.should be 1
+        @user2.accept_friend_request @request_two.id, @group2.id
+        @user2.friends.include?(@person_one).should be true  
+        Person.all.count.should be 3
+      end
+
+      it 'should keep the person around if one of the users rejects him' do
+
+        @user.receive @req_xml
+        @user.pending_requests.size.should be 1
+        @user.accept_friend_request @request.id, @group.id
+        @user.friends.include?(@person_one).should be true  
+
+        @user2.receive @req_two_xml
+        @user2.pending_requests.size.should be 1
+        @user2.ignore_friend_request @request_two.id
+        @user2.friends.include?(@person_one).should be false  
+        Person.all.count.should be 3
+      end
+
+      it 'should not keep the person around if the users ignores them' do
+        @user.receive @req_xml
+        @user.pending_requests.size.should be 1
+        @user.ignore_friend_request @user.pending_requests.first.id
+        @user.friends.include?(@person_one).should be false  
+
+        @user2.receive @req_two_xml
+        @user2.pending_requests.size.should be 1
+        @user2.ignore_friend_request @user2.pending_requests.first.id#@request_two.id
+        @user2.friends.include?(@person_one).should be false 
+        Person.all.count.should be 2
+      end
+
 
-      @user.send_friend_request_to( friend.url ).should be nil
     end
 
-    it 'should be able to give me the terse url for webfinger' do
-      @user.terse_url.should == 'example.com'
+    describe 'a user accepting rejecting multiple people' do
+      before do
+        @person_one = Factory.create :person
+        @person_two = Factory.create :person
+
+        @user.pending_requests.empty?.should be true
+        @user.friends.empty?.should be true
+
+        @request = Request.instantiate(:to => @user.receive_url, :from => @person_one)
+        @request_two = Request.instantiate(:to => @user.receive_url, :from => @person_two)
+      end
+      
+      after do
+        @user.receive_friend_request @request        
+
+        @person_two.destroy
+        @user.pending_requests.size.should be 1
+        @user.friends.size.should be 0
+
+        @user.receive_friend_request @request_two
+        @user.pending_requests.size.should be 2
+        @user.friends.size.should be 0
+
+        @user.accept_friend_request @request.id, @group.id
+        @user.pending_requests.size.should be 1
+        @user.friends.size.should be 1
+        @user.friends.include?(@person_one).should be true
+
+        @user.ignore_friend_request @request_two.id
+        @user.pending_requests.size.should be 0
+        @user.friends.size.should be 1
+        @user.friends.include?(@person_two).should be false
+
+      end
+
     end
+  end
 
+  describe 'profiles' do
     it 'should be able to update their profile and send it to their friends' do 
       Factory.create(:person)
       
       updated_profile = {:profile => {:first_name => 'bob', :last_name => 'billytown', :image_url => "http://clown.com"}}
       
-      queue = Profile.send :class_variable_get, :@@queue
-      queue.should_receive(:process)
+      message_queue.should_receive(:process)
       
-      @user.update_profile(updated_profile).should == true
+      @user.person.update_profile(updated_profile).should == true
       @user.profile.image_url.should == "http://clown.com"
     end
   end
 
+  describe 'receiving' do
+    before do
+      @user2 = Factory.create(:user)
+      @user.friends << @user2.person
+      @user2.friends << @user.person
+      @user.person.user_refs += 1
+      @user2.person.user_refs += 1
+      @user.save
+      @user2.save
+    end
+
+    it 'should be able to parse and store a status message from xml' do
+      status_message = @user2.post :status_message, :message => 'store this!'
+      person = @user2.person
+
+      xml = status_message.to_diaspora_xml
+      @user2.destroy
+      status_message.destroy
+      StatusMessage.all.size.should == 0
+      @user.receive( xml )
+      
+      person.posts.first.message.should == 'store this!'
+      StatusMessage.all.size.should == 1
+    end
+  end
+
+  describe 'unfriending' do
+    before do
+      @user2 = Factory.create :user
+      @group2 = @user2.group(:name => "Gross people")
+      
+      request = @user.send_friend_request_to( @user2.receive_url, @group.id)
+      request.reverse @user2 
+      @user2.activate_friend(@user.person, @group2)
+      @user.receive request.to_diaspora_xml
+    end
+
+    it 'should unfriend the other user on the same seed' do
+      @user.reload
+      @user2.reload
+
+      @user.friends.count.should == 1
+      @user2.friends.count.should == 1
+      
+      @user.person.user_refs.should == 1
+
+      @user2.person.user_refs.should == 1
+
+      @user2.unfriend @user.person
+      @user2.friends.count.should be 0
+
+      @user.person.reload
+      @user.person.user_refs.should == 0 
+
+      @user.unfriended_by @user2.person
+
+      @user2.person.reload
+      @user2.person.user_refs.should == 0
+
+      @group.reload
+      @group2.reload
+      @group.people.count.should == 0
+      @group2.people.count.should == 0
+    end
+  end
 end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 9eba3000c0b762a42dacd51f26ca4373d115261b..fb730c6db0feb91f720d02ea8f06ef4da7ef787e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -71,3 +71,7 @@ end
     end
     models
   end
+
+  def message_queue
+    Post.send(:class_variable_get, :@@queue)
+  end
diff --git a/spec/user_encryption_spec.rb b/spec/user_encryption_spec.rb
index 729920af265efb745a4d35be9c33ed4eb15252a6..fde3cf5a8de4c838d89365b9234f54c504c4909e 100644
--- a/spec/user_encryption_spec.rb
+++ b/spec/user_encryption_spec.rb
@@ -3,16 +3,10 @@ include ApplicationHelper
 include Diaspora::Parser
 
 describe 'user encryption' do
-  before :all do
-    #ctx = GPGME::Ctx.new
-    #keys = ctx.keys
-    #keys.each{|k| ctx.delete_key(k, true)}
-    
-  end
   before do
     unstub_mocha_stubs
     @user = Factory.create(:user)
-    @user.save
+    @group = @user.group(:name => 'dudes')
     @person = Factory.create(:person_with_private_key,
       :profile => Profile.new(:first_name => 'Remote',
                               :last_name => 'Friend'),
@@ -33,28 +27,28 @@ describe 'user encryption' do
     #keys.each{|k| ctx.delete_key(k, true)}
   end
   it 'should have a key' do
-    @user.key.should_not be nil
+    @user.encryption_key.should_not be nil
   end
   describe 'key exchange on friending' do
-       it 'should send over a public key' do
-      Comment.send(:class_variable_get, :@@queue).stub!(:add_post_request)
-      request = @user.send_friend_request_to("http://example.com/")
-      Request.build_xml_for([request]).include?( @user.export_key).should be true
+    it 'should send over a public key' do
+      message_queue.stub!(:add_post_request)
+      request = @user.send_friend_request_to("http://example.com/", @group.id)
+      request.to_diaspora_xml.include?( @user.export_key).should be true
     end
 
     it 'should receive and marshal a public key from a request' do
       person = Factory.build(:person, :url => "http://test.url/" )
-      person.key.nil?.should== false
+      person.encryption_key.nil?.should== false
       #should move this to friend request, but i found it here 
       id = person.id
       original_key = person.export_key
       
       request = Request.instantiate(:to =>"http://www.google.com/", :from => person)
       
-      xml = Request.build_xml_for [request]
+      xml = request.to_diaspora_xml
       person.destroy
       personcount = Person.all.count
-      store_objects_from_xml(xml)
+      @user.receive xml
       Person.all.count.should == personcount + 1
       new_person = Person.first(:url => "http://test.url/")
       new_person.id.should == id
@@ -65,9 +59,20 @@ describe 'user encryption' do
   describe 'signing and verifying' do
 
     it 'should sign a message on create' do
-      message = Factory.create(:status_message, :person => @user)
+      message = @user.post :status_message, :message => "hi"
       message.verify_creator_signature.should be true 
     end
+
+    it 'should sign a retraction on create' do
+
+      unstub_mocha_stubs
+      message = @user.post :status_message, :message => "hi"
+
+
+      retraction = Retraction.for(message)
+      retraction.verify_creator_signature.should be true
+
+    end
     
     it 'should not be able to verify a message from a person without a key' do 
       person = Factory.create(:person, :serialized_key => "lskdfhdlfjnh;klsf")
@@ -78,7 +83,7 @@ describe 'user encryption' do
     
     it 'should verify a remote signature' do 
       message = Factory.build(:status_message, :person => @person)
-      message.creator_signature = message.send(:sign_with_key,@person.key)
+      message.creator_signature = message.send(:sign_with_key,@person.encryption_key)
       message.save(:validate => false)
       message.verify_creator_signature.should be true
     end
@@ -86,14 +91,14 @@ describe 'user encryption' do
     it 'should know if the signature is from the wrong person' do
       message = Factory.build(:status_message, :person => @person)
       message.save(:validate => false)
-      message.creator_signature = message.send(:sign_with_key,@person.key)
+      message.creator_signature = message.send(:sign_with_key,@person.encryption_key)
       message.person = @user
       message.verify_creator_signature.should be false
     end
    
     it 'should know if the signature is for the wrong text' do
       message = Factory.build(:status_message, :person => @person)
-      message.creator_signature = message.send(:sign_with_key,@person.key)
+      message.creator_signature = message.send(:sign_with_key,@person.encryption_key)
       message.message = 'I love VENISON'
       message.save(:validate => false)
       message.verify_creator_signature.should be false
@@ -102,18 +107,22 @@ describe 'user encryption' do
 
   describe 'sending and recieving signatures' do
     it 'should contain the signature in the xml' do
-      message = Factory.create(:status_message, :person => @user)
+      message = @user.post :status_message, :message => "hi"
       xml = message.to_xml.to_s
       xml.include?(message.creator_signature).should be true
     end
+
     it 'A message with an invalid signature should be rejected' do
-      message = Factory.build(:status_message, :person => @person)
-      message.creator_signature = message.send(:sign )
-      message.save
-      xml = Post.build_xml_for([message])
+      @user2 = Factory.create :user
+
+      message = @user2.post :status_message, :message => "hey"
+      message.creator_signature = "totally valid"
+      message.save(:validate => false)
+
+      xml = message.to_diaspora_xml
       message.destroy
       Post.count.should be 0
-      store_objects_from_xml(xml)
+      @user.receive xml
       Post.count.should be 0
     end
 
@@ -121,9 +130,9 @@ describe 'user encryption' do
   describe 'comments' do
     before do
       @remote_message = Factory.build(:status_message, :person => @person)
-      @remote_message.creator_signature = @remote_message.send(:sign_with_key,@person.key)
+      @remote_message.creator_signature = @remote_message.send(:sign_with_key,@person.encryption_key)
       @remote_message.save 
-      @message = Factory.create(:status_message, :person => @user)
+      @message = @user.post :status_message, :message => "hi"
     end
     it 'should attach the creator signature if the user is commenting' do
       @user.comment "Yeah, it was great", :on => @remote_message
@@ -131,25 +140,25 @@ describe 'user encryption' do
     end
 
     it 'should sign the comment if the user is the post creator' do
-      message = Factory.create(:status_message, :person => @user)
+      message = @user.post :status_message, :message => "hi"
       @user.comment "Yeah, it was great", :on => message
       message.comments.first.verify_creator_signature.should be true
-      StatusMessage.first(:message => message.message).comments.first.verify_post_creator_signature.should be true
+      message.comments.first.verify_post_creator_signature.should be true
     end
     
     it 'should verify a comment made on a remote post by a different friend' do
       comment = Comment.new(:person => @person2, :text => "balls", :post => @remote_message)
-      comment.creator_signature = comment.send(:sign_with_key,@person2.key)
+      comment.creator_signature = comment.send(:sign_with_key,@person2.encryption_key)
       comment.verify_creator_signature.should be true
       comment.valid?.should be false
-      comment.post_creator_signature = comment.send(:sign_with_key,@person.key)
+      comment.post_creator_signature = comment.send(:sign_with_key,@person.encryption_key)
       comment.verify_post_creator_signature.should be true
       comment.valid?.should be true
     end
 
     it 'should reject comments on a remote post with only a creator sig' do
         comment = Comment.new(:person => @person2, :text => "balls", :post => @remote_message)
-        comment.creator_signature = comment.send(:sign_with_key,@person2.key)
+        comment.creator_signature = comment.send(:sign_with_key,@person2.encryption_key)
         comment.verify_creator_signature.should be true
         comment.verify_post_creator_signature.should be false
         comment.save.should be false
@@ -157,7 +166,7 @@ describe 'user encryption' do
 
     it 'should receive remote comments on a user post with a creator sig' do
         comment = Comment.new(:person => @person2, :text => "balls", :post => @message)
-        comment.creator_signature = comment.send(:sign_with_key,@person2.key)
+        comment.creator_signature = comment.send(:sign_with_key,@person2.encryption_key)
         comment.save.should be true
     end
 
diff --git a/test/selenium/post_and_delete_status_message_not_testing_websocket b/test/selenium/post_and_delete_status_message_not_testing_websocket
deleted file mode 100644
index bb1cbf7da30103e0b7266c609465af765871c094..0000000000000000000000000000000000000000
--- a/test/selenium/post_and_delete_status_message_not_testing_websocket
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="selenium.base" href="http://tom.joindiaspora.com/" />
-<title>post_and_delete_status_message_not_testing_websocket</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
-<thead>
-<tr><td rowspan="1" colspan="3">post_and_delete_status_message_not_testing_websocket</td></tr>
-</thead><tbody>
-<tr>
-	<td>open</td>
-	<td>/login</td>
-	<td></td>
-</tr>
-<tr>
-	<td>type</td>
-	<td>user_password</td>
-	<td>evankorth</td>
-</tr>
-<tr>
-	<td>clickAndWait</td>
-	<td>user_submit</td>
-	<td></td>
-</tr>
-<tr>
-	<td>type</td>
-	<td>status_message_message</td>
-	<td>THIS IS A RUNNING SELENIUM TEST AAAAAAAAH</td>
-</tr>
-<tr>
-	<td>click</td>
-	<td>status_message_submit</td>
-	<td></td>
-</tr>
-<tr>
-	<td>refreshAndWait</td>
-	<td></td>
-	<td></td>
-</tr>
-<tr>
-	<td>verifyTextPresent</td>
-	<td>THIS IS A RUNNING SELENIUM TEST AAAAAAAAH</td>
-	<td></td>
-</tr>
-<tr>
-	<td>click</td>
-	<td>link=Delete</td>
-	<td></td>
-</tr>
-<tr>
-	<td>assertConfirmation</td>
-	<td>Are you sure?</td>
-	<td></td>
-</tr>
-<tr>
-	<td>refreshAndWait</td>
-	<td></td>
-	<td></td>
-</tr>
-<tr>
-	<td>verifyTextNotPresent</td>
-	<td>THIS IS A RUNNING SELENIUM TEST AAAAAAAAH</td>
-	<td></td>
-</tr>
-<tr>
-	<td>clickAndWait</td>
-	<td>link=logout</td>
-	<td></td>
-</tr>
-
-</tbody></table>
-</body>
-</html>