diff --git a/.gitignore b/.gitignore
index a17dc3a1be140e1c960e02fd5ef65b11003626ed..b09f9b136cc9e72993f2ddd54ada34685b7eff13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 # Configuration files
 config/app_config.yml
 config/fb_config.yml
+config/oauth_keys.yml
 config/initializers/secret_token.rb
 .bundle
 vendor/bundle/*
diff --git a/Gemfile b/Gemfile
index bd90c0a4657d2d8c5114c0e7524c59d3120cbe4b..cd11c7ceb911c4e2730c7a4e1bc984f4b1118a78 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,6 +9,10 @@ gem "chef"
 gem 'devise', '1.1.3'
 gem 'devise-mongo_mapper', :git => 'git://github.com/collectiveidea/devise-mongo_mapper'
 gem 'devise_invitable', '~> 0.3.4'
+
+#Authentication
+gem 'omniauth'
+gem 'twitter'
 #Mongo
 gem 'mongo_mapper', :branch => 'rails3', :git => 'git://github.com/jnunemaker/mongomapper.git'
 gem 'bson_ext', '1.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 8f325e5ca83dd637fbf84cd11ebd794ca7871413..1abff88d14a068f57082a6dfa1d7e16f5a29c8eb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -169,6 +169,9 @@ GEM
     factory_girl_rails (1.0)
       factory_girl (~> 1.3)
       rails (>= 3.0.0.beta4)
+    faraday (0.4.6)
+      addressable (>= 2.1.1)
+      rack (>= 1.0.1)
     ffi (0.6.3)
       rake (>= 0.8.7)
     gherkin (2.2.9)
@@ -178,6 +181,8 @@ GEM
     hashie (0.4.0)
     highline (1.6.1)
     http_connection (1.4.0)
+    httparty (0.6.1)
+      crack (= 0.1.8)
     i18n (0.4.1)
     json (1.4.6)
     json_pure (1.4.6)
@@ -205,6 +210,8 @@ GEM
     moneta (0.6.0)
     mongo (1.1)
       bson (>= 1.0.5)
+    multi_json (0.0.4)
+    net-ldap (0.1.1)
     net-scp (1.0.4)
       net-ssh (>= 1.99.1)
     net-sftp (2.0.5)
@@ -213,6 +220,33 @@ GEM
     net-ssh-gateway (1.0.1)
       net-ssh (>= 1.99.1)
     nokogiri (1.4.3.1)
+    oa-basic (0.1.5)
+      multi_json (~> 0.0.2)
+      nokogiri (~> 1.4.2)
+      oa-core (= 0.1.5)
+      rest-client (~> 1.6.0)
+    oa-core (0.1.5)
+      rack (~> 1.1)
+    oa-enterprise (0.1.5)
+      net-ldap (~> 0.1.1)
+      nokogiri (~> 1.4.2)
+      oa-core (= 0.1.5)
+      pyu-ruby-sasl (~> 0.0.3.1)
+      rubyntlm (~> 0.1.1)
+    oa-oauth (0.1.5)
+      multi_json (~> 0.0.2)
+      nokogiri (~> 1.4.2)
+      oa-core (= 0.1.5)
+      oauth (~> 0.4.0)
+      oauth2 (~> 0.0.10)
+    oa-openid (0.1.5)
+      oa-core (= 0.1.5)
+      rack-openid (~> 1.1.1)
+      ruby-openid-apps-discovery
+    oauth (0.4.3)
+    oauth2 (0.0.13)
+      faraday (~> 0.4.1)
+      multi_json (>= 0.0.4)
     ohai (0.5.8)
       extlib
       json (>= 1.4.4, <= 1.4.6)
@@ -220,15 +254,25 @@ GEM
       mixlib-config
       mixlib-log
       systemu
+    omniauth (0.1.5)
+      oa-basic (= 0.1.5)
+      oa-core (= 0.1.5)
+      oa-enterprise (= 0.1.5)
+      oa-oauth (= 0.1.5)
+      oa-openid (= 0.1.5)
     plucky (0.3.6)
       mongo (~> 1.1)
     polyglot (0.3.1)
     pubsubhubbub (0.1.1)
       em-http-request (>= 0.1.5)
       eventmachine (>= 0.12.9)
+    pyu-ruby-sasl (0.0.3.2)
     rack (1.2.1)
     rack-mount (0.6.13)
       rack (>= 1.0.0)
+    rack-openid (1.1.2)
+      rack (>= 0.4)
+      ruby-openid (>= 2.0.3)
     rack-test (0.5.6)
       rack (>= 1.0)
     rails (3.0.1)
@@ -264,6 +308,10 @@ GEM
       ruby-debug-base (~> 0.10.3.0)
     ruby-debug-base (0.10.3)
       linecache (>= 0.3)
+    ruby-openid (2.1.8)
+    ruby-openid-apps-discovery (1.2.0)
+      ruby-openid (>= 2.1.7)
+    rubyntlm (0.1.1)
     rubyzip (0.9.4)
     selenium-webdriver (0.0.29)
       childprocess (>= 0.0.7)
@@ -280,6 +328,11 @@ GEM
     thor (0.14.3)
     treetop (1.4.8)
       polyglot (>= 0.3.1)
+    twitter (0.9.12)
+      hashie (~> 0.4.0)
+      httparty (~> 0.6.1)
+      multi_json (~> 0.0.4)
+      oauth (~> 0.4.3)
     tzinfo (0.3.23)
     uuidtools (2.1.1)
     warden (0.10.7)
@@ -318,6 +371,7 @@ DEPENDENCIES
   mini_magick
   mocha
   mongo_mapper!
+  omniauth
   pubsubhubbub
   rails (>= 3.0.0)
   redfinger!
@@ -327,5 +381,6 @@ DEPENDENCIES
   ruby-debug
   sprinkle!
   thin
+  twitter
   webmock
   will_paginate (= 3.0.pre2)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 137705df418e93625ab4be732edac8fb4083a957..df08808aea9510cc828ba9f5afbd1a5810c9ad90 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -8,7 +8,6 @@ class ApplicationController < ActionController::Base
 
   before_filter :set_friends_and_status, :except => [:create, :update]
   before_filter :count_requests
-  before_filter :fb_user_info
   before_filter :set_invites
 
   layout :layout_by_resource
@@ -44,16 +43,4 @@ class ApplicationController < ActionController::Base
       @invites = current_user.invites
     end
   end
-
-  def fb_user_info
-    if current_user
-      @access_token = warden.session[:access_token]
-      @logged_in = @access_token.present?
-    end
-  end
-
-  def logged_into_fb?
-    @logged_in
-  end
-
 end
diff --git a/app/controllers/aspects_controller.rb b/app/controllers/aspects_controller.rb
index ddde8a7257834c578394fbb972b5fda9418634ec..0129c0abfb438e6daf6da3e7dd2f1d000a8aecae 100644
--- a/app/controllers/aspects_controller.rb
+++ b/app/controllers/aspects_controller.rb
@@ -11,9 +11,6 @@ class AspectsController < ApplicationController
   def index
     @posts = current_user.visible_posts(:by_members_of => :all).paginate :page => params[:page], :per_page => 15, :order => 'created_at DESC'
     @aspect = :all
-
-    @fb_access_url = MiniFB.oauth_url(FB_APP_ID, APP_CONFIG[:pod_url] + "services/create",
-                                      :scope=>MiniFB.scopes.join(","))
   end
 
   def create
@@ -56,15 +53,6 @@ class AspectsController < ApplicationController
     end
   end
 
-  def public
-   # @fb_access_url = MiniFB.oauth_url(FB_APP_ID, APP_CONFIG[:pod_url] + "services/create",
-    #                                  :scope=>MiniFB.scopes.join(","))
-
-    @posts = current_user.visible_posts(:person_id => current_user.person.id, :public => true).paginate :page => params[:page], :per_page => 15, :order => 'created_at DESC'
-
-    respond_with @aspect
-  end
-
   def manage
     @aspect = :manage
     @remote_requests = current_user.requests_for_me
diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb
index 97f52cef2a532ae89bbad98c94e5ef3156062004..7c5da42a7892ce81812e62806a569b7529f51cb6 100644
--- a/app/controllers/services_controller.rb
+++ b/app/controllers/services_controller.rb
@@ -4,37 +4,42 @@
 
 
 class ServicesController < ApplicationController
+  before_filter :authenticate_user!
 
-  def create
-    puts 'services/create'
-    p params
-
-    code = params['code'] # Facebooks verification string
-    if code
-      access_token_hash = MiniFB.oauth_access_token(FB_APP_ID, APP_CONFIG[:pod_url] + "services/create", FB_SECRET, code)
-      p access_token_hash
-      @access_token = access_token_hash["access_token"]
-
-      # TODO: This is where you'd want to store the token in your database
-      # but for now, we'll just keep it in the session so we don't need a database
-      warden.session[:access_token] = @access_token
-      flash[:success] = "Authentication successful."
-    end
-    redirect_to edit_user_url current_user
+  def index
+    @services = current_user.services
   end
 
-  def destroy
-    warden.session[:access_token] = nil
-		warden.session[:user_id] = nil
-    redirect_to edit_user_url current_user
-  end
+  def create
+    auth = request.env['omniauth.auth']
+
+    provider = auth['provider']
+    user     = auth['user_info']
+
+    if provider == 'twitter'
+      access_token = auth['extra']['access_token']
+      current_user.services.create(:nickname => user['nickname'],
+                                   :access_token => access_token.token, 
+                                   :access_secret => access_token.secret,
+                                   :provider => provider, 
+                                   :uid => auth['uid'])
+                                   
+    elsif provider == 'facebook'
+      current_user.services.create(:nickname => user['nickname'],
+                                   :access_token => auth['credentials']['token'],
+                                   :provider => provider, 
+                                   :uid => auth['uid'])
+    end
 
-  def fb_post
-    id = 'me'
-    type = 'feed'
 
-    @res = MiniFB.post(@access_token, id, :type=>type, :metadata=>true, :params=>params)
-    redirect_to edit_user_url current_user
+    flash[:notice] = "Authentication successful."
+    redirect_to services_url
   end
 
+  def destroy
+    @service = current_user.services.find(params[:id])
+    @service.destroy
+    flash[:notice] = "Successfully destroyed authentication."
+    redirect_to services_url
+  end
 end
diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb
index 5268184721f5ec9713e5a5145a5d3ef6fb7377ca..a5c018af237fd78d07186e2b72594d59607a06e8 100644
--- a/app/controllers/status_messages_controller.rb
+++ b/app/controllers/status_messages_controller.rb
@@ -9,13 +9,13 @@ class StatusMessagesController < ApplicationController
   respond_to :json, :only => :show
 
   def create
-    data = clean_hash params[:status_message]
-
-    if logged_into_fb? && params[:status_message][:public] == '1'
-      current_user.post_to_message_fb(params[:status_message][:message], @access_token)
-    end
+    public_flag = params[:status_message][:public]
+    public_flag.to_s.match(/(true)/) ? public_flag = true : public_flag = false
+    params[:status_message][:public] = public_flag 
 
-    @status_message = current_user.post(:status_message, data)
+    data = clean_hash params[:status_message]
+    message = params[:status_message][:message]
+    status_message = current_user.post(:status_message, data)
     render :nothing => true
   end
 
@@ -27,11 +27,7 @@ class StatusMessagesController < ApplicationController
 
   def show
     @status_message = current_user.find_visible_post_by_id params[:id]
-    unless @status_message
-      render :status => 404
-    else
-      respond_with @status_message
-    end
+    respond_with @status_message
   end
 
   private
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index aacff850431a9f2c7c1113c2d1b1b0125b6d69dd..9c1bb3e9cb2009a49e730427401156f04692bd1e 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -19,9 +19,6 @@ class UsersController < ApplicationController
     @person  = @user.person
     @profile = @user.person.profile
     @photos  = current_user.visible_posts(:person_id => current_user.person.id, :_type => 'Photo').paginate :page => params[:page], :order => 'created_at DESC'
-
-    @fb_access_url = MiniFB.oauth_url(FB_APP_ID, APP_CONFIG[:pod_url] + "services/create",
-                                      :scope=>MiniFB.scopes.join(","))
   end
 
   def update
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 8851f3c8e57e8375a72b51cf481231a087e59345..869d49a9838eedbea40c7550350c75ea053fecad 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -78,9 +78,4 @@ module ApplicationHelper
   def post_yield_tag(post)
     (':' + post.id.to_s).to_sym
   end
-
-  def connected_fb_as token
-    response_hash = MiniFB.get(token, 'me')
-    "Connected to facebook as #{response_hash[:name]}"
-  end
 end
diff --git a/app/models/fb_status.rb b/app/models/fb_status.rb
deleted file mode 100644
index 7076cbd3138b0b72f1951d8ea46824dc40ae93fa..0000000000000000000000000000000000000000
--- a/app/models/fb_status.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-#   Copyright (c) 2010, Diaspora Inc.  This file is
-#   licensed under the Affero General Public License version 3 or later.  See
-#   the COPYRIGHT file.
-
-
-class FbStatus
-  include MongoMapper::Document
-
-  key :graph_id, String
-  key :author_id, String
-  key :author_name, String
-  key :message, String
-  key :updated_time, Time
-
-  timestamps!
-
-  validates_presence_of :graph_id,:author_id,:author_name,:message,:updated_time
-
-  def self.from_api(hash)
-    #just keeping them in memory for now
-    self.new(
-                  :graph_id     => hash['id'],
-                  :author_id    => hash['from']['id'],
-                  :author_name  => hash['from']['name'],
-                  :message      => hash['message'],
-                  :updated_time => Time.parse(hash['updated_time'])
-            )
-  end
-end
diff --git a/app/models/service.rb b/app/models/service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1b64f013edfcc13fa9368e09273012a235d6a57a
--- /dev/null
+++ b/app/models/service.rb
@@ -0,0 +1,15 @@
+#   Copyright (c) 2010, Diaspora Inc.  This file is
+#   licensed under the Affero General Public License version 3 or later.  See
+#   the COPYRIGHT file.
+
+class Service
+  include MongoMapper::Document
+
+  belongs_to :user
+
+  key :provider, String
+  key :uid, String
+  key :access_token, String
+  key :access_secret, String
+  key :nickname, String
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 343cc2d76d210fd6e72b51429f453e58af5bf7f6..6a184b1566c7786b0e725788e05da554ad7c2d59 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -61,6 +61,8 @@ class User
   many :raw_visible_posts, :in => :visible_post_ids, :class_name => 'Post'
   many :aspects, :class_name => 'Aspect', :dependent => :destroy
 
+  many :services, :class_name => "Service"
+
   #after_create :seed_aspects
 
   before_destroy :unfriend_everyone, :remove_person
@@ -149,21 +151,29 @@ class User
 
     aspect_ids = validate_aspect_permissions(aspect_ids)
 
-    intitial_post(class_name, aspect_ids, options)
+    post = build_post(class_name, options)
+    post.socket_to_uid(id, :aspect_ids => aspect_ids) if post.respond_to?(:socket_to_uid)
+    push_to_aspects(post, aspect_ids)
+    
+    if options[:public] == true
+      self.services.each do |service|
+        self.send("post_to_#{service.provider}".to_sym, service, post.message)
+      end
+    end
+
+    post
   end
 
-  def post_to_message_fb(message, access_token)
-    id = 'me'
-    type = 'feed'
+  def post_to_facebook(service, message)
     Rails.logger.info("Sending a message: #{message} to Facebook")
-    EventMachine::HttpRequest.new("https://graph.facebook.com/me/feed?message=#{message}&access_token=#{access_token}").post
+    EventMachine::HttpRequest.new("https://graph.facebook.com/me/feed?message=#{message}&access_token=#{service.access_token}").post
   end
 
-  def intitial_post(class_name, aspect_ids, options = {})
-    post = build_post(class_name, options)
-    post.socket_to_uid(id, :aspect_ids => aspect_ids) if post.respond_to?(:socket_to_uid)
-    push_to_aspects(post, aspect_ids)
-    post
+  def post_to_twitter(service, message)
+    oauth = Twitter::OAuth.new(SERVICES['twitter']['consumer_token'], SERVICES['twitter']['consumer_secret'])
+    oauth.authorize_from_access(service.access_token, service.access_secret)
+    client = Twitter::Base.new(oauth)
+    client.update(message)
   end
 
   def update_post(post, post_hash = {})
diff --git a/app/views/services/index.html.haml b/app/views/services/index.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..5bec5593368e3d0835664b987877e67813c0a189
--- /dev/null
+++ b/app/views/services/index.html.haml
@@ -0,0 +1,28 @@
+-#   Copyright (c) 2010, Diaspora Inc.  This file is
+-#   licensed under the Affero General Public License version 3 or later.  See
+-#   the COPYRIGHT file.
+
+#section_header
+  %h2
+    Settings
+  %ul#settings_nav
+    %li=link_to 'Profile', '#', :class => 'profile'
+    %li=link_to 'Account', '#', :class => 'account'
+    %li=link_to 'Services', services_path
+
+.span-19.prepend-5.last
+  %h2
+    Services
+
+  %ul#stream
+    - for service in @services
+      %h3
+        %b= service.provider
+        logged in as
+        %b
+          = service.nickname
+        = link_to "disconnect", service, :confirm => "disconnect #{service.provider}?", :method => :delete
+
+  %h4= link_to "Connect to twitter", "/auth/twitter" if SERVICES['twitter']['consumer_key']!= ""
+  %h4= link_to "Connect to facebook", "/auth/facebook" if SERVICES['facebook']['app_id'] !=""
+
diff --git a/app/views/shared/_aspect_friends.haml b/app/views/shared/_aspect_friends.haml
index c44d88e6b4c24f36f58318957c35c44e957f92f7..f4b2f06f72336158b12169e1d0dd7464782330a7 100644
--- a/app/views/shared/_aspect_friends.haml
+++ b/app/views/shared/_aspect_friends.haml
@@ -15,11 +15,6 @@
     - for friend in @friends
       = person_image_link(friend)
 
-    - if @logged_in && (@aspect == :public)
-      %h3 Facebook Friends
-      - @fb_friends = MiniFB.get(@access_token, 'me', :type => "friends")
-      - @fb_friends[:data].each do |friend|
-        = image_tag( "http://graph.facebook.com/#{friend[:id]}/picture" )
     -unless (@aspect == :all)
       = link_to (image_tag('add_friend_button.png', :title => "add to #{@aspect}")), "#add_request_pane", :id => 'add_request_button'
 
diff --git a/app/views/shared/_public_explain.haml b/app/views/shared/_public_explain.haml
index ca1a2b1d7878bbe3daa9a96f5ef5df20f3670701..3d7e7f64473ffec179d4af83e3f2be0e7a5b2fc7 100644
--- a/app/views/shared/_public_explain.haml
+++ b/app/views/shared/_public_explain.haml
@@ -9,10 +9,14 @@
     Public messages will be available for others outside of Diaspora to see.
     %br
     %br
-    - if @logged_in
-      = connected_fb_as(@access_token)
-    - else
-      = link_to "Connect to Facebook", @fb_access_url
+
+    - if current_user.services
+      - for service in current_user.services 
+        = "logged in to #{service.provider}"
+        %br
+
+    = link_to "manage connected services", services_path
+
     %br
     %br
     = link_to "OK", '#', :class => "button", :onClick => '$.fancybox.close();'
diff --git a/app/views/shared/_publisher.haml b/app/views/shared/_publisher.haml
index 56ac9e440187db87ae73a1aad085ad2e33183400..4ac7c5392a7878b0b305a74b3a2a3b66a8091470 100644
--- a/app/views/shared/_publisher.haml
+++ b/app/views/shared/_publisher.haml
@@ -2,20 +2,22 @@
 -#   licensed under the Affero General Public License version 3 or later.  See
 -#   the COPYRIGHT file.
 
-:javascript
-  $("div.public_toggle input").live("click", function(evt){
-    if("#{@logged_in}" == "false" && $(this).attr('checked') == true){
-      $(".question_mark").click(); 
-    }; 
-  });
-  
-  $("#publisher textarea, #publisher input").live("focus", function(evt){
-    $("#publisher .options_and_submit").fadeIn(50);
-  });
-
-  $("#publisher form").live("submit", function(evt){
-    $("#publisher .options_and_submit").hide();
-  });
+
+- content_for :head do
+  :javascript
+    $("div.public_toggle input").live("click", function(evt){
+      if($(this).attr('checked') == true){
+        $(".question_mark").click(); 
+      }; 
+    });
+    
+    $("#publisher textarea, #publisher input").live("focus", function(evt){
+      $("#publisher .options_and_submit").fadeIn(50);
+    });
+
+    $("#publisher form").live("submit", function(evt){
+      $("#publisher .options_and_submit").hide();
+    });
 
 #publisher
   = owner_image_tag
@@ -33,7 +35,7 @@
     
         - if aspect == :all
           .public_toggle
-            = status.check_box( :public, :value => false )
+            = status.check_box( :public, {}, true, false )
             make public
             = link_to '(?)', "#question_mark_pane", :class => 'question_mark'
 
diff --git a/app/views/users/_services.haml b/app/views/users/_services.haml
deleted file mode 100644
index a9a6d7977b5b78a020e070f95cb66c7e40dde9af..0000000000000000000000000000000000000000
--- a/app/views/users/_services.haml
+++ /dev/null
@@ -1,26 +0,0 @@
--#   Copyright (c) 2010, Diaspora Inc.  This file is
--#   licensed under the Affero General Public License version 3 or later.  See
--#   the COPYRIGHT file.
-
-
-%h2 Services
-
-- if FACEBOOK
-  %h3 Facebook
-  %p
-    - if @logged_in
-      = connected_fb_as(@access_token)
-
-      %p
-      - @fb_friends = MiniFB.get(@access_token, 'me', :type => "friends")
-      - @fb_friends[:data].each do |friend|
-        = image_tag( "http://graph.facebook.com/#{friend[:id]}/picture" )
-
-      = link_to "Disconnect from Facebook", services_destroy_path
-    - else
-      = link_to "Connect to Facebook", @fb_access_url
-
-  #content_bottom
-    .back
-      = link_to "⇧ home", root_path
-
diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml
index 48b266c09cd3f0ffd46176fdbb7a5c85b5446e36..104a9e8fdd6fc6428f6697e863ed7023056d8ea0 100644
--- a/app/views/users/edit.html.haml
+++ b/app/views/users/edit.html.haml
@@ -18,7 +18,7 @@
   %ul#settings_nav
     %li=link_to 'Profile', '#', :class => 'profile'
     %li=link_to 'Account', '#', :class => 'account'
-    %li=link_to 'Services', '#', :class => 'services'
+    %li=link_to 'Services', services_path
 
 .span-19.prepend-5.last
   #profile.settings_pane{:style=>"display:block;"}
@@ -27,6 +27,3 @@
   #account.settings_pane
     = render 'users/account'
 
-  #services.settings_pane
-    = render 'users/services'
-
diff --git a/config/deploy.rb b/config/deploy.rb
index b4893ec93748366e93d7a075af73c88527ec5b70..09d8c0bc31be9eff4cefc0114c2d1fc3b9865a6f 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -56,9 +56,9 @@ namespace :deploy do
     run "ln -s -f #{shared_path}/app_config.yml #{current_path}/config/app_config.yml"
   end
 
-  task :symlink_fb_config do
-    run "touch #{shared_path}/fb_config.yml"
-    run "ln -s -f #{shared_path}/fb_config.yml #{current_path}/config/fb_config.yml"
+  task :symlink_oauth_keys_config do
+    run "touch #{shared_path}/oauth_keys.yml"
+    run "ln -s -f #{shared_path}/oauth_keys.yml #{current_path}/config/oauth_keys.yml"
   end
 
    task :start do
@@ -157,4 +157,4 @@ namespace :db do
 
 end
 
-after "deploy:symlink", "deploy:symlink_images", "deploy:symlink_bundle", 'deploy:symlink_config', 'deploy:symlink_fb_config'
+after "deploy:symlink", "deploy:symlink_images", "deploy:symlink_bundle", 'deploy:symlink_config', 'deploy:symlink_oauth_keys_config'
diff --git a/config/fb_config.yml b/config/fb_config.yml
deleted file mode 100644
index 4c3309fac7d1cc71a65136229ae6bf68bb017178..0000000000000000000000000000000000000000
--- a/config/fb_config.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-fb_api_key: {dcf4e90df086cf6d3e531b31e043ff32}
-fb_secret: {7fe864834726f8a5e65bc93928b99a53}
-fb_app_id: {120373411325347}
-host: http://localhost:3000/
diff --git a/config/fb_config.yml.example b/config/fb_config.yml.example
deleted file mode 100644
index 5bb1453166122f79fc718a368831c0d0bf5eab35..0000000000000000000000000000000000000000
--- a/config/fb_config.yml.example
+++ /dev/null
@@ -1,4 +0,0 @@
-fb_api_key: {key}
-fb_secret: {secret}
-fb_app_id: {app_id}
-host: http://localhost:3000/
diff --git a/config/initializers/_load_services.rb b/config/initializers/_load_services.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e893ce9aef9824a42157f438c39947e1d4de1274
--- /dev/null
+++ b/config/initializers/_load_services.rb
@@ -0,0 +1,19 @@
+#   Copyright (c) 2010, Diaspora Inc.  This file is
+#   licensed under the Affero General Public License version 3 or later.  See
+#   the COPYRIGHT file.
+
+def load_config_yaml filename
+  YAML.load(File.read(filename))
+end
+
+oauth_keys_file = "#{Rails.root}/config/oauth_keys.yml"
+
+
+SERVICES = nil
+silence_warnings do
+  if File.exist? oauth_keys_file
+    SERVICES = load_config_yaml(oauth_keys_file)
+  else
+    SERVICES = load_config_yaml("#{oauth_keys_file}.example")
+  end
+end
\ No newline at end of file
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a9253f6c2f1cced9a38c9aec0c93b37b91eae5a9
--- /dev/null
+++ b/config/initializers/omniauth.rb
@@ -0,0 +1,9 @@
+#   Copyright (c) 2010, Diaspora Inc.  This file is
+#   licensed under the Affero General Public License version 3 or later.  See
+#   the COPYRIGHT file.
+
+Rails.application.config.middleware.use OmniAuth::Builder do
+  provider :twitter, SERVICES['twitter']['consumer_key'], SERVICES['twitter']['consumer_secret']
+  provider :facebook, SERVICES['facebook']['app_id'], SERVICES['facebook']['app_secret']
+end  
+
diff --git a/config/oauth_keys.yml.example b/config/oauth_keys.yml.example
new file mode 100644
index 0000000000000000000000000000000000000000..8e1db632a890000d032628b2e7e79f9a20103824
--- /dev/null
+++ b/config/oauth_keys.yml.example
@@ -0,0 +1,6 @@
+twitter:
+  consumer_key: ""
+  consumer_secret: ""
+facebook:
+  app_id: ""
+  app_secret: ""
diff --git a/config/routes.rb b/config/routes.rb
index 7364f901617830cb6e755c7d436a70554c034a0c..b9b05ca6528b5e3faa18632ef7fa566dec3b9c5f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -9,28 +9,26 @@ Diaspora::Application.routes.draw do
   resources :requests,        :except => [:edit, :update]
   resources :photos,          :except => [:index]
   resources :albums
+  resources :services
+
+  match '/auth/:provider/callback' => 'services#create'
 
   devise_for :users, :controllers => {:registrations => "registrations",
                                       :password      => "devise/passwords",
-                                      :invitations    => "invitations"}
+                                      :invitations   => "invitations"}
   # added public route to user
   match 'public/:username',        :to => 'users#public'
   match 'users/export',            :to => 'users#export'
   match 'users/import',            :to => 'users#import'
   match 'users/export_photos',     :to => 'users#export_photos'
-  resources :users,         :except => [:create, :new, :show]
+  resources :users,                :except => [:create, :new, :show]
 
   match 'aspects/move_friend',  :to => 'aspects#move_friend', :as => 'move_friend'
   match 'aspects/add_to_aspect',:to => 'aspects#add_to_aspect', :as => 'add_to_aspect'
   match 'aspects/remove_from_aspect',:to => 'aspects#remove_from_aspect', :as => 'remove_from_aspect'
   match 'aspects/manage',       :to => 'aspects#manage'
-  match 'aspects/public',       :to => 'aspects#public'
   resources :aspects,           :except => [:edit]
 
-  match 'services/create',    :to   => "services#create"
-  match 'services/destroy',   :to   => "services#destroy"
-  match 'services/fb_post',   :to   => "services#fb_post"
-
   match 'warzombie',          :to   => "dev_utilities#warzombie"
   match 'zombiefriends',      :to   => "dev_utilities#zombiefriends"
   match 'zombiefriendaccept', :to   => "dev_utilities#zombiefriendaccept"
diff --git a/pkg/Licenses b/pkg/Licenses
new file mode 100644
index 0000000000000000000000000000000000000000..cc8f337418abab47654e5b47ebda8c9c68685bf0
--- /dev/null
+++ b/pkg/Licenses
@@ -0,0 +1,99 @@
+
+abstract:		Ruby
+actionmailer:		MIT
+actionpack:		MIT
+activemodel:		MIT
+activerecord:		MIT
+activeresource:		?   (Other distros uses MIT, "Ruby-alike", no pointers)
+activesupport:		MIT
+addressable:		MIT
+arel:			MIT
+aws			MIT
+bcrypt-ruby:		MIT
+builder:		MIT
+bunny:			MIT
+capistrano:		MIT
+capybara:		MIT
+chef:			ASL 2.0
+childprocess:		MIT
+columnize: 		GPLv2
+crack:			MIT
+cucumber:		MIT
+cucumber-rails:         MIT
+culerity:		MIT
+daemons:		Ruby+MIT
+database_cleaner:	MIT
+devise:			MIT
+devise_invitable	MIT
+diff			Ruby+GPLv2+ Artistic 2.0
+em-websocket:		MIT
+eribus:			MIT
+event-machine:		Ruby+GPLv2
+extlib:			MIT
+factory_girls           MIT
+factory_girls_rails:	MIT
+ffi			MIT
+haml			MIT
+http_connection:	MIT
+gherkin:		MIT
+hashie:			MIT
+highline		GPLv2+Ruby
+json: 			Ruby
+json-pure: 		Ruby
+launchy:		MIT
+linecache:		GPLv2
+mail:			MIT
+mime-types:		GPLv2+Ruby+Artistic 2.0
+mini_magick:		MIT
+mini_fb:		?
+mixlib-authentication:  ASL 2.0
+mixlib-cli              ASL 2.0
+mixlib-config           ASL 2.0
+mixlib-log              ASL 2.0
+mocha			Ruby+MIT
+moneta:			MIT
+mongo:			ASL 2.0
+net-scp:		MIT
+net-sftp:		MIT
+net-ssh:		MIT
+net-ssh-gatawey:	MIT
+ohai:			ASL 2.0
+plucky:			MIT
+polyglot.		MIT
+pubsubhubbub:           ASL 2.0  http://code.google.com/p/pubsubhubbub/
+rake:			MIT
+rack-mount:             MIT
+rack-test:		MIT
+railties:		MIT
+rest-client:		MIT
+rspec-core:		MIT
+rspec-expectations:	MIT
+rspec-mocks:       	MIT
+rspec-rails:       	MIT
+rack:			MIT
+rack-mount:		MIT
+ruby-debug:		MIT
+ruby-debug-base:	MIT
+rubyzip:		Ruby
+selenium-webdriver:	ASL 2.0
+subexec:		MIT
+term-ansicolor: 	GPLv2
+textile.		MIT
+textile-warden:		MIT
+thin:			MIT
+thor:			MIT
+treetop:		MIT
+tx-info:		MIT
+uutdtools:		MIT
+iwarden:		MIT
+webmock:		MIT
+will-paginate		MIT
+
+
+
+
+
+
+
+
+
diff --git a/pkg/fedora/.gitignore b/pkg/fedora/.gitignore
index bedbdc76076f5c4c63f61dd26aa4f50f56099a07..2a21dd54dd0095065bfef5ccadf9d4f55a0bd710 100644
--- a/pkg/fedora/.gitignore
+++ b/pkg/fedora/.gitignore
@@ -1,3 +1,4 @@
 TODO
 dist
 .stgit*
+vendor
diff --git a/pkg/fedora/diaspora-bundle.spec b/pkg/fedora/diaspora-bundle.spec
index dee189a2604de958ef3bad1fe7953f2ca9dd8e49..a13a853688b3b210205331af95daf48164a6c992 100644
--- a/pkg/fedora/diaspora-bundle.spec
+++ b/pkg/fedora/diaspora-bundle.spec
@@ -38,9 +38,16 @@ Source file usede to compile native libraries in diaspora-bundle.
 %setup -q -n %{name}-%{version}-%{git_release}
 
 %build
-mkdir -p vendor/cache
-mv *.gem vendor/cache
-bundle install --local --deployment --without ri rdoc
+bundle install --local --deployment --without ri rdoc test
+for gem in vendor/git/*; do
+    gem install --local   \
+                --force   \
+                --no-rdoc \
+                --no-ri   \
+                --install-dir vendor/bundle/ruby/1.8/bundler \
+    $gem
+
+done
 
 pushd vendor/bundle/ruby/1.8/gems
     # In repo (2.2.4)
@@ -200,7 +207,7 @@ popd
 }
 
 mkdir -p $RPM_BUILD_ROOT/%{_libdir}/diaspora-bundle
-cp -ar  vendor/bundle  $RPM_BUILD_ROOT/%{_libdir}/diaspora-bundle
+cp -ar  vendor  $RPM_BUILD_ROOT/%{_libdir}/diaspora-bundle
 
 find  %{buildroot}/%{_libdir}/diaspora-bundle  \
     -type d  -fprintf dirs '%%%dir "%%p"\n'
@@ -218,7 +225,7 @@ cat files >> dirs && cp dirs files
 
 %files -f files
 %defattr(-, diaspora, diaspora, 0755)
-%doc  COPYRIGHT Gemfile Gemfile.lock AUTHORS GNU-AGPL-3.0
+%doc  COPYRIGHT Gemfile Gemfile.lock AUTHORS GNU-AGPL-3.0 docs
 
 %files -f dev-files devel
 %defattr(-, root, root, 0644)
diff --git a/pkg/fedora/diaspora.spec b/pkg/fedora/diaspora.spec
index 1d61026e5d29206c9bc3ebee886ac2bd64045aa8..8a30492c8aef5ce93e718709c244bad165300963 100644
--- a/pkg/fedora/diaspora.spec
+++ b/pkg/fedora/diaspora.spec
@@ -49,13 +49,12 @@ find . -perm /u+x -type f -exec \
 
 %build
 rm -rf master/vendor/bundle
-mkdir master/tmp || :
 
 %install
 rm -fr $RPM_BUILD_ROOT
 
 sed -i \
-    '/BUNDLE_PATH/s|:.*|: %{_libdir}/diaspora-bundle/bundle|' \
+    '/BUNDLE_PATH/s|:.*|: %{_libdir}/diaspora-bundle/vendor/bundle|' \
      master/.bundle/config
 
 cp master/GNU-AGPL-3.0 master/COPYRIGHT master/README.md master/AUTHORS .
diff --git a/pkg/fedora/make-dist.sh b/pkg/fedora/make-dist.sh
index 3da2ab6e398f4bf2df40c3f3978eaa41a59460fb..2ff8c9ef20cbade5aa7766345df0f84a3f5f3049 100755
--- a/pkg/fedora/make-dist.sh
+++ b/pkg/fedora/make-dist.sh
@@ -138,7 +138,7 @@ function checkout()
         cd diaspora;
         git fetch --quiet upstream
         git merge --quiet upstream/master
-        git checkout --quiet  ${1:-'HEAD'}
+        [ -n "$1" ] && git reset --hard  --quiet  $1
         git_id  -n
     )
 }
@@ -175,41 +175,91 @@ function make_src
     echo "Required bundle:     $(git_id dist/diaspora/Gemfile)"
 }
 
-function get_git_repos()
+
+function build_git_gems()
+# Usage: build_git_gems <Gemfile> <tmpdir> <gemdir>
+# Horrible hack, in wait for bundler handling git gems OK.
 {
-    grep -A 2 GIT $1 |
-        awk   ' /remote:/   { repo = $2 }
-                /revision:/ { printf "%s=%s\n",repo, $2}'
+    mkdir gem-tmp || :
+    cd gem-tmp
+    rm -rf *
+
+    grep 'git:'  ../$1 |  sed 's/,/ /' | awk '
+       /^.*git:\/\/.*$/  {
+                    gsub( "=>", "")
+                    gsub( ",", "")
+                    if ( $1 != "gem") {
+                          print "Strange git: line (ignored) :" $0
+                          next
+                    }
+                    name = $2
+                    suffix = ""
+                    url=""
+                    for (i = 3; i <= NF; i += 1) {
+                        key = $i
+                        i += 1
+                        if (key == ":git")
+                            url = $i
+                        else if ( key == ":ref") {
+                            suffix =  "; cd " name
+                            suffix = suffix "; git reset --hard " $i
+                            suffix = suffix "; cd .."
+                        }
+                        else if ( key == ":branch")
+                            suffix = "; git checkout " $i
+                    }
+                    print "Running: ", cmd
+                    cmd =  sprintf( "git clone --quiet %s %s %s\n",
+                                     url, name, suffix)
+                    system( cmd)
+                }'
+    sed -i 's/Date.today/"2010-10-24"/' carrierwave/carrierwave.gemspec
+    for dir in *; do
+        cd $dir
+        gem build *.gemspec
+        cp *.gem ../../$2
+        cd ..
+    done
+
+    cd ..
+    # rm -rf gem-tmp
 }
 
+function make_docs()
+{
+    local gemfile=$1
+    for url in $(read_git_urls $gemfile); do
+        local name=${url##*/}
+        name=${name%.*}
+        rm -rf vendor/git/$name
+        git clone --bare --quiet $url vendor/git/$name &&
+            sed -i "s#$url#vendor/git/$name#" $gemfile ||
+                echo "Cannot fix git repo \"$url\""
+    done
+}
 
