tweetable 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +8 -0
- data/History.txt +4 -0
- data/Manifest.txt +33 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +37 -0
- data/Rakefile +19 -0
- data/VERSION +1 -0
- data/lib/tweetable/authorization.rb +21 -0
- data/lib/tweetable/collection.rb +54 -0
- data/lib/tweetable/link.rb +30 -0
- data/lib/tweetable/message.rb +119 -0
- data/lib/tweetable/persistable.rb +32 -0
- data/lib/tweetable/photo.rb +6 -0
- data/lib/tweetable/queue.rb +121 -0
- data/lib/tweetable/search.rb +77 -0
- data/lib/tweetable/twitter_client.rb +36 -0
- data/lib/tweetable/twitter_streaming_client.rb +67 -0
- data/lib/tweetable/url.rb +39 -0
- data/lib/tweetable/user.rb +104 -0
- data/lib/tweetable.rb +82 -0
- data/pkg/tweetable-0.1.7.gem +0 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/collection_spec.rb +55 -0
- data/spec/fixtures/blank.json +1 -0
- data/spec/fixtures/flippyhead.json +1 -0
- data/spec/fixtures/follower_ids.json +1 -0
- data/spec/fixtures/friend_ids.json +1 -0
- data/spec/fixtures/friends_timeline.json +1 -0
- data/spec/fixtures/link_blank.json +1 -0
- data/spec/fixtures/link_exists.json +1 -0
- data/spec/fixtures/rate_limit_status.json +1 -0
- data/spec/fixtures/search.json +1 -0
- data/spec/fixtures/user_timeline.json +1 -0
- data/spec/fixtures/verify_credentials.json +1 -0
- data/spec/link_spec.rb +35 -0
- data/spec/message_spec.rb +148 -0
- data/spec/persistable_spec.rb +53 -0
- data/spec/queue_spec.rb +29 -0
- data/spec/search_spec.rb +60 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/tweetable_spec.rb +19 -0
- data/spec/twitter_client_spec.rb +41 -0
- data/spec/twitter_streaming_client_spec.rb +18 -0
- data/spec/user_spec.rb +143 -0
- data/tweetable.gemspec +106 -0
- metadata +165 -0
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            # require 'yajl'
         | 
| 2 | 
            +
            require 'crack'
         | 
| 3 | 
            +
            require 'crack/json'
         | 
| 4 | 
            +
            require 'net/http'
         | 
| 5 | 
            +
            require 'cgi'
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
            module Tweetable
         | 
| 8 | 
            +
              class URL  
         | 
| 9 | 
            +
                LONG_URL_API_URL = 'http://www.longurlplease.com/api/v1.1'  
         | 
| 10 | 
            +
                LONG_URL_TIMEOUT = 5  
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
                def self.headers  
         | 
| 13 | 
            +
                  { "Content-Type" => 'application/json' }  
         | 
| 14 | 
            +
                end  
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
                # the api can handle multiple url queries and response, but this does just 1  
         | 
| 17 | 
            +
                def self.lookup_long_url(search)  
         | 
| 18 | 
            +
                  url = URI.parse(LONG_URL_API_URL)  
         | 
| 19 | 
            +
                  url.query = "q=#{CGI.escape(search)}"  
         | 
| 20 | 
            +
                     
         | 
| 21 | 
            +
                  http = Net::HTTP.new(url.host, url.port)  
         | 
| 22 | 
            +
                  http.read_timeout = LONG_URL_TIMEOUT  
         | 
| 23 | 
            +
                    
         | 
| 24 | 
            +
                  long_url = nil
         | 
| 25 | 
            +
                  begin
         | 
| 26 | 
            +
                    json = http.get(url.to_s, headers).body
         | 
| 27 | 
            +
                    urls =  Crack::JSON.parse(json)
         | 
| 28 | 
            +
                    long_url = urls.values[0]
         | 
| 29 | 
            +
                  rescue Crack::ParseError
         | 
| 30 | 
            +
                    raise TweetableError.new("Error parsing json trying to get long URL: #{json.to_s}")        
         | 
| 31 | 
            +
                  rescue Timeout::Error => e
         | 
| 32 | 
            +
                    raise TweetableError.new("Timeout trying to get long URL: #{e}")
         | 
| 33 | 
            +
                  rescue Exception => e      
         | 
| 34 | 
            +
                    raise TweetableError.new("Error trying to get long URL: #{e}")
         | 
| 35 | 
            +
                  end      
         | 
| 36 | 
            +
                  long_url.nil? ? search : long_url
         | 
| 37 | 
            +
                end   
         | 
| 38 | 
            +
              end  
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,104 @@ | |
| 1 | 
            +
            module Tweetable
         | 
| 2 | 
            +
              class User < Persistable
         | 
| 3 | 
            +
                attribute :created_at
         | 
| 4 | 
            +
                attribute :updated_at    
         | 
| 5 | 
            +
                attribute :screen_name
         | 
| 6 | 
            +
                attribute :profile_image_url
         | 
| 7 | 
            +
                attribute :user_id
         | 
| 8 | 
            +
                attribute :friends_count
         | 
| 9 | 
            +
                attribute :followers_count
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                index :screen_name
         | 
| 12 | 
            +
                index :user_id
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
                list :messages, Message
         | 
| 15 | 
            +
                list :friend_messages, Message
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                set :friend_ids
         | 
| 18 | 
            +
                set :follower_ids
         | 
| 19 | 
            +
                set :tags
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                def self.create_from_timeline(user)
         | 
| 22 | 
            +
                  u = User.find_or_create(:screen_name, user.screen_name.downcase)
         | 
| 23 | 
            +
                  u.update(
         | 
| 24 | 
            +
                    :user_id => user[:id],
         | 
| 25 | 
            +
                    :profile_image_url => user.profile_image_url,
         | 
| 26 | 
            +
                    :followers_count => user.followers_count, 
         | 
| 27 | 
            +
                    :friends_count => user.friends_count)
         | 
| 28 | 
            +
                  u
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                def update_all(force = false)
         | 
| 32 | 
            +
                  return unless needs_update?(force)
         | 
| 33 | 
            +
                  update_info if self.config[:include_on_update].include?(:info)
         | 
| 34 | 
            +
                  update_friend_ids if self.config[:include_on_update].include?(:friend_ids)
         | 
| 35 | 
            +
                  update_follower_ids if self.config[:include_on_update].include?(:follower_ids)
         | 
| 36 | 
            +
                  update_friend_messages if self.config[:include_on_update].include?(:friend_messages)
         | 
| 37 | 
            +
                  self.update(:updated_at => Time.now.utc.to_s)            
         | 
| 38 | 
            +
                  self.config[:include_on_update].include?(:messages) ? update_messages : []  # return newly found messages
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              
         | 
| 41 | 
            +
                def update_info
         | 
| 42 | 
            +
                  uid  = self.user_id.blank? ? self.screen_name : self.user_id
         | 
| 43 | 
            +
                  info = self.client.user(uid)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  self.user_id = info[:id]
         | 
| 46 | 
            +
                  self.screen_name = info[:screen_name].downcase
         | 
| 47 | 
            +
                  self.profile_image_url = info[:profile_image_url]
         | 
| 48 | 
            +
                  self.friends_count = info[:friends_count]
         | 
| 49 | 
            +
                  self.followers_count = info[:followers_count]      
         | 
| 50 | 
            +
                  self.save
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                def update_friend_ids    
         | 
| 54 | 
            +
                  fids = self.client.friend_ids(:screen_name => self.screen_name, :page => 1) # limit to 5000 friend ids      
         | 
| 55 | 
            +
                  fids.each{|fid| self.friend_ids << fid}
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              
         | 
| 58 | 
            +
                def update_follower_ids
         | 
| 59 | 
            +
                  fids = self.client.follower_ids(:screen_name => self.screen_name, :page => 1) # limit to 5000 friend ids
         | 
| 60 | 
            +
                  fids.each{|fid| self.follower_ids << fid}
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                        
         | 
| 63 | 
            +
                def update_messages(options = {})      
         | 
| 64 | 
            +
                  most_recent_message = self.messages.first(:order => 'DESC', :by => :message_id) 
         | 
| 65 | 
            +
                  options.merge!(:count => self.config[:max_message_count], :screen_name => self.screen_name)
         | 
| 66 | 
            +
                  options[:since_id] = most_recent_message.message_id if most_recent_message
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  timeline = self.client.user_timeline(options)
         | 
| 69 | 
            +
                  build_messages(timeline, self.messages)
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
                
         | 