-function package_git_gems()
+function make_docs()
 {
-    gemfile="$1"
-    dest="$2"
-
-    rm -rf git-tmp
-    mkdir git-tmp
-    cd git-tmp
-        for repo in $( get_git_repos $1); do
-            url=${repo%%=*}
-            rev=${repo##*=}
-
-            name=${url##*/}
-            name="${name%.git}"
-
-            rm -rf "$name"
-            git clone "$url" "$name"
-            cd $name
-                git reset --hard  $rev
-                sed -i '/s.date/s/Date.today/"2010-09-25"/' *.gemspec
-                gem build *.gemspec
-                cp *.gem $dest
-                echo "Built GIT gem $name (*.gem)"
-                echo "Where: $dest"
-            cd ..
-        done
-    cd ..
+    local gems=$1
+    local dest=$2
+
+    for gem in $(ls $gems); do
+        local name=$(basename $gem)
+        [ -r $gems/$gem/README* ] && {
+             local readme=$(basename $gems/$gem/README*)
+             cp  -a $gems/$gem/$readme $dest/$readme.$name
+        }
+        [ -r $gems/$gem/COPYRIGHT ] && \
+             cp -a $gems/$gem/COPYRIGHT $dest/COPYRIGHT.$name
+        [ -r $gems/$gem/LICENSE ] && \
+             cp -a $gems/$gem/LICENSE $dest/LICENSE.$name
+        [ -r $gems/$gem/License ] && \
+             cp -a $gems/$gem/License $dest/License.$name
+        [ -r $gems/$gem/MIT-LICENSE ] && \
+             cp -a $gems/$gem/MIT-LICENSE $dest/MIT-LICENSE.$name
+        [ -r $gems/$gem/COPYING ] && \
+             cp -a $gems/$gem/COPYING $dest/COPYING.$name
+    done
 }
 
 
@@ -219,8 +269,8 @@ function make_bundle()
 #
 {
     checkout ${1:-'HEAD'} >/dev/null
-    bundle_id=$( git_id dist/diaspora/Gemfile)
-    bundle_name="diaspora-bundle-$VERSION-$bundle_id"
+    local bundle_id=$( git_id dist/diaspora/Gemfile)
+    local bundle_name="diaspora-bundle-$VERSION-$bundle_id"
     test -e  "dist/$bundle_name.tar.gz" || {
         echo "Creating bundle $bundle_name"
         cd dist
@@ -231,22 +281,25 @@ function make_bundle()
                     rm -rf .bundle
                     bundle update
                 fi
-                bundle install --deployment
+                [ -d 'vendor/git' ] || mkdir  vendor/git
+                bundle install
                 bundle package
-                package_git_gems "$PWD/Gemfile.lock" "$PWD/vendor/cache"
+                mkdir vendor/git
+                build_git_gems  Gemfile vendor/git
+
+                mkdir  -p "../$bundle_name/docs"
+                mkdir -p "../$bundle_name/vendor"
                 cp -ar AUTHORS Gemfile Gemfile.lock GNU-AGPL-3.0 COPYRIGHT \
-                       vendor/cache
-                cd vendor
-                    mv cache $bundle_name
-                    tar czf ../../$bundle_name.tar.gz $bundle_name
-                    mv $bundle_name cache
-                cd ..
+                    ../$bundle_name
+                make_docs "vendor/gems"  "../$bundle_name/docs"
+                mv vendor/cache ../$bundle_name/vendor
             cd ..
+            tar czf $bundle_name.tar.gz $bundle_name
+            mv $bundle_name/vendor/cache diaspora/vendor/cache
         cd ..
     }
     echo
     echo "Bundle: dist/$bundle_name.tar.gz"
-    echo "Current dir:$PWD"
 }
 
 
diff --git a/pkg/ubuntu/diaspora-bundle-install b/pkg/ubuntu/diaspora-bundle-install
index 88924b9309027b238203e6d88abba54b756e7f1e..65ae9520e8d99934a1c81ee0f2bd7857c3660c8d 100755
--- a/pkg/ubuntu/diaspora-bundle-install
+++ b/pkg/ubuntu/diaspora-bundle-install
@@ -23,11 +23,18 @@ mv $(basename $1 .tar.gz) diaspora-bundle
 
 mkdir -p /usr/share/doc/diaspora-bundle || :
 cd /usr/lib/diaspora-bundle
-cp AUTHORS GNU-AGPL-3.0 COPYRIGHT Gemfile Gemfile.lock \
+cp -a AUTHORS GNU-AGPL-3.0 COPYRIGHT Gemfile Gemfile.lock \
      /usr/share/doc/diaspora-bundle
-
-mkdir -p vendor/cache
-mv *.gem vendor/cache
+cp -ar docs /usr/share/doc/diaspora-bundle
 
 bundle install --local --deployment --without ri rdoc
+for gem in vendor/git/*; do
+    gem install --local   \
+                --force   \
+                --no-rdoc \
+                --no-ri   \
+                --install-dir vendor/bundle/ruby/1.8/bundler \
+    $gem
+done
+
 
diff --git a/public/javascripts/aspect-edit.js b/public/javascripts/aspect-edit.js
index 9e565e4b2ead1e87e21cbbbfe4a16124a61bdb19..4b6f1c42173dabaa1bd7fa324387e57fe3410adc 100644
--- a/public/javascripts/aspect-edit.js
+++ b/public/javascripts/aspect-edit.js
@@ -25,8 +25,12 @@ $(function() {
     revert: true,
     start: function(event,ui){
       $(this).children("img").animate({'height':80, 'width':80, 'opacity':0.8},200);
+      $(this).children("img").tipsy("hide");
       $(".draggable_info").fadeIn(100);
     },
+    drag: function(event,ui){
+      $(this).children("img").tipsy("hide"); //ensure this is hidden
+    },
     stop: function(event,ui){
       $(this).children("img").animate({'height':70, 'width':70, 'opacity':1},200);
       $(".draggable_info").fadeOut(100);
diff --git a/public/javascripts/view.js b/public/javascripts/view.js
index 0b3987d53c587c5c445b2bae33e3af88f3b42d75..26b3fea5515f342d9c1df9b857201019572ebaf6 100644
--- a/public/javascripts/view.js
+++ b/public/javascripts/view.js
@@ -76,6 +76,7 @@ $(document).ready(function(){
 
   $("img", "#left_pane").tipsy({live:true});
   $(".add_aspect_button", "#aspect_nav").tipsy({gravity:'w'});
+  $(".person img", ".dropzone").tipsy({live:true});
 
 });//end document ready
 
diff --git a/spec/controllers/albums_controller_spec.rb b/spec/controllers/albums_controller_spec.rb
index 5c53f1909eb21b2eaec3e8f39aa1df0706eb4634..74bec40453dc92be2ae741695329fab84e8aba05 100644
--- a/spec/controllers/albums_controller_spec.rb
+++ b/spec/controllers/albums_controller_spec.rb
@@ -14,7 +14,6 @@ describe AlbumsController do
   end
 
   it "should update the name of an album" do
-    sign_in :user, @user
     put :update, :id => @album.id, :album => { :name => "new_name"}
     @album.reload.name.should eql("new_name")
   end
diff --git a/spec/controllers/services_controller_spec.rb b/spec/controllers/services_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0c19c1e23310cf9c787278a2a6a96df36e37d1d6
--- /dev/null
+++ b/spec/controllers/services_controller_spec.rb
@@ -0,0 +1,48 @@
+#   Copyright (c) 2010, Diaspora Inc.  This file is
+#   licensed under the Affero General Public License version 3 or later.  See
+#   the COPYRIGHT file.
+
+require 'spec_helper'
+
+describe ServicesController do
+  render_views
+  let(:user) { Factory(:user) }
+  let!(:aspect) { user.aspect(:name => "lame-os") }
+
+  let!(:service1) {a = Factory(:service); user.services << a; a}
+  let!(:service2) {a = Factory(:service); user.services << a; a}
+  let!(:service3) {a = Factory(:service); user.services << a; a}
+  let!(:service4) {a = Factory(:service); user.services << a; a}
+
+  let(:mock_access_token) { Object.new }
+
+  let(:omniauth_auth) {{ 'provider' => 'twitter', 'uid' => '2', 
+                         'user_info' => { 'nickname' => 'grimmin' },
+                         'extra' => { 'access_token' => mock_access_token }}}
+
+  before do
+    sign_in :user, user
+    mock_access_token.stub!(:token).and_return("12345")
+    mock_access_token.stub!(:secret).and_return("56789")
+  end
+
+  describe '#index' do
+    it 'displays all connected serivices for a user' do
+      get :index
+      assigns[:services].should == user.services
+    end
+  end
+
+  describe '#create' do
+    it 'creates a new OmniauthService' do
+      request.env['omniauth.auth'] = omniauth_auth
+      lambda{post :create}.should change(user.services, :count).by(1)
+    end
+  end
+
+  describe '#destroy' do
+    it 'should destroy a service of a users with the id' do
+      lambda{delete :destroy, :id => service1.id.to_s}.should change(user.services, :count).by(-1)
+    end
+  end
+end
diff --git a/spec/controllers/status_message_controller_spec.rb b/spec/controllers/status_message_controller_spec.rb
index 9c84fe3e8c366ad395e9119698def79a7b21a1ff..0869972b3c22b885561f0745d51638e1a6137236 100644
--- a/spec/controllers/status_message_controller_spec.rb
+++ b/spec/controllers/status_message_controller_spec.rb
@@ -12,27 +12,40 @@ describe StatusMessagesController do
 
   before do
     sign_in :user, user
+    @controller.stub!(:current_user).and_return(user)
   end
 
   describe '#create' do
-   let(:status_message_hash) {{"status_message"=>{"public"=>"1", "message"=>"facebook, is that you?", "to" =>"#{aspect.id}"}}}
-    
-   before do
-     @controller.stub!(:logged_into_fb?).and_return(true)
-   end
-
-   it 'should post to facebook when public is set' do
-     my_mock = mock("http")
-     my_mock.stub!(:post)
-     EventMachine::HttpRequest.should_receive(:new).and_return(my_mock)
-     post :create, status_message_hash
-   end
-   
-   it 'should not post to facebook when public in not set' do
-     status_message_hash['status_message']['public'] = '0'
-     EventMachine::HttpRequest.should_not_receive(:new)
-     post :create, status_message_hash
-   end
+    let(:status_message_hash) {{"status_message"=>{"public"=>"true", "message"=>"facebook, is that you?", "to" =>"#{aspect.id}"}}}
+
+    context "posting out to facebook" do
+      let!(:service2) { s = Factory(:service, :provider => 'facebook'); user.services << s; s }
+
+      it 'should post to facebook when public is set' do
+        user.should_receive(:post_to_facebook)
+        post :create, status_message_hash
+      end
+
+      it 'should not post to facebook when public is not set' do
+        status_message_hash['status_message']['public'] = 'false'
+        user.should_not_receive(:post_to_facebook)
+        post :create, status_message_hash
+      end
+    end
+
+    context "posting to twitter" do
+      let!(:service1) { s = Factory(:service, :provider => 'twitter'); user.services << s; s }
+
+      it 'should post to twitter if public is set' do
+        user.should_receive(:post_to_twitter).and_return(true)
+        post :create, status_message_hash
+      end
+
+      it 'should not post to twitter when public in not set' do
+        status_message_hash['status_message']['public'] = 'false'
+        user.should_not_receive(:post_to_twitter)
+        post :create, status_message_hash
+      end
+    end
   end
 end
-
diff --git a/spec/factories.rb b/spec/factories.rb
index 8d0b76aee2593b9a50b8fc31bf25c64bf520a666..32d74793706f9c3553a9f5f57f46e492807db2ff 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -52,29 +52,19 @@ Factory.define :status_message do |m|
   m.person
 end
 
-Factory.define :blog do |b|
-  b.sequence(:title) {|n| "bobby's #{n} penguins"}
-  b.sequence(:body) {|n| "jimmy's huge #{n} whales"}
-end
-
-Factory.define :bookmark do |b|
-  b.link "http://www.yahooligans.com/"
-end
+Factory.define :photo do |p|
+  p.image File.open( File.dirname(__FILE__) + '/fixtures/button.png')
 
-Factory.define :post do |p|
 end
 
-Factory.define :photo do |p|
-  p.image File.open( File.dirname(__FILE__) + '/fixtures/button.png')
+Factory.define :service do |service|
+  service.nickname "sirrobertking"
+  service.provider "twitter"
 
+  service.sequence(:uid)           { |token| "00000#{token}" }
+  service.sequence(:access_token)  { |token| "12345#{token}" }
+  service.sequence(:access_secret) { |token| "98765#{token}" }
 end
 
 Factory.define(:comment) {}
 
-Factory.define :fb_status do |s|
-   s.graph_id "367501354973"
-   s.author_name "Bret Taylor"
-   s.author_id "220439"
-   s.message "Pigs run from our house in fear. Tonight, I am wrapping the pork tenderloin in bacon and putting pancetta in the corn."
-   s.updated_time Time.parse "2010-03-06T02:57:48+0000"
-end
diff --git a/spec/fixtures/fb_status b/spec/fixtures/fb_status
deleted file mode 100644
index 5602e8343c35a4be0ccd9bb10b846de4773fd4eb..0000000000000000000000000000000000000000
--- a/spec/fixtures/fb_status
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-   "id": "367501354973",
-   "from": {
-      "name": "Bret Taylor",
-      "id": "220439"
-   },
-   "message": "Pigs run from our house in fear. Tonight, I am wrapping the pork tenderloin in bacon and putting pancetta in the corn.",
-   "updated_time": "2010-03-06T02:57:48+0000",
-   "likes": {
-      "data": [
-         {
-            "id": "29906278",
-            "name": "Ross Miller"
-         }
-      ]
-   },
-   "comments": {
-      "data": [
-         {
-            "id": "367501354973_12216733",
-            "from": {
-               "name": "Doug Edwards",
-               "id": "628675309"
-            },
-            "message": "Make sure you don't, as they say, go whole hog...\nhttp://www.youtube.com/watch?v=U4wTFuaV8VQ",
-            "created_time": "2010-03-06T03:24:46+0000"
-         },
-         {
-            "id": "367501354973_12249673",
-            "from": {
-               "name": "Tom Taylor",
-               "id": "1249191863"
-            },
-            "message": "Are you and Karen gonna, as they say, pig out?",
-            "created_time": "2010-03-06T21:05:21+0000"
-         },
-         {
-            "id": "367501354973_12249857",
-            "from": {
-               "name": "Sheila Taylor",
-               "id": "1315606682"
-            },
-            "message": "how did it turn out?  Sounds nummy!\n",
-            "created_time": "2010-03-06T21:10:30+0000"
-         },
-         {
-            "id": "367501354973_12250973",
-            "from": {
-               "name": "Bret Taylor",
-               "id": "220439"
-            },
-            "message": "Mom: turned out well. Sauce was good as well: pan sauce with mustard, balsamic, onion, and maple syrup. Surprisingly good in the end, and not too sweet, which was my concern. ",
-            "created_time": "2010-03-06T21:44:53+0000"
-         },
-         {
-            "id": "367501354973_12251276",
-            "from": {
-               "name": "Sheila Taylor",
-               "id": "1315606682"
-            },
-            "message": "Sounds delicious!  I probably would have skipped the maple syrup, but I am not married to a Canadian :)\n\nSheila Taylor\n(925) 818-7795\nP.O. Box 938\nGlen Ellen, CA 95442\nwww.winecountrytrekking.com",
-            "created_time": "2010-03-06T21:55:12+0000"
-         },
-         {
-            "id": "367501354973_12264435",
-            "from": {
-               "name": "Amelia Ann Arapoff",
-               "id": "1580390378"
-            },
-            "message": "Bacon is always in our refrigerator, in case of need, somehow there is always need.",
-            "created_time": "2010-03-07T05:11:52+0000"
-         }
-      ],
-      "paging": {
-         "previous": "https://graph.facebook.com/367501354973/comments?access_token=2227470867%7C2.wNlupL2HPsOtrlYFBF56NA__.3600.1285354800-100001548997697%7C8lZ_pdgNDvSHYS4o1OkqhdQu6mA&limit=25&since=2010-03-07T05%3A11%3A52%2B0000",
-         "next": "https://graph.facebook.com/367501354973/comments?access_token=2227470867%7C2.wNlupL2HPsOtrlYFBF56NA__.3600.1285354800-100001548997697%7C8lZ_pdgNDvSHYS4o1OkqhdQu6mA&limit=25&until=2010-03-06T03%3A24%3A45%2B0000"
-      }
-   }
-}
\ No newline at end of file
diff --git a/spec/lib/encryptor_spec.rb b/spec/lib/encryptor_spec.rb
index e993dac458f6f27af9bf8b22d65935f66bb372ec..3e6df211d032bf0a254cbe7a34d7a35b058524e9 100644
--- a/spec/lib/encryptor_spec.rb
+++ b/spec/lib/encryptor_spec.rb
@@ -42,13 +42,11 @@ describe 'user encryption' do
   end
 
   describe 'encryption' do
-    before do
-      @string = File.open(File.dirname(__FILE__) + '/../fixtures/fb_status').read
-    end
     it 'should encrypt a string' do
-      ciphertext = @user.encrypt @string
-      ciphertext.include?(@string).should be false
-      @user.decrypt(ciphertext).should == @string
+      string = "Secretsauce"
+      ciphertext = @user.encrypt string
+      ciphertext.include?(string).should be false
+      @user.decrypt(ciphertext).should == string
     end
   end
 end
diff --git a/spec/models/fb_status_spec.rb b/spec/models/fb_status_spec.rb
deleted file mode 100644
index 7d46d9553d85c042865a1b28440ef3a058ae9ae7..0000000000000000000000000000000000000000
--- a/spec/models/fb_status_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-#   Copyright (c) 2010, Diaspora Inc.  This file is
-#   licensed under the Affero General Public License version 3 or later.  See
-#   the COPYRIGHT file.
-
-
-
-require File.join(Rails.root,'spec/spec_helper')
-
-
-describe FbStatus do
-
-  let(:fb_status) { Factory.create :fb_status }
-
-  it 'is valid' do
-    fb_status.should be_valid
-  end
-
-  describe '#from_api' do
-    let!(:json_string) {File.open(File.dirname(__FILE__) + '/../fixtures/fb_status').read}
-    let!(:json_object) { JSON.parse(json_string) }
-    let!(:status_from_json) {FbStatus.from_api(json_object)}
-
-    it 'has graph_id' do
-      status_from_json.graph_id.should == json_object['id']
-    end
-
-    it 'has author_id' do
-      status_from_json.author_id.should == json_object['from']['id']
-    end
-
-    it 'has author_name' do
-      status_from_json.author_name.should == json_object['from']['name']
-    end
-
-    it 'has message' do
-      status_from_json.message.should == json_object['message']
-    end
-
-    it 'has author_name' do
-      status_from_json.updated_time.should == Time.parse(json_object['updated_time'])
-    end
-  end
-
-end
diff --git a/spec/models/user/posting_spec.rb b/spec/models/user/posting_spec.rb
index 70438bbeceef0023d48980d3747aa3c57053fd91..5e1b115aef87ff16e9afcf793a390b2f4160438f 100644
--- a/spec/models/user/posting_spec.rb
+++ b/spec/models/user/posting_spec.rb
@@ -7,12 +7,16 @@ require 'spec_helper'
 describe User do
 
   let!(:user) { Factory(:user) }
+  let!(:user2) { Factory(:user) }
+
   let!(:aspect) { user.aspect(:name => 'heroes') }
   let!(:aspect1) { user.aspect(:name => 'other') }
-
-  let!(:user2) { Factory(:user) }
   let!(:aspect2) { user2.aspect(:name => 'losers') }
 
+  let!(:service1) { s = Factory(:service, :provider => 'twitter'); user.services << s; s }
+  let!(:service2) { s = Factory(:service, :provider => 'facebook'); user.services << s; s }
+
+
   describe '#validate_aspect_permissions' do
     it 'requires an aspect' do
       proc {
@@ -44,11 +48,26 @@ describe User do
       aspect.reload
       aspect.posts.should include album
     end
+
     it "should add the post to that user's visible posts" do
       status_message = user.post :status_message, :message => "hi", :to => aspect.id
       user.reload
       user.raw_visible_posts.include?(status_message).should be true
     end
+
+    it "posts to services if post is public" do
+      message = "hello, world!"
+      user.should_receive(:post_to_twitter).with(service1, message).exactly(1).times
+      user.should_receive(:post_to_facebook).with(service2, message).exactly(1).times
+      user.post :status_message, :message => message, :to => "all", :public => true
+    end
+
+    it "does not post to services if post is not public" do
+      user.should_receive(:post_to_twitter).exactly(0).times
+      user.should_receive(:post_to_facebook).exactly(0).times
+      user.post :status_message, :message => "hi", :to => "all"
+    end
+
   end
 
   describe '#update_post' do