| 72 | 
            +
                def update_friend_messages(options = {})
         | 
| 73 | 
            +
                  most_recent_message = self.friend_messages.first(:order => 'DESC', :by => :message_id) 
         | 
| 74 | 
            +
                  options.merge!(:count => self.config[:max_message_count], :screen_name => self.screen_name)
         | 
| 75 | 
            +
                  options[:since_id] = most_recent_message.message_id if most_recent_message
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  timeline = self.client.friends_timeline(options)      
         | 
| 78 | 
            +
                  build_messages(timeline, self.friend_messages, :create_user => true)
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                def twitter_link
         | 
| 82 | 
            +
                  "http://twitter.com/#{screen_name}"
         | 
| 83 | 
            +
                end    
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                private 
         | 
| 86 | 
            +
                def build_messages(timeline, collection, options = {})
         | 
| 87 | 
            +
                  new_messages = []
         | 
| 88 | 
            +
                  
         | 
| 89 | 
            +
                  timeline.each do |message|
         | 
| 90 | 
            +
                    m = Message.create_from_timeline(message, options[:create_user])
         | 
| 91 | 
            +
                    next if !m.valid?
         | 
| 92 | 
            +
                    collection << m
         | 
| 93 | 
            +
                    new_messages << m      
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                  
         | 
| 96 | 
            +
                  new_messages # return just the newly created messages
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                def validate
         | 
| 100 | 
            +
                  super      
         | 
| 101 | 
            +
                  assert_unique :screen_name
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
            end
         | 
    
        data/lib/tweetable.rb
    ADDED
    
    | @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            $:.unshift(File.dirname(__FILE__)) unless 
         | 
| 2 | 
            +
              $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'logging'
         | 
| 5 | 
            +
            require 'twitter'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Tweetable
         | 
| 8 | 
            +
              DEFAULT_CONFIG = {
         | 
| 9 | 
            +
                :max_message_count => 10, 
         | 
| 10 | 
            +
                :include_on_update => [:info, :friend_ids, :follower_ids, :messages], # skipping :friend_messages
         | 
| 11 | 
            +
                :update_delay => 60*10
         | 
| 12 | 
            +
              }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              # Generic exception class.
         | 
| 15 | 
            +
              class TweetableError < StandardError
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              class TweetableAuthError < StandardError
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              # Raised when there is a temporary problem like Twitter::Unavailable
         | 
| 22 | 
            +
              class TemporaryPullFromQueueError < TweetableError
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              # Raised when there is a problem pulling from the queue
         | 
| 26 | 
            +
              class PullFromQueueError < TweetableError
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              autoload :Persistable, File.join(File.dirname(__FILE__), *%w[tweetable persistable.rb])
         | 
| 30 | 
            +
              autoload :TwitterClient, File.join(File.dirname(__FILE__), *%w[tweetable twitter_client.rb])
         | 
| 31 | 
            +
              autoload :TwitterStreamingClient, File.join(File.dirname(__FILE__), *%w[tweetable twitter_streaming_client.rb])
         | 
| 32 | 
            +
              autoload :Link, File.join(File.dirname(__FILE__), *%w[tweetable link.rb])
         | 
| 33 | 
            +
              autoload :Photo, File.join(File.dirname(__FILE__), *%w[tweetable photo.rb])
         | 
| 34 | 
            +
              autoload :Message, File.join(File.dirname(__FILE__), *%w[tweetable message.rb])
         | 
| 35 | 
            +
              autoload :Search, File.join(File.dirname(__FILE__), *%w[tweetable search.rb])
         | 
| 36 | 
            +
              autoload :User, File.join(File.dirname(__FILE__), *%w[tweetable user.rb])
         | 
| 37 | 
            +
              autoload :Collection, File.join(File.dirname(__FILE__), *%w[tweetable collection.rb])
         | 
| 38 | 
            +
              autoload :UserCollection, File.join(File.dirname(__FILE__), *%w[tweetable collection.rb])
         | 
| 39 | 
            +
              autoload :MessageCollection, File.join(File.dirname(__FILE__), *%w[tweetable collection.rb])
         | 
| 40 | 
            +
              autoload :SearchCollection, File.join(File.dirname(__FILE__), *%w[tweetable collection.rb])
         | 
| 41 | 
            +
              autoload :LinkCollection, File.join(File.dirname(__FILE__), *%w[tweetable collection.rb])
         | 
| 42 | 
            +
              autoload :Authorization, File.join(File.dirname(__FILE__), *%w[tweetable authorization.rb])
         | 
| 43 | 
            +
              autoload :URL, File.join(File.dirname(__FILE__), *%w[tweetable url.rb])
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def client
         | 
| 46 | 
            +
                Thread.current[:twitter_client] ||= options.nil? ? TwitterClient.new.login(*credentials) : TwitterClient.new.authorize(*options)
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              def streaming_client
         | 
| 50 | 
            +
                Thread.current[:twitter_streaming_client] ||= TwitterStreamingClient.new.authorize(*options)
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def login(*credentials)
         | 
| 54 | 
            +
                @credentials = credentials
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def authorize(*options)
         | 
| 58 | 
            +
                @options = options
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def options
         | 
| 62 | 
            +
                @options
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
              
         | 
| 65 | 
            +
              def config(config = nil)
         | 
| 66 | 
            +
                @config ||= DEFAULT_CONFIG
         | 
| 67 | 
            +
                @config.merge!(config) unless config.nil?
         | 
| 68 | 
            +
                @config
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def credentials
         | 
| 72 | 
            +
                @credentials
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
              def log
         | 
| 76 | 
            +
                @log = Logging.logger(STDOUT)
         | 
| 77 | 
            +
                @log.level = :debug
         | 
| 78 | 
            +
                @log
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              module_function :client, :options, :authorize, :login, :credentials, :log, :config
         | 
| 82 | 
            +
            end
         | 
| Binary file | 
    
        data/script/console
    ADDED
    
    | @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # File: script/console
         | 
| 3 | 
            +
            irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            libs =  " -r irb/completion"
         | 
| 6 | 
            +
            # Perhaps use a console_lib to store any extra methods I may want available in the cosole
         | 
| 7 | 
            +
            # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
         | 
| 8 | 
            +
            libs <<  " -r #{File.dirname(__FILE__) + '/../lib/tweetable.rb'}"
         | 
| 9 | 
            +
            puts "Loading tweetable gem"
         | 
| 10 | 
            +
            exec "#{irb} #{libs} --simple-prompt"
         | 
    
        data/script/destroy
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'rubigen'
         | 
| 6 | 
            +
            rescue LoadError
         | 
| 7 | 
            +
              require 'rubygems'
         | 
| 8 | 
            +
              require 'rubigen'
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
            require 'rubigen/scripts/destroy'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ARGV.shift if ['--help', '-h'].include?(ARGV[0])
         | 
| 13 | 
            +
            RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
         | 
| 14 | 
            +
            RubiGen::Scripts::Destroy.new.run(ARGV)
         | 
    
        data/script/generate
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            begin
         | 
| 5 | 
            +
              require 'rubigen'
         | 
| 6 | 
            +
            rescue LoadError
         | 
| 7 | 
            +
              require 'rubygems'
         | 
| 8 | 
            +
              require 'rubigen'
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
            require 'rubigen/scripts/generate'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ARGV.shift if ['--help', '-h'].include?(ARGV[0])
         | 
| 13 | 
            +
            RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
         | 
| 14 | 
            +
            RubiGen::Scripts::Generate.new.run(ARGV)
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/spec_helper.rb'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Tweetable::Collection, 'when building lists' do 
         | 
| 4 | 
            +
              before do 
         | 
| 5 | 
            +
                RedisSpecHelper.reset
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              it "should dissallow collections without a name" do
         | 
| 9 | 
            +
                Tweetable::Collection.create.should_not be_valid
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              it "should build new MessageCollection" do
         | 
| 13 | 
            +
                Tweetable::MessageCollection.new.should_not be_nil
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
              it "should build new UserCollection" do
         | 
| 17 | 
            +
                Tweetable::UserCollection.new.should_not be_nil
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
              
         | 
| 20 | 
            +
              it "should build new SearchCollection" do
         | 
| 21 | 
            +
                Tweetable::SearchCollection.new.should_not be_nil
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              it "should find or create a new SearchCollection" do
         | 
| 25 | 
            +
                Tweetable::SearchCollection.find_or_create(:name, 'some-name').should be_instance_of Tweetable::SearchCollection
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "should find an existing collection" do
         | 
| 29 | 
            +
                Tweetable::SearchCollection.create(:name => 'some-name')
         | 
| 30 | 
            +
                Tweetable::SearchCollection.find(:name => 'some-name').first.should be_instance_of Tweetable::SearchCollection
         | 
| 31 | 
            +
              end  
         | 
| 32 | 
            +
            end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            describe Tweetable::Collection, 'when building sets' do 
         | 
| 35 | 
            +
              before do 
         | 
| 36 | 
            +
                RedisSpecHelper.reset
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              it "should add user to user set" do
         | 
| 40 | 
            +
                collection = Tweetable::UserCollection.find_or_create(:name, 'some-name')
         | 
| 41 | 
            +
                collection.user_set.add(Tweetable::User.create(:screen_name => 'this'))
         | 
| 42 | 
            +
                collection.user_set.size.should == 1
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              it "should only add unique users to set" do
         | 
| 46 | 
            +
                collection = Tweetable::UserCollection.find_or_create(:name, 'some-name')
         | 
| 47 | 
            +
                user = Tweetable::User.create(:screen_name => 'this', :created_at => Time.now.utc.to_s)
         | 
| 48 | 
            +
                user2 = Tweetable::User.create(:screen_name => 'this2', :created_at => Time.now.utc.to_s)
         | 
| 49 | 
            +
                collection.user_set.add(user)
         | 
| 50 | 
            +
                collection.user_set.add(user2)
         | 
| 51 | 
            +
                collection.user_set.add(user)
         | 
| 52 | 
            +
                collection.user_set.size.should == 2
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
              
         | 
| 55 | 
            +
            end
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            []
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            {"profile_background_image_url":"http://s.twimg.com/a/1274144130/images/themes/theme12/bg.gif","profile_link_color":"FF0000","url":"http://wagglelabs.com","description":"Haha made ya read!","status":{"contributors":null,"coordinates":null,"in_reply_to_screen_name":null,"geo":null,"favorited":false,"truncated":false,"in_reply_to_status_id":null,"source":"<a href=\"http://twitterrific.com\" rel=\"nofollow\">Twitterrific</a>","in_reply_to_user_id":null,"created_at":"Sat May 29 03:21:34 +0000 2010","id":14951172829,"place":null,"text":"Watering mytwee !"},"profile_background_tile":false,"profile_sidebar_fill_color":"FFF7CC","location":"Capitol Hill, Washington","statuses_count":262,"notifications":null,"profile_image_url":"http://a3.twimg.com/profile_images/74792235/screen-capture-2_normal.png","profile_sidebar_border_color":"F2E195","followers_count":233,"contributors_enabled":false,"lang":"en","screen_name":"Flippyhead","friends_count":114,"favourites_count":2,"profile_background_color":"BADFCD","protected":false,"following":null,"geo_enabled":true,"time_zone":"Pacific Time (US & Canada)","created_at":"Wed Feb 20 04:05:51 +0000 2008","name":"Peter T. Brown","profile_text_color":"0C3E53","id":13705052,"verified":false,"utc_offset":-28800}
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            [103136961,12767492,38488854,43330332,117481827,114770454,87265151,7315022,14470427,15661935,118054255,116260600,58822253,31340126,17296974,32503163,108098467,60002553,79313634,20254889,82887533,12101862,39617233,15878021,95752657,97296470,22343218,94655742,91197034,15140257,14305034,87716554,87618379,85689666,56425680,16607043,1699751,45283949,3452941,84318041,82091551,16753165,59543723,36585916,79669240,78114832,15759497,32241975,76542156,16337900,14814522,16598422,14166535,64881807,46293477,41241684,17724900,40162052,34364391,25577085,31231869,67645971,19942432,46725587,62416583,3778581,2856031,16030970,15443687,16987565,33893844,43183984,24562033,15665281,11334,17304123,20104538,16388638,17663086,53480097,16230239,58598857,46236831,58579307,58587952,24718118,23096363,18348762,25846278,23047941,19990886,19159761,13656362,2656,5702262,15283419,51553499,17629947,18229081,25030269,16004418,17413507,46757793,41849734,18457047,2654,809512,54078161,15575798,46715253,21538391,14446704,7597362,14762678,17093876,32327090,43418805,25539943,24018995,9022272,38533218,20123484,31560075,27731367,22996821,20351687,30688103,44668855,17813503,16438680,18041530,21681207,29260057,44681603,43753948,43012556,16072309,17627869,23178979,20395561,51585617,15399031,15618016,18285296,29571801,14838820,14137771,24251591,18584722,19207519,19089507,16460227,17089852,14352556,49594418,14385806,10475492,49239945,23456819,15103961,15522944,47891060,1612021,37533608,42924484,14207966,41479415,26565471,37879230,983011,33337061,36267489,17181629,33389895,22900167,34986068,34904138,34686817,34423762,18811351,32664150,32649092,32630299,32607874,14069658,32235388,32227031,32222310,32216021,32211757,32204651,31294847,31237665,18810879,24166272,20255102,6726182,22071150,6140,8938362,16820481,18973843,24576385,16100658,21701416,1442541,19121958,22966270,15069767,17158244,17218814,21015551,780886,20402566,15555883,1173281,15841044,15552710,3093981,802799,19239032,14334195,19943055,10395332,2078,15909918,13357,3734051,3567281]
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            [17333183,14305100,12685,3452941,60493684,21547828,1442541,14305034,20608910,36082429,3778581,19035252,30495974,14032852,9580822,21066103,21944280,18789983,6170,25577085,13445732,14677720,9066762,3302921,1192,16004418,38975663,21159411,14278978,9420652,5832712,14166535,17242834,18457047,3244801,2729061,16393990,14939200,17304123,13895242,16316680,1235521,13035,11907952,24726388,7255652,10168952,15629200,7787522,14805814,16669075,30313925,35270768,51886564,5493,11263102,48381958,12691112,19159761,53256107,8071082,1916151,23832616,11397012,20734538,17093876,7597362,16735575,32241975,27339792,41478837,35395379,17065232,14446704,16129920,639643,12854372,14319981,16753165,24737795,33187261,16793850,15347711,8693202,14589771,22132568,42678765,50089613,20092241,29566363,16072309,17290254,18772339,19121773,30270211,41479415,3093981,17203250,649,14814522,7706092,2029851,43753948,6140,16112339,17663086,15126376,5651,47891060,9504712,15522944,6118342,12111,45384353,6583802,3585151,31136692,20123484,17086635,43012556,46725587,43916629,15618016,13134132,18492538,24258295,24251591,30903701,49258589,29327220,30688103,16426042,16055631,7017692,148373,14137771,31825923,15610682,45769183,20104538,8248752,17875633,3370001,44274687,20210157,15741618,25181690,25694758,31231869,17813503,37678947,29260057,14091396,45607634,46293477,13983,18492596,30340010,28286020,24827930,16230239,19089507,17089852,23519997,21361624,23642374,62903,20037216,16115979,29571801,32327090,17627869,14818663,17205623,18584722,23879834,19128879,14782042,14852457,14838820,16120957,18041530,19897797,22996563,21400763,20216202,18091654,41008177,16607043,23178979,18285296,12650182,18152775,20735406,19040380,25369931,31560075,24156110,6839892,21842077,34988327,17368984,20395561,22952101,12258422,24018995,19452490,21630899,22821231,22409250,16460227,18999188,24960841,32684446,9076552,23721204,41439789,6429402,27033107,44681603,22961177,25846278,18999061,21591962,29915826,19207519,19216123,15463366,31226467,19012200,3019081,7378312,19782239,26394794,7076432,19786525,17724900,21994180,15200655,22221963,26704718,17671951,17545756,21891183,17645701,32175337,34991746,49108215,25030269,10944522,16438680,22966270,16099148,18131862,15399031,14769689,756278,15846932,14470427,14385806,790368,4044361,6025032,5500632,1249191,809512,11334,1173281,9338012,14256894,14326765,14232711,820661,15876737,786818,9022272,16095572,10058162,21538391,19094626,28921689,36132718,1053901,15240977,25032607,50057976,23899200,15685878,16975038,763489,14324794,17464103,20254889,5702262,23456819,15103961,48160844,2185,18673,13357,12428572,14575000,23393638,17870251,22028135,33337061,9676672,586,32216021,32211757,428333,32649092,32664150,14069658,1338321,734493,15552710,97933,6726182,4557111,14170620,24576385,16100658,21701416,780886,8938362,18973843,11132462,15909918,2061681,10395332,14388729,2078,16359539,4644261,15841044,15069767,802799,3567281]
         |