aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorre4k <re4k@re4k.info>2013-03-06 00:06:29 +0900
committerre4k <re4k@re4k.info>2013-03-06 00:06:29 +0900
commita6a3e8317e1f9fa435ad434c05dc4336b8f2e299 (patch)
treea0261f0b616f80025ad3d7964a70c8e2cf41a793
downloadaclog-a6a3e8317e1f9fa435ad434c05dc4336b8f2e299.tar.gz
first commit
-rw-r--r--.gitignore26
l---------Gemfile1
l---------Gemfile.lock1
-rw-r--r--config.ru7
-rw-r--r--web/Gemfile50
-rw-r--r--web/Gemfile.lock182
-rw-r--r--web/README.rdoc261
-rw-r--r--web/Rakefile7
-rw-r--r--web/app/assets/images/rails.pngbin0 -> 6646 bytes
-rw-r--r--web/app/assets/javascripts/application.js13
-rw-r--r--web/app/assets/javascripts/i.js.coffee3
-rw-r--r--web/app/assets/javascripts/main.js.coffee3
-rw-r--r--web/app/assets/javascripts/sessions.js.coffee3
-rw-r--r--web/app/assets/javascripts/users.js.coffee3
-rw-r--r--web/app/assets/stylesheets/application.css.sass20
-rw-r--r--web/app/controllers/application_controller.rb19
-rw-r--r--web/app/controllers/i_controller.rb6
-rw-r--r--web/app/controllers/main_controller.rb4
-rw-r--r--web/app/controllers/sessions_controller.rb25
-rw-r--r--web/app/controllers/users_controller.rb77
-rw-r--r--web/app/helpers/application_helper.rb12
-rw-r--r--web/app/helpers/i_helper.rb2
-rw-r--r--web/app/helpers/main_helper.rb2
-rw-r--r--web/app/helpers/sessions_helper.rb2
-rw-r--r--web/app/helpers/users_helper.rb2
-rw-r--r--web/app/mailers/.gitkeep0
-rw-r--r--web/app/models/.gitkeep0
-rw-r--r--web/app/models/account.rb3
-rw-r--r--web/app/models/favorite.rb5
-rw-r--r--web/app/models/retweet.rb5
-rw-r--r--web/app/models/tweet.rb6
-rw-r--r--web/app/models/user.rb6
-rw-r--r--web/app/views/i/show.haml3
-rw-r--r--web/app/views/layouts/application.haml8
-rw-r--r--web/app/views/main/index.haml2
-rw-r--r--web/app/views/shared/._tweet.haml.swpbin0 -> 12288 bytes
-rw-r--r--web/app/views/shared/_tweet.haml35
-rw-r--r--web/app/views/shared/_tweets.haml4
-rw-r--r--web/app/views/users/best.haml1
-rw-r--r--web/app/views/users/info.haml1
-rw-r--r--web/app/views/users/my.haml2
-rw-r--r--web/app/views/users/recent.haml1
-rw-r--r--web/app/views/users/timeline.haml1
-rw-r--r--web/config.ru4
-rw-r--r--web/config/application.rb25
-rw-r--r--web/config/boot.rb4
-rw-r--r--web/config/database.yml33
-rw-r--r--web/config/environment.rb10
-rw-r--r--web/config/environments/development.rb27
-rw-r--r--web/config/environments/production.rb80
-rw-r--r--web/config/environments/test.rb36
-rw-r--r--web/config/initializers/backtrace_silencers.rb7
-rw-r--r--web/config/initializers/filter_parameter_logging.rb4
-rw-r--r--web/config/initializers/haml.rb4
-rw-r--r--web/config/initializers/inflections.rb16
-rw-r--r--web/config/initializers/mime_types.rb10
-rw-r--r--web/config/initializers/omniauth.rb8
-rw-r--r--web/config/initializers/rails_config.rb3
-rw-r--r--web/config/initializers/secret_token.rb12
-rw-r--r--web/config/initializers/session_store.rb3
-rw-r--r--web/config/initializers/wrap_parameters.rb14
-rw-r--r--web/config/locales/en.yml23
-rw-r--r--web/config/routes.rb24
-rw-r--r--web/config/settings.yml4
-rw-r--r--web/config/settings/development.yml0
-rw-r--r--web/config/settings/production.yml0
-rw-r--r--web/config/settings/test.yml0
-rw-r--r--web/db/migrate/20130225123010_create_accounts.rb10
-rw-r--r--web/db/migrate/20130226145932_create_users.rb13
-rw-r--r--web/db/migrate/20130226150329_create_tweets.rb13
-rw-r--r--web/db/migrate/20130226150829_create_favorites.rb8
-rw-r--r--web/db/migrate/20130226151042_create_retweets.rb8
-rw-r--r--web/db/schema.rb52
-rw-r--r--web/db/seeds.rb7
-rw-r--r--web/lib/assets/.gitkeep0
-rw-r--r--web/lib/tasks/.gitkeep0
-rw-r--r--web/log/.gitkeep0
-rw-r--r--web/log/development.log30
-rw-r--r--web/log/production.log0
-rw-r--r--web/public/404.xhtml26
-rw-r--r--web/public/422.xhtml26
-rw-r--r--web/public/500.xhtml25
-rw-r--r--web/public/favicon.ico0
-rwxr-xr-xweb/script/rails6
-rw-r--r--web/vendor/assets/javascripts/.gitkeep0
-rw-r--r--web/vendor/assets/stylesheets/.gitkeep0
-rw-r--r--web/vendor/plugins/.gitkeep0
-rw-r--r--worker/receiver.rb6
-rw-r--r--worker/receiver/logger.rb28
-rw-r--r--worker/receiver/worker.rb247
90 files changed, 1670 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eb96b5a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile ~/.gitignore_global
+
+# Ignore bundler config
+.bundle
+
+# Ignore the default SQLite database.
+web/db/*.sqlite3
+
+# Ignore all logfiles and tempfiles.
+log/*.log
+tmp
+
+web/config/settings.local.yml
+web/config/settings/*.local.yml
+web/config/environments/*.local.yml
+web/config/initializers/secret_token.local.rb
+
+# dotcloud
+/dotcloud.yml
+/supervisord.conf
+.dotcloud
+
diff --git a/Gemfile b/Gemfile
new file mode 120000
index 0000000..02eac92
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1 @@
+web/Gemfile \ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 120000
index 0000000..4e92a6a
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1 @@
+web/Gemfile.lock \ No newline at end of file
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..cbf22b4
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,7 @@
+require ::File.expand_path('../web/config/application', __FILE__)
+Rails.application.require_environment!
+
+require ::File.expand_path('../worker/receiver', __FILE__)
+
+Receiver::Worker.new.start
+
diff --git a/web/Gemfile b/web/Gemfile
new file mode 100644
index 0000000..7530826
--- /dev/null
+++ b/web/Gemfile
@@ -0,0 +1,50 @@
+ruby '1.9.3'
+source 'https://rubygems.org'
+
+gem 'rails', '4.0.0.beta1'
+
+gem 'thin'
+
+# Bundle edge Rails instead:
+# gem 'rails', :git => 'git://github.com/rails/rails.git'
+
+gem 'mysql2'
+gem 'haml-rails'
+
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', '~> 4.0.0.beta1'
+ gem 'coffee-rails', '~> 4.0.0.beta1'
+
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
+ gem 'therubyracer', :platforms => :ruby
+
+ gem 'uglifier', '>= 1.0.3'
+end
+
+group :development do
+ gem 'sqlite3'
+end
+
+gem 'yajl-ruby', :require => "yajl"
+gem 'rails_config'
+gem 'omniauth-twitter', :github => "re4k/omniauth-twitter"
+gem 'em-twitter'
+gem 'twitter'
+gem 'will_paginate', :github => 're4k/will_paginate'
+
+# To use ActiveModel has_secure_password
+# gem 'bcrypt-ruby', '~> 3.0.0'
+
+# To use Jbuilder templates for JSON
+# gem 'jbuilder'
+
+# Use unicorn as the app server
+gem 'unicorn'
+
+# Deploy with Capistrano
+# gem 'capistrano'
+
+# To use debugger
+# gem 'debugger'
diff --git a/web/Gemfile.lock b/web/Gemfile.lock
new file mode 100644
index 0000000..07f3817
--- /dev/null
+++ b/web/Gemfile.lock
@@ -0,0 +1,182 @@
+GIT
+ remote: git://github.com/re4k/omniauth-twitter.git
+ revision: 313df7eb05e78477cf3eb06bced3c9b64957840f
+ specs:
+ omniauth-twitter (0.0.14)
+ multi_json (~> 1.3)
+ omniauth-oauth (~> 1.0)
+
+GIT
+ remote: git://github.com/re4k/will_paginate.git
+ revision: fcbbd91ced44aaabb1f369875ee9f4f651bc74fb
+ specs:
+ will_paginate (3.0.4)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actionmailer (4.0.0.beta1)
+ actionpack (= 4.0.0.beta1)
+ mail (~> 2.5.3)
+ actionpack (4.0.0.beta1)
+ activesupport (= 4.0.0.beta1)
+ builder (~> 3.1.0)
+ erubis (~> 2.7.0)
+ rack (~> 1.5.2)
+ rack-test (~> 0.6.2)
+ activemodel (4.0.0.beta1)
+ activesupport (= 4.0.0.beta1)
+ builder (~> 3.1.0)
+ activerecord (4.0.0.beta1)
+ activemodel (= 4.0.0.beta1)
+ activerecord-deprecated_finders (~> 0.0.3)
+ activesupport (= 4.0.0.beta1)
+ arel (~> 4.0.0.beta1)
+ activerecord-deprecated_finders (0.0.3)
+ activesupport (4.0.0.beta1)
+ i18n (~> 0.6.2)
+ minitest (~> 4.2)
+ multi_json (~> 1.3)
+ thread_safe (~> 0.1)
+ tzinfo (~> 0.3.33)
+ arel (4.0.0.beta1)
+ atomic (1.0.1)
+ builder (3.1.4)
+ coffee-rails (4.0.0.beta1)
+ coffee-script (>= 2.2.0)
+ railties (>= 4.0.0.beta, < 5.0)
+ coffee-script (2.2.0)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.6.1)
+ daemons (1.1.9)
+ em-twitter (0.2.1)
+ eventmachine (~> 1.0)
+ http_parser.rb (~> 0.5)
+ simple_oauth (~> 0.1)
+ erubis (2.7.0)
+ eventmachine (1.0.1)
+ execjs (1.4.0)
+ multi_json (~> 1.0)
+ faraday (0.8.6)
+ multipart-post (~> 1.1)
+ haml (4.0.0)
+ tilt
+ haml-rails (0.4)
+ actionpack (>= 3.1, < 4.1)
+ activesupport (>= 3.1, < 4.1)
+ haml (>= 3.1, < 4.1)
+ railties (>= 3.1, < 4.1)
+ hashie (1.2.0)
+ hike (1.2.1)
+ http_parser.rb (0.5.3)
+ i18n (0.6.4)
+ json (1.7.7)
+ kgio (2.8.0)
+ libv8 (3.11.8.13)
+ mail (2.5.3)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ mime-types (1.21)
+ minitest (4.6.2)
+ multi_json (1.6.1)
+ multipart-post (1.2.0)
+ mysql2 (0.3.11)
+ oauth (0.4.7)
+ omniauth (1.1.3)
+ hashie (~> 1.2)
+ rack
+ omniauth-oauth (1.0.1)
+ oauth
+ omniauth (~> 1.0)
+ polyglot (0.3.3)
+ rack (1.5.2)
+ rack-test (0.6.2)
+ rack (>= 1.0)
+ rails (4.0.0.beta1)
+ actionmailer (= 4.0.0.beta1)
+ actionpack (= 4.0.0.beta1)
+ activerecord (= 4.0.0.beta1)
+ activesupport (= 4.0.0.beta1)
+ bundler (>= 1.3.0, < 2.0)
+ railties (= 4.0.0.beta1)
+ sprockets-rails (~> 2.0.0.rc3)
+ rails_config (0.3.2)
+ activesupport (>= 3.0)
+ railties (4.0.0.beta1)
+ actionpack (= 4.0.0.beta1)
+ activesupport (= 4.0.0.beta1)
+ rake (>= 0.8.7)
+ rdoc (~> 3.4)
+ thor (>= 0.17.0, < 2.0)
+ raindrops (0.10.0)
+ rake (10.0.3)
+ rdoc (3.12.2)
+ json (~> 1.4)
+ ref (1.0.2)
+ sass (3.2.6)
+ sass-rails (4.0.0.beta1)
+ railties (>= 4.0.0.beta, < 5.0)
+ sass (>= 3.1.10)
+ sprockets-rails (~> 2.0.0.rc0)
+ tilt (~> 1.3)
+ simple_oauth (0.2.0)
+ sprockets (2.9.0)
+ hike (~> 1.2)
+ multi_json (~> 1.0)
+ rack (~> 1.0)
+ tilt (~> 1.1, != 1.3.0)
+ sprockets-rails (2.0.0.rc3)
+ actionpack (>= 3.0)
+ activesupport (>= 3.0)
+ sprockets (~> 2.8)
+ sqlite3 (1.3.7)
+ therubyracer (0.11.4)
+ libv8 (~> 3.11.8.12)
+ ref
+ thin (1.5.0)
+ daemons (>= 1.0.9)
+ eventmachine (>= 0.12.6)
+ rack (>= 1.0.0)
+ thor (0.17.0)
+ thread_safe (0.1.0)
+ atomic
+ tilt (1.3.4)
+ treetop (1.4.12)
+ polyglot
+ polyglot (>= 0.3.1)
+ twitter (4.5.0)
+ faraday (~> 0.8, < 0.10)
+ multi_json (~> 1.0)
+ simple_oauth (~> 0.2)
+ tzinfo (0.3.36)
+ uglifier (1.3.0)
+ execjs (>= 0.3.0)
+ multi_json (~> 1.0, >= 1.0.2)
+ unicorn (4.6.2)
+ kgio (~> 2.6)
+ rack
+ raindrops (~> 0.7)
+ yajl-ruby (1.1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ coffee-rails (~> 4.0.0.beta1)
+ em-twitter
+ haml-rails
+ mysql2
+ omniauth-twitter!
+ rails (= 4.0.0.beta1)
+ rails_config
+ sass-rails (~> 4.0.0.beta1)
+ sqlite3
+ therubyracer
+ thin
+ twitter
+ uglifier (>= 1.0.3)
+ unicorn
+ will_paginate!
+ yajl-ruby
diff --git a/web/README.rdoc b/web/README.rdoc
new file mode 100644
index 0000000..7c36f23
--- /dev/null
+++ b/web/README.rdoc
@@ -0,0 +1,261 @@
+== Welcome to Rails
+
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
+
+This pattern splits the view (also called the presentation) into "dumb"
+templates that are primarily responsible for inserting pre-built data in between
+HTML tags. The model contains the "smart" domain objects (such as Account,
+Product, Person, Post) that holds all the business logic and knows how to
+persist themselves to a database. The controller handles the incoming requests
+(such as Save New Account, Update Product, Show Post) by manipulating the model
+and directing data to the view.
+
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
+
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
+
+
+== Getting Started
+
+1. At the command prompt, create a new Rails application:
+ <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
+
+2. Change directory to <tt>myapp</tt> and start the web server:
+ <tt>cd myapp; rails server</tt> (run with --help for options)
+
+3. Go to http://localhost:3000/ and you'll see:
+ "Welcome aboard: You're riding Ruby on Rails!"
+
+4. Follow the guidelines to start developing your application. You can find
+the following resources handy:
+
+* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
+* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
+
+
+== Debugging Rails
+
+Sometimes your application goes wrong. Fortunately there are a lot of tools that
+will help you debug it and get it back on the rails.
+
+First area to check is the application log files. Have "tail -f" commands
+running on the server.log and development.log. Rails will automatically display
+debugging and runtime information to these files. Debugging info will also be
+shown in the browser on requests from 127.0.0.1.
+
+You can also log your own messages directly into the log file from your code
+using the Ruby logger class from inside your controllers. Example:
+
+ class WeblogController < ActionController::Base
+ def destroy
+ @weblog = Weblog.find(params[:id])
+ @weblog.destroy
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+ end
+ end
+
+The result will be a message in your log file along the lines of:
+
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
+
+More information on how to use the logger is at http://www.ruby-doc.org/core/
+
+Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
+several books available online as well:
+
+* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+
+These two books will bring you up to speed on the Ruby language and also on
+programming in general.
+
+
+== Debugger
+
+Debugger support is available through the debugger command when you start your
+Mongrel or WEBrick server with --debugger. This means that you can break out of
+execution at any point in the code, investigate and change the model, and then,
+resume execution! You need to install ruby-debug to run the server in debugging
+mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.all
+ debugger
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the server window. Here you can do things like:
+
+ >> @posts.inspect
+ => "[#<Post:0x14a6be8
+ @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
+ #<Post:0x14a6620
+ @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better, you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you can enter "cont".
+
+
+== Console
+
+The console is a Ruby shell, which allows you to interact with your
+application's domain model. Here you'll have all parts of the application
+configured, just like it is when the application is running. You can inspect
+domain models, change values, and save to the database. Starting the script
+without arguments will launch it in the development environment.
+
+To start the console, run <tt>rails console</tt> from the application
+directory.
+
+Options:
+
+* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications
+ made to the database.
+* Passing an environment name as an argument will load the corresponding
+ environment. Example: <tt>rails console production</tt>.
+
+To reload your controllers and models after launching the console run
+<tt>reload!</tt>
+
+More information about irb can be found at:
+link:http://www.rubycentral.org/pickaxe/irb.html
+
+
+== dbconsole
+
+You can go to the command line of your database directly through <tt>rails
+dbconsole</tt>. You would be connected to the database with the credentials
+defined in database.yml. Starting the script without arguments will connect you
+to the development database. Passing an argument will connect you to a different
+database, like <tt>rails dbconsole production</tt>. Currently works for MySQL,
+PostgreSQL and SQLite 3.
+
+== Description of Contents
+
+The default directory structure of a generated Ruby on Rails application:
+
+ |-- app
+ | |-- assets
+ | |-- images
+ | |-- javascripts
+ | `-- stylesheets
+ | |-- controllers
+ | |-- helpers
+ | |-- mailers
+ | |-- models
+ | `-- views
+ | `-- layouts
+ |-- config
+ | |-- environments
+ | |-- initializers
+ | `-- locales
+ |-- db
+ |-- doc
+ |-- lib
+ | `-- tasks
+ |-- log
+ |-- public
+ |-- script
+ |-- test
+ | |-- fixtures
+ | |-- functional
+ | |-- integration
+ | |-- performance
+ | `-- unit
+ |-- tmp
+ | |-- cache
+ | |-- pids
+ | |-- sessions
+ | `-- sockets
+ `-- vendor
+ |-- assets
+ `-- stylesheets
+ `-- plugins
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/assets
+ Contains subdirectories for images, stylesheets, and JavaScript files.
+
+app/controllers
+ Holds controllers that should be named like weblogs_controller.rb for
+ automated URL mapping. All controllers should descend from
+ ApplicationController which itself descends from ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb. Models descend from
+ ActiveRecord::Base by default.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.html.erb for the WeblogsController#index action. All views use
+ eRuby syntax by default.
+
+app/views/layouts
+ Holds the template files for layouts to be used with views. This models the
+ common header/footer method of wrapping views. In your views, define a layout
+ using the <tt>layout :default</tt> and create a file named default.html.erb.
+ Inside default.html.erb, call <% yield %> to render the view using this
+ layout.
+
+app/helpers
+ Holds view helpers that should be named like weblogs_helper.rb. These are
+ generated for you automatically when using generators for controllers.
+ Helpers can be used to wrap functionality for your views into methods.
+
+config
+ Configuration files for the Rails environment, the routing map, the database,
+ and other dependencies.
+
+db
+ Contains the database schema in schema.rb. db/migrate contains all the
+ sequence of Migrations for your schema.
+
+doc
+ This directory is where your application documentation will be stored when
+ generated using <tt>rake doc:app</tt>
+
+lib
+ Application specific libraries. Basically, any kind of custom code that
+ doesn't belong under controllers, models, or helpers. This directory is in
+ the load path.
+
+public
+ The directory available for the web server. Also contains the dispatchers and the
+ default HTML files. This should be set as the DOCUMENT_ROOT of your web
+ server.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures. When using the rails generate
+ command, template test files will be generated for you and placed in this
+ directory.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins
+ subdirectory. If the app has frozen rails, those gems also go here, under
+ vendor/rails/. This directory is in the load path.
diff --git a/web/Rakefile b/web/Rakefile
new file mode 100644
index 0000000..c2dad7b
--- /dev/null
+++ b/web/Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+Aclog::Application.load_tasks
diff --git a/web/app/assets/images/rails.png b/web/app/assets/images/rails.png
new file mode 100644
index 0000000..d5edc04
--- /dev/null
+++ b/web/app/assets/images/rails.png
Binary files differ
diff --git a/web/app/assets/javascripts/application.js b/web/app/assets/javascripts/application.js
new file mode 100644
index 0000000..15ebed9
--- /dev/null
+++ b/web/app/assets/javascripts/application.js
@@ -0,0 +1,13 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// the compiled file.
+//
+// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
+// GO AFTER THE REQUIRES BELOW.
+//
+//= require_tree .
diff --git a/web/app/assets/javascripts/i.js.coffee b/web/app/assets/javascripts/i.js.coffee
new file mode 100644
index 0000000..7615679
--- /dev/null
+++ b/web/app/assets/javascripts/i.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/web/app/assets/javascripts/main.js.coffee b/web/app/assets/javascripts/main.js.coffee
new file mode 100644
index 0000000..7615679
--- /dev/null
+++ b/web/app/assets/javascripts/main.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/web/app/assets/javascripts/sessions.js.coffee b/web/app/assets/javascripts/sessions.js.coffee
new file mode 100644
index 0000000..7615679
--- /dev/null
+++ b/web/app/assets/javascripts/sessions.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/web/app/assets/javascripts/users.js.coffee b/web/app/assets/javascripts/users.js.coffee
new file mode 100644
index 0000000..7615679
--- /dev/null
+++ b/web/app/assets/javascripts/users.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/web/app/assets/stylesheets/application.css.sass b/web/app/assets/stylesheets/application.css.sass
new file mode 100644
index 0000000..cc6ec33
--- /dev/null
+++ b/web/app/assets/stylesheets/application.css.sass
@@ -0,0 +1,20 @@
+.item
+ :border-bottom 1px solid #999999
+ .tweet
+ :width 800px
+ .icon
+ :width 100px
+ :float left
+ .right
+ :float left
+ .meta
+ .created_at
+ :display block
+ :float left
+ .source
+ :display block
+ :float right
+ .data
+ :width 800px
+ :clear both
+
diff --git a/web/app/controllers/application_controller.rb b/web/app/controllers/application_controller.rb
new file mode 100644
index 0000000..80361c9
--- /dev/null
+++ b/web/app/controllers/application_controller.rb
@@ -0,0 +1,19 @@
+class ApplicationController < ActionController::Base
+ protect_from_forgery
+ before_filter :set_content_type
+
+ def set_content_type
+ request.format = :xhtml if request.format == :html
+ end
+
+ def get_page_number(params)
+ if params[:page]
+ i = params[:page].to_i
+ if i && i > 0
+ return i
+ else
+ return 1
+ end
+ end
+ end
+end
diff --git a/web/app/controllers/i_controller.rb b/web/app/controllers/i_controller.rb
new file mode 100644
index 0000000..9765d3b
--- /dev/null
+++ b/web/app/controllers/i_controller.rb
@@ -0,0 +1,6 @@
+class IController < ApplicationController
+ def show
+ id = params[:id].to_i
+ @item = Tweet.find(id)
+ end
+end
diff --git a/web/app/controllers/main_controller.rb b/web/app/controllers/main_controller.rb
new file mode 100644
index 0000000..88181c2
--- /dev/null
+++ b/web/app/controllers/main_controller.rb
@@ -0,0 +1,4 @@
+class MainController < ApplicationController
+ def index
+ end
+end
diff --git a/web/app/controllers/sessions_controller.rb b/web/app/controllers/sessions_controller.rb
new file mode 100644
index 0000000..9155529
--- /dev/null
+++ b/web/app/controllers/sessions_controller.rb
@@ -0,0 +1,25 @@
+class SessionsController < ApplicationController
+ def callback
+ auth = request.env["omniauth.auth"]
+ user = Account.find_or_initialize_by(:id => auth["uid"])
+ user.update_attributes(:oauth_token => auth["credentials"]["token"],
+ :oauth_token_secret => auth["credentials"]["secret"])
+ session[:user_id] = user.id
+ EM.defer do
+ EM.connect("127.0.0.1", Settings.worker_port) do |client|
+ def client.post_init
+ p data = [:REGISTER, user.id].map(&:to_s).join(" ")
+ send_data(data)
+ end
+ end
+ end
+
+ redirect_to root_url
+ end
+
+ def destroy
+ reset_session
+
+ redirect_to root_url
+ end
+end
diff --git a/web/app/controllers/users_controller.rb b/web/app/controllers/users_controller.rb
new file mode 100644
index 0000000..369fff6
--- /dev/null
+++ b/web/app/controllers/users_controller.rb
@@ -0,0 +1,77 @@
+class UsersController < ApplicationController
+ def best
+ page = get_page_number(params)
+ screen_name = params[:screen_name]
+ user = User.find_by(:screen_name => screen_name)
+ if user
+ @items = user.tweets
+ .where("favorites_count > 0 or retweets_count > 0")
+ .order("COALESCE(favorites_count, 0) + COALESCE(retweets_count, 0) DESC")
+ .paginate(:page => page, :per_page => Settings.page_per)
+ else
+ @items = []
+ end
+ end
+
+ def recent
+ page = get_page_number(params)
+ screen_name = params[:screen_name]
+ user = User.find_by(:screen_name => screen_name)
+ if user
+ @items = user.tweets
+ .where("favorites_count > 0 or retweets_count > 0")
+ .order("id DESC")
+ .paginate(:page => page, :per_page => Settings.page_per)
+ else
+ @items = []
+ end
+ end
+
+ def timeline
+ page = get_page_number(params)
+ screen_name = params[:screen_name]
+ user = User.find_by(:screen_name => screen_name)
+ if user
+ @items = user.tweets
+ .order("id DESC")
+ .paginate(:page => page, :per_page => Settings.page_per)
+ else
+ @items = []
+ end
+ end
+
+ def my
+ page = get_page_number(params)
+ screen_name = params[:screen_name]
+ user = User.find_by(:screen_name => screen_name)
+ if user
+ tweet_ids = ActiveRecord::Base.connection.execute(
+ "SELECT * FROM (" +
+ "SELECT tweet_id FROM favorites WHERE user_id = #{user.id} " +
+ "UNION " +
+ "SELECT tweet_id FROM retweets WHERE user_id = #{user.id} " +
+ ") rf " +
+ "ORDER BY 1 DESC " +
+ "LIMIT #{Settings.page_per} " +
+ "OFFSET #{Settings.page_per * (page - 1)}")
+ tweet_ids.map!{|m| m.values[0]}
+ if tweet_ids && tweet_ids.size > 0
+ @items = Tweet.find(tweet_ids, :order => "id DESC")
+ else
+ @items = []
+ end
+ else
+ @items = []
+ end
+ end
+
+ def info
+ screen_name = params[:screen_name]
+ user = User.find_by(:screen_name => screen_name)
+ if user && account = Account.find_by(:id => user.id)
+ @info = get_user_info
+ else
+ @info = nil
+ end
+ end
+end
diff --git a/web/app/helpers/application_helper.rb b/web/app/helpers/application_helper.rb
new file mode 100644
index 0000000..a01f54a
--- /dev/null
+++ b/web/app/helpers/application_helper.rb
@@ -0,0 +1,12 @@
+module ApplicationHelper
+ def format_tweet_created_at(dt)
+ dt.to_s
+ end
+
+ def format_tweet_text(text)
+ text
+ .gsub(/<url:((?:https?|ftp).+?):(.+?)>/){link_to($2, $1, :target => "_blank")}
+ .gsub(/<hashtag:(.+?)>/){link_to("##{$1}", "https://twitter.com/search?q=%23#{$1}")}
+ .gsub(/<mention:(.+?)>/){link_to("@#{$1}", "/#{$1}")}
+ end
+end
diff --git a/web/app/helpers/i_helper.rb b/web/app/helpers/i_helper.rb
new file mode 100644
index 0000000..ef8bff0
--- /dev/null
+++ b/web/app/helpers/i_helper.rb
@@ -0,0 +1,2 @@
+module IHelper
+end
diff --git a/web/app/helpers/main_helper.rb b/web/app/helpers/main_helper.rb
new file mode 100644
index 0000000..826effe
--- /dev/null
+++ b/web/app/helpers/main_helper.rb
@@ -0,0 +1,2 @@
+module MainHelper
+end
diff --git a/web/app/helpers/sessions_helper.rb b/web/app/helpers/sessions_helper.rb
new file mode 100644
index 0000000..309f8b2
--- /dev/null
+++ b/web/app/helpers/sessions_helper.rb
@@ -0,0 +1,2 @@
+module SessionsHelper
+end
diff --git a/web/app/helpers/users_helper.rb b/web/app/helpers/users_helper.rb
new file mode 100644
index 0000000..2310a24
--- /dev/null
+++ b/web/app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
diff --git a/web/app/mailers/.gitkeep b/web/app/mailers/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/app/mailers/.gitkeep
diff --git a/web/app/models/.gitkeep b/web/app/models/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/app/models/.gitkeep
diff --git a/web/app/models/account.rb b/web/app/models/account.rb
new file mode 100644
index 0000000..1220cee
--- /dev/null
+++ b/web/app/models/account.rb
@@ -0,0 +1,3 @@
+class Account < ActiveRecord::Base
+# attr_accessible :id, :oauth_token, :oauth_token_secret
+end
diff --git a/web/app/models/favorite.rb b/web/app/models/favorite.rb
new file mode 100644
index 0000000..56dbf76
--- /dev/null
+++ b/web/app/models/favorite.rb
@@ -0,0 +1,5 @@
+class Favorite < ActiveRecord::Base
+# attr_accessible :tweet, :user
+ belongs_to :tweet, :counter_cache => true
+ belongs_to :user
+end
diff --git a/web/app/models/retweet.rb b/web/app/models/retweet.rb
new file mode 100644
index 0000000..2f23ae0
--- /dev/null
+++ b/web/app/models/retweet.rb
@@ -0,0 +1,5 @@
+class Retweet < ActiveRecord::Base
+# attr_accessible :id, :tweet, :user
+ belongs_to :tweet, :counter_cache => true
+ belongs_to :user
+end
diff --git a/web/app/models/tweet.rb b/web/app/models/tweet.rb
new file mode 100644
index 0000000..a6862eb
--- /dev/null
+++ b/web/app/models/tweet.rb
@@ -0,0 +1,6 @@
+class Tweet < ActiveRecord::Base
+# attr_accessible :id, :text, :source, :tweeted_at, :user
+ belongs_to :user
+ has_many :favorites, :dependent => :delete_all
+ has_many :retweets, :dependent => :delete_all
+end
diff --git a/web/app/models/user.rb b/web/app/models/user.rb
new file mode 100644
index 0000000..ea1bb26
--- /dev/null
+++ b/web/app/models/user.rb
@@ -0,0 +1,6 @@
+class User < ActiveRecord::Base
+# attr_accessible :id, :screen_name, :name, :profile_image_url
+ has_many :tweets, :dependent => :delete_all
+ has_many :favorites, :dependent => :delete_all
+ has_many :retweets, :dependent => :delete_all
+end
diff --git a/web/app/views/i/show.haml b/web/app/views/i/show.haml
new file mode 100644
index 0000000..dfb6b20
--- /dev/null
+++ b/web/app/views/i/show.haml
@@ -0,0 +1,3 @@
+.content
+ = render :partial => "shared/tweet", :locals => {:item => @item}
+
diff --git a/web/app/views/layouts/application.haml b/web/app/views/layouts/application.haml
new file mode 100644
index 0000000..524a715
--- /dev/null
+++ b/web/app/views/layouts/application.haml
@@ -0,0 +1,8 @@
+!!! xml
+%html{xmlns: "http://www.w3.org/1999/xhtml"}
+ %head
+ %title Aclog
+ = stylesheet_link_tag "application"
+ /= javascript_include_tag "application"
+ %body
+ = yield
diff --git a/web/app/views/main/index.haml b/web/app/views/main/index.haml
new file mode 100644
index 0000000..e72b8b7
--- /dev/null
+++ b/web/app/views/main/index.haml
@@ -0,0 +1,2 @@
+%a{:href => "/i/login"}
+ Login
diff --git a/web/app/views/shared/._tweet.haml.swp b/web/app/views/shared/._tweet.haml.swp
new file mode 100644
index 0000000..9c6ebb8
--- /dev/null
+++ b/web/app/views/shared/._tweet.haml.swp
Binary files differ
diff --git a/web/app/views/shared/_tweet.haml b/web/app/views/shared/_tweet.haml
new file mode 100644
index 0000000..db10dcf
--- /dev/null
+++ b/web/app/views/shared/_tweet.haml
@@ -0,0 +1,35 @@
+.item
+ .tweet
+ .icon
+ %img{:src => item.user.profile_image_url}
+ .right
+ .user
+ %span
+ = item.user.name
+ %span
+ = "@#{item.user.screen_name}"
+ .text
+ = raw format_tweet_text(item.text)
+ .meta
+ %span.created_at
+ = format_tweet_created_at(item.tweeted_at)
+ %span.source
+ = raw item.source
+ .data
+ .favorites
+ FAV
+ - item.favorites.map{|m| m.user}.each_slice(10) do |row|
+ .users_row
+ - row.each do |u|
+ %a{:href => "/#{u.screen_name}", :title => u.screen_name}
+ %img{:src => u.profile_image_url}
+ .retweets
+ RETWEET
+ - item.retweets.map{|m| m.user}.each_slice(10) do |row|
+ .users_row
+ - row.each do |u|
+ %a{:href => "/#{u.screen_name}", :title => u.screen_name}
+ %img{:src => u.profile_image_url}
+
+
+
diff --git a/web/app/views/shared/_tweets.haml b/web/app/views/shared/_tweets.haml
new file mode 100644
index 0000000..719185d
--- /dev/null
+++ b/web/app/views/shared/_tweets.haml
@@ -0,0 +1,4 @@
+%div.items
+ = render :partial => "shared/tweet", :collection => items, :as => :item
+- if items.size > 0
+ = will_paginate items
diff --git a/web/app/views/users/best.haml b/web/app/views/users/best.haml
new file mode 100644
index 0000000..2672287
--- /dev/null
+++ b/web/app/views/users/best.haml
@@ -0,0 +1 @@
+= render :partial => "shared/tweets", :locals => {:items => @items}
diff --git a/web/app/views/users/info.haml b/web/app/views/users/info.haml
new file mode 100644
index 0000000..2672287
--- /dev/null
+++ b/web/app/views/users/info.haml
@@ -0,0 +1 @@
+= render :partial => "shared/tweets", :locals => {:items => @items}
diff --git a/web/app/views/users/my.haml b/web/app/views/users/my.haml
new file mode 100644
index 0000000..4e54081
--- /dev/null
+++ b/web/app/views/users/my.haml
@@ -0,0 +1,2 @@
+%div.items
+ = render :partial => "shared/tweet", :collection => @items, :as => :item
diff --git a/web/app/views/users/recent.haml b/web/app/views/users/recent.haml
new file mode 100644
index 0000000..2672287
--- /dev/null
+++ b/web/app/views/users/recent.haml
@@ -0,0 +1 @@
+= render :partial => "shared/tweets", :locals => {:items => @items}
diff --git a/web/app/views/users/timeline.haml b/web/app/views/users/timeline.haml
new file mode 100644
index 0000000..2672287
--- /dev/null
+++ b/web/app/views/users/timeline.haml
@@ -0,0 +1 @@
+= render :partial => "shared/tweets", :locals => {:items => @items}
diff --git a/web/config.ru b/web/config.ru
new file mode 100644
index 0000000..b9360cf
--- /dev/null
+++ b/web/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run Aclog::Application
diff --git a/web/config/application.rb b/web/config/application.rb
new file mode 100644
index 0000000..7df2cca
--- /dev/null
+++ b/web/config/application.rb
@@ -0,0 +1,25 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+# Assets should be precompiled for production (so we don't need the gems loaded then)
+Bundler.require(*Rails.groups(:assets => %w(development test)))
+
+module Aclog
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # Custom directories with classes and modules you want to be autoloadable.
+ config.autoload_paths += Dir["#{config.root}/lib/**/"]
+
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+ # config.time_zone = 'Central Time (US & Canada)'
+
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
+ # config.i18n.default_locale = :de
+ end
+end
diff --git a/web/config/boot.rb b/web/config/boot.rb
new file mode 100644
index 0000000..3596736
--- /dev/null
+++ b/web/config/boot.rb
@@ -0,0 +1,4 @@
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
diff --git a/web/config/database.yml b/web/config/database.yml
new file mode 100644
index 0000000..a8c0f51
--- /dev/null
+++ b/web/config/database.yml
@@ -0,0 +1,33 @@
+<%
+require "json"
+
+environment = File.exists?("/home/dotcloud/environment.json") ?
+ JSON.parse(File.read("/home/dotcloud/environment.json")) :
+ {}
+%>
+development:
+ adapter: sqlite3
+ database: db/development.sqlite3
+ pool: 5
+ timeout: 5000
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+ adapter: sqlite3
+ database: db/test.sqlite3
+ pool: 5
+ timeout: 5000
+
+production:
+ adapter: mysql2
+ encoding: utf8
+ reconnect: true
+ database: production
+ pool: 5
+ username: <%= environment["DOTCLOUD_DB_MYSQL_LOGIN"] %>
+ password: <%= environment["DOTCLOUD_DB_MYSQL_PASSWORD"] %>
+ host: <%= environment["DOTCLOUD_DB_MYSQL_HOST"] %>
+ port: <%= environment["DOTCLOUD_DB_MYSQL_PORT"] %>
+
diff --git a/web/config/environment.rb b/web/config/environment.rb
new file mode 100644
index 0000000..a5a567a
--- /dev/null
+++ b/web/config/environment.rb
@@ -0,0 +1,10 @@
+# Load the rails application.
+require File.expand_path('../application', __FILE__)
+
+require 'active_record/connection_adapters/mysql2_adapter'
+ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"
+
+# Initialize the rails application.
+Aclog::Application.initialize!
+
+
diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb
new file mode 100644
index 0000000..5f95ca6
--- /dev/null
+++ b/web/config/environments/development.rb
@@ -0,0 +1,27 @@
+Aclog::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Do not eager load code on boot.
+ config.eager_load = false
+
+ # Show full error reports and disable caching.
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Don't care if the mailer can't send.
+ config.action_mailer.raise_delivery_errors = false
+
+ # Print deprecation notices to the Rails logger.
+ config.active_support.deprecation = :log
+
+ # Raise an error on page load if there are pending migrations
+ config.active_record.migration_error = :page_load
+
+ # Expands the lines which load the assets.
+ config.assets.debug = true
+end
diff --git a/web/config/environments/production.rb b/web/config/environments/production.rb
new file mode 100644
index 0000000..c219686
--- /dev/null
+++ b/web/config/environments/production.rb
@@ -0,0 +1,80 @@
+Aclog::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # Code is not reloaded between requests.
+ config.cache_classes = true
+
+ # Eager load code on boot. This eager loads most of Rails and
+ # your application in memory, allowing both thread web servers
+ # and those relying on copy on write to perform better.
+ # Rake tasks automatically ignore this option for performance.
+ config.eager_load = true
+
+ # Full error reports are disabled and caching is turned on.
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Enable Rack::Cache to put a simple HTTP cache in front of your application
+ # Add `rack-cache` to your Gemfile before enabling this.
+ # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
+ # config.action_dispatch.rack_cache = true
+
+ # Disable Rails's static asset server (Apache or nginx will already do this).
+ config.serve_static_assets = true
+
+ # Compress JavaScripts and CSS.
+ config.assets.js_compressor = :uglifier
+ # config.assets.css_compressor = :sass
+
+ # Whether to fallback to assets pipeline if a precompiled asset is missed.
+ config.assets.compile = true
+
+ # Generate digests for assets URLs.
+ config.assets.digest = true
+
+ # Version of your assets, change this if you want to expire all your assets.
+ config.assets.version = '1.0'
+
+ # Specifies the header that your server uses for sending files.
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ # config.force_ssl = true
+
+ # Set to :debug to see everything in the log.
+ config.log_level = :info
+
+ # Prepend all log lines with the following tags.
+ # config.log_tags = [ :subdomain, :uuid ]
+
+ # Use a different logger for distributed setups.
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
+
+ # Use a different cache store in production.
+ # config.cache_store = :mem_cache_store
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Precompile additional assets.
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
+ # config.assets.precompile += %w( search.js )
+
+ # Ignore bad email addresses and do not raise email delivery errors.
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found).
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners.
+ config.active_support.deprecation = :notify
+
+ # Disable automatic flushing of the log to improve performance.
+ # config.autoflush_log = false
+
+ # Use default logging formatter so that PID and timestamp are not suppressed.
+ config.log_formatter = ::Logger::Formatter.new
+end
diff --git a/web/config/environments/test.rb b/web/config/environments/test.rb
new file mode 100644
index 0000000..7254eb2
--- /dev/null
+++ b/web/config/environments/test.rb
@@ -0,0 +1,36 @@
+Aclog::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Do not eager load code on boot. This avoids loading your whole application
+ # just for the purpose of running a single test. If you are using a tool that
+ # preloads Rails for running tests, you may have to set it to true.
+ config.eager_load = false
+
+ # Configure static asset server for tests with Cache-Control for performance.
+ config.serve_static_assets = true
+ config.static_cache_control = "public, max-age=3600"
+
+ # Show full error reports and disable caching.
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Raise exceptions instead of rendering exception templates.
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment.
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Print deprecation notices to the stderr.
+ config.active_support.deprecation = :stderr
+end
diff --git a/web/config/initializers/backtrace_silencers.rb b/web/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000..59385cd
--- /dev/null
+++ b/web/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/web/config/initializers/filter_parameter_logging.rb b/web/config/initializers/filter_parameter_logging.rb
new file mode 100644
index 0000000..4a994e1
--- /dev/null
+++ b/web/config/initializers/filter_parameter_logging.rb
@@ -0,0 +1,4 @@
+# Be sure to restart your server when you modify this file.
+
+# Configure sensitive parameters which will be filtered from the log file.
+Rails.application.config.filter_parameters += [:password]
diff --git a/web/config/initializers/haml.rb b/web/config/initializers/haml.rb
new file mode 100644
index 0000000..38f22ae
--- /dev/null
+++ b/web/config/initializers/haml.rb
@@ -0,0 +1,4 @@
+Haml::Template.options[:attr_wrapper] = "\""
+Haml::Template.options[:format] = :xhtml
+Haml::Template.options[:mime_type] = "application/xhtml+xml"
+
diff --git a/web/config/initializers/inflections.rb b/web/config/initializers/inflections.rb
new file mode 100644
index 0000000..ac033bf
--- /dev/null
+++ b/web/config/initializers/inflections.rb
@@ -0,0 +1,16 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format. Inflections
+# are locale specific, and you may define rules for as many different
+# locales as you wish. All of these examples are active by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
+
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.acronym 'RESTful'
+# end
diff --git a/web/config/initializers/mime_types.rb b/web/config/initializers/mime_types.rb
new file mode 100644
index 0000000..6e2831e
--- /dev/null
+++ b/web/config/initializers/mime_types.rb
@@ -0,0 +1,10 @@
+# Be sure to restart your server when you modify this file.
+module Mime
+ remove_const("HTML")
+end
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
+# Mime::Type.register_alias "text/html", :iphone
+Mime::Type.register "text/html", :html
+Mime::Type.register "application/xhtml+xml", :xhtml
+
diff --git a/web/config/initializers/omniauth.rb b/web/config/initializers/omniauth.rb
new file mode 100644
index 0000000..540652c
--- /dev/null
+++ b/web/config/initializers/omniauth.rb
@@ -0,0 +1,8 @@
+Rails.application.config.middleware.use OmniAuth::Builder do
+ provider :twitter,
+ Settings.consumer_key,
+ Settings.consumer_secret,
+ :request_path => "/i/login",
+ :callback_path => "/i/callback"
+end
+
diff --git a/web/config/initializers/rails_config.rb b/web/config/initializers/rails_config.rb
new file mode 100644
index 0000000..5378de9
--- /dev/null
+++ b/web/config/initializers/rails_config.rb
@@ -0,0 +1,3 @@
+RailsConfig.setup do |config|
+ config.const_name = "Settings"
+end \ No newline at end of file
diff --git a/web/config/initializers/secret_token.rb b/web/config/initializers/secret_token.rb
new file mode 100644
index 0000000..2bb2281
--- /dev/null
+++ b/web/config/initializers/secret_token.rb
@@ -0,0 +1,12 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+# You can use `rake secret` to generate a secure secret key.
+
+# Make sure your secret_key_base is kept private
+# if you're sharing your code publicly.
+# Aclog::Application.config.secret_key_base = '*****'
diff --git a/web/config/initializers/session_store.rb b/web/config/initializers/session_store.rb
new file mode 100644
index 0000000..0a965bc
--- /dev/null
+++ b/web/config/initializers/session_store.rb
@@ -0,0 +1,3 @@
+# Be sure to restart your server when you modify this file.
+
+Aclog::Application.config.session_store :encrypted_cookie_store, key: '_Aclog_session'
diff --git a/web/config/initializers/wrap_parameters.rb b/web/config/initializers/wrap_parameters.rb
new file mode 100644
index 0000000..33725e9
--- /dev/null
+++ b/web/config/initializers/wrap_parameters.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+
+# This file contains settings for ActionController::ParamsWrapper which
+# is enabled by default.
+
+# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
+ActiveSupport.on_load(:action_controller) do
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
+end
+
+# To enable root element in JSON for ActiveRecord objects.
+# ActiveSupport.on_load(:active_record) do
+# self.include_root_in_json = true
+# end
diff --git a/web/config/locales/en.yml b/web/config/locales/en.yml
new file mode 100644
index 0000000..0653957
--- /dev/null
+++ b/web/config/locales/en.yml
@@ -0,0 +1,23 @@
+# Files in the config/locales directory are used for internationalization
+# and are automatically loaded by Rails. If you want to use locales other
+# than English, add the necessary files in this directory.
+#
+# To use the locales, use `I18n.t`:
+#
+# I18n.t 'hello'
+#
+# In views, this is aliased to just `t`:
+#
+# <%= t('hello') %>
+#
+# To use a different locale, set it with `I18n.locale`:
+#
+# I18n.locale = :es
+#
+# This would use the information in config/locales/es.yml.
+#
+# To learn more, please read the Rails Internationalization guide
+# available at http://guides.rubyonrails.org/i18n.html.
+
+en:
+ hello: "Hello world"
diff --git a/web/config/routes.rb b/web/config/routes.rb
new file mode 100644
index 0000000..abb15c3
--- /dev/null
+++ b/web/config/routes.rb
@@ -0,0 +1,24 @@
+Aclog::Application.routes.draw do
+ constraints = {
+ :id => /[0-9]+/,
+ :screen_name => /[a-zA-Z0-9_]{1,20}/,
+ :page => /[0-9]+/,
+ }
+
+ paging_defaults = {
+ :page => "1"
+ }
+
+ root :to => "main#index"
+ get "i/callback" => "sessions#callback"
+ get "i/logout" => "sessions#destroy"
+
+ get "i/:id" => "i#show", :constraints => constraints
+ get ":screen_name/status(es)/:id" => "i#show", :constraints => constraints
+
+ get ":screen_name(/:page)" => "users#best", :constraints => constraints, :defaults => paging_defaults
+ get ":screen_name/my(/:page)" => "users#my", :constraints => constraints, :defaults => paging_defaults
+ get ":screen_name/timeline(/:page)" => "users#timeline", :constraints => constraints, :defaults => paging_defaults
+ get ":screen_name/recent(/:page)" => "users#recent", :constraints => constraints, :defaults => paging_defaults
+ get ":screen_name/info(/:page)" => "users#info", :constraints => constraints, :defaults => paging_defaults
+end
diff --git a/web/config/settings.yml b/web/config/settings.yml
new file mode 100644
index 0000000..bde35a9
--- /dev/null
+++ b/web/config/settings.yml
@@ -0,0 +1,4 @@
+consumer_key: <%= ENV["CONSUMER_KEY"] %>
+consumer_secret: <%= ENV["CONSUMER_SECRET"] %>
+worker_port: 46607
+page_per: 3
diff --git a/web/config/settings/development.yml b/web/config/settings/development.yml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/config/settings/development.yml
diff --git a/web/config/settings/production.yml b/web/config/settings/production.yml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/config/settings/production.yml
diff --git a/web/config/settings/test.yml b/web/config/settings/test.yml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/config/settings/test.yml
diff --git a/web/db/migrate/20130225123010_create_accounts.rb b/web/db/migrate/20130225123010_create_accounts.rb
new file mode 100644
index 0000000..6856539
--- /dev/null
+++ b/web/db/migrate/20130225123010_create_accounts.rb
@@ -0,0 +1,10 @@
+class CreateAccounts < ActiveRecord::Migration
+ def change
+ create_table :accounts do |t|
+ t.string :oauth_token
+ t.string :oauth_token_secret
+
+ t.timestamps
+ end
+ end
+end
diff --git a/web/db/migrate/20130226145932_create_users.rb b/web/db/migrate/20130226145932_create_users.rb
new file mode 100644
index 0000000..1c863d2
--- /dev/null
+++ b/web/db/migrate/20130226145932_create_users.rb
@@ -0,0 +1,13 @@
+class CreateUsers < ActiveRecord::Migration
+ def change
+ create_table :users do |t|
+ t.string :screen_name
+ t.string :name
+ t.text :profile_image_url
+
+ t.timestamps
+ end
+
+ add_index :users, :screen_name
+ end
+end
diff --git a/web/db/migrate/20130226150329_create_tweets.rb b/web/db/migrate/20130226150329_create_tweets.rb
new file mode 100644
index 0000000..393b26e
--- /dev/null
+++ b/web/db/migrate/20130226150329_create_tweets.rb
@@ -0,0 +1,13 @@
+class CreateTweets < ActiveRecord::Migration
+ def change
+ create_table :tweets do |t|
+ t.text :text
+ t.text :source
+ t.references :user, :limit => 8
+ t.datetime :tweeted_at
+
+ t.integer :favorites_count
+ t.integer :retweets_count
+ end
+ end
+end
diff --git a/web/db/migrate/20130226150829_create_favorites.rb b/web/db/migrate/20130226150829_create_favorites.rb
new file mode 100644
index 0000000..d8b34fb
--- /dev/null
+++ b/web/db/migrate/20130226150829_create_favorites.rb
@@ -0,0 +1,8 @@
+class CreateFavorites < ActiveRecord::Migration
+ def change
+ create_table :favorites do |t|
+ t.references :tweet, :limit => 8
+ t.references :user, :limit => 8
+ end
+ end
+end
diff --git a/web/db/migrate/20130226151042_create_retweets.rb b/web/db/migrate/20130226151042_create_retweets.rb
new file mode 100644
index 0000000..a2eb3cf
--- /dev/null
+++ b/web/db/migrate/20130226151042_create_retweets.rb
@@ -0,0 +1,8 @@
+class CreateRetweets < ActiveRecord::Migration
+ def change
+ create_table :retweets do |t|
+ t.references :tweet, :limit => 8
+ t.references :user, :limit => 8
+ end
+ end
+end
diff --git a/web/db/schema.rb b/web/db/schema.rb
new file mode 100644
index 0000000..72fb1e1
--- /dev/null
+++ b/web/db/schema.rb
@@ -0,0 +1,52 @@
+# encoding: UTF-8
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema.define(version: 20130226151042) do
+
+ create_table "accounts", force: true do |t|
+ t.string "oauth_token"
+ t.string "oauth_token_secret"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "favorites", force: true do |t|
+ t.integer "tweet_id", limit: 8
+ t.integer "user_id", limit: 8
+ end
+
+ create_table "retweets", force: true do |t|
+ t.integer "tweet_id", limit: 8
+ t.integer "user_id", limit: 8
+ end
+
+ create_table "tweets", force: true do |t|
+ t.text "text"
+ t.text "source"
+ t.integer "user_id", limit: 8
+ t.datetime "tweeted_at"
+ t.integer "favorites_count"
+ t.integer "retweets_count"
+ end
+
+ create_table "users", force: true do |t|
+ t.string "screen_name"
+ t.string "name"
+ t.text "profile_image_url"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "users", ["screen_name"], name: "index_users_on_screen_name"
+
+end
diff --git a/web/db/seeds.rb b/web/db/seeds.rb
new file mode 100644
index 0000000..4edb1e8
--- /dev/null
+++ b/web/db/seeds.rb
@@ -0,0 +1,7 @@
+# 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: 'Emanuel', city: cities.first)
diff --git a/web/lib/assets/.gitkeep b/web/lib/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/lib/assets/.gitkeep
diff --git a/web/lib/tasks/.gitkeep b/web/lib/tasks/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/lib/tasks/.gitkeep
diff --git a/web/log/.gitkeep b/web/log/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/log/.gitkeep
diff --git a/web/log/development.log b/web/log/development.log
new file mode 100644
index 0000000..b9db4b6
--- /dev/null
+++ b/web/log/development.log
@@ -0,0 +1,30 @@
+  (275.7ms) CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL) 
+  (255.3ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
+Migrating to CreateAccounts (20130225123010)
+  (0.1ms) begin transaction
+  (0.6ms) CREATE TABLE "accounts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "oauth_token" varchar(255), "oauth_token_secret" varchar(255), "created_at" datetime, "updated_at" datetime) 
+ SQL (2.4ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20130225123010"]]
+  (280.2ms) commit transaction
+Migrating to CreateUsers (20130226145932)
+  (0.2ms) begin transaction
+  (0.5ms) CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "screen_name" varchar(255), "name" varchar(255), "profile_image_url" text, "created_at" datetime, "updated_at" datetime) 
+  (0.1ms) CREATE INDEX "index_users_on_screen_name" ON "users" ("screen_name")
+ SQL (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20130226145932"]]
+  (284.4ms) commit transaction
+Migrating to CreateTweets (20130226150329)
+  (0.2ms) begin transaction
+  (0.5ms) CREATE TABLE "tweets" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "text" text, "source" text, "user_id" integer(8), "tweeted_at" datetime, "favorites_count" integer, "retweets_count" integer)
+ SQL (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20130226150329"]]
+  (284.5ms) commit transaction
+Migrating to CreateFavorites (20130226150829)
+  (0.1ms) begin transaction
+  (0.2ms) CREATE TABLE "favorites" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "tweet_id" integer(8), "user_id" integer(8))
+ SQL (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20130226150829"]]
+  (254.0ms) commit transaction
+Migrating to CreateRetweets (20130226151042)
+  (0.1ms) begin transaction
+  (0.5ms) CREATE TABLE "retweets" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "tweet_id" integer(8), "user_id" integer(8))
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES (?) [["version", "20130226151042"]]
+  (262.1ms) commit transaction
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
diff --git a/web/log/production.log b/web/log/production.log
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/log/production.log
diff --git a/web/public/404.xhtml b/web/public/404.xhtml
new file mode 100644
index 0000000..9a48320
--- /dev/null
+++ b/web/public/404.xhtml
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>The page you were looking for doesn't exist (404)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/404.html -->
+ <div class="dialog">
+ <h1>The page you were looking for doesn't exist.</h1>
+ <p>You may have mistyped the address or the page may have moved.</p>
+ </div>
+</body>
+</html>
diff --git a/web/public/422.xhtml b/web/public/422.xhtml
new file mode 100644
index 0000000..83660ab
--- /dev/null
+++ b/web/public/422.xhtml
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>The change you wanted was rejected (422)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/422.html -->
+ <div class="dialog">
+ <h1>The change you wanted was rejected.</h1>
+ <p>Maybe you tried to change something you didn't have access to.</p>
+ </div>
+</body>
+</html>
diff --git a/web/public/500.xhtml b/web/public/500.xhtml
new file mode 100644
index 0000000..f3648a0
--- /dev/null
+++ b/web/public/500.xhtml
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>We're sorry, but something went wrong (500)</title>
+ <style type="text/css">
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+ div.dialog {
+ width: 25em;
+ padding: 0 4em;
+ margin: 4em auto 0 auto;
+ border: 1px solid #ccc;
+ border-right-color: #999;
+ border-bottom-color: #999;
+ }
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+ </style>
+</head>
+
+<body>
+ <!-- This file lives in public/500.html -->
+ <div class="dialog">
+ <h1>We're sorry, but something went wrong.</h1>
+ </div>
+</body>
+</html>
diff --git a/web/public/favicon.ico b/web/public/favicon.ico
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/public/favicon.ico
diff --git a/web/script/rails b/web/script/rails
new file mode 100755
index 0000000..f8da2cf
--- /dev/null
+++ b/web/script/rails
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
+
+APP_PATH = File.expand_path('../../config/application', __FILE__)
+require File.expand_path('../../config/boot', __FILE__)
+require 'rails/commands'
diff --git a/web/vendor/assets/javascripts/.gitkeep b/web/vendor/assets/javascripts/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/vendor/assets/javascripts/.gitkeep
diff --git a/web/vendor/assets/stylesheets/.gitkeep b/web/vendor/assets/stylesheets/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/vendor/assets/stylesheets/.gitkeep
diff --git a/web/vendor/plugins/.gitkeep b/web/vendor/plugins/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/web/vendor/plugins/.gitkeep
diff --git a/worker/receiver.rb b/worker/receiver.rb
new file mode 100644
index 0000000..06680a7
--- /dev/null
+++ b/worker/receiver.rb
@@ -0,0 +1,6 @@
+module Receiver
+ require ::File.expand_path("../receiver/logger", __FILE__)
+ require ::File.expand_path("../receiver/worker", __FILE__)
+
+ # monyo
+end
diff --git a/worker/receiver/logger.rb b/worker/receiver/logger.rb
new file mode 100644
index 0000000..d00b2e1
--- /dev/null
+++ b/worker/receiver/logger.rb
@@ -0,0 +1,28 @@
+class Receiver::Logger
+ include Singleton
+
+ def debug(msg)
+ log(@out, "DEBUG", msg)
+ end
+
+ def info(msg)
+ log(@out, "INFO", msg)
+ end
+
+ def warn(msg)
+ log(@err, "WARN", msg)
+ end
+
+ def error(msg)
+ log(@err, "ERROR", msg)
+ end
+
+ def log(out, type, msg)
+ out.puts Time.now.utc.iso8601(3) + " " + type + ": " + msg
+ end
+
+ def initialize
+ @out = STDOUT
+ @err = STDERR
+ end
+end
diff --git a/worker/receiver/worker.rb b/worker/receiver/worker.rb
new file mode 100644
index 0000000..c21f876
--- /dev/null
+++ b/worker/receiver/worker.rb
@@ -0,0 +1,247 @@
+require "time"
+
+class Receiver::Worker
+ def initialize
+ @logger = Receiver::Logger.instance
+ end
+
+ # Create Aclog format text from Twitter Status Hash
+ def format_text_from_hash(hash)
+ text = hash[:text]
+ entities = hash[:entities]
+
+ return text unless entities
+
+ gaps = {}
+ replace = -> ents, bl do
+ ents.each do |entity|
+ starts = entity[:indices].first
+ ends = entity[:indices].last
+ rep = bl.call(entity)
+ gaps[starts] = rep.size - (ends - starts)
+ bgap = gaps.select{|k, v| k < starts}.values.inject(0){|s, m| s += m}
+ text[starts + bgap...ends + bgap] = rep
+ end
+ end
+
+ replace.call((entities[:media] || []) + (entities[:urls] || []),
+ -> entity {"<url:#{CGI.escapeHTML(entity[:expanded_url])}:#{CGI.escapeHTML(entity[:display_url])}>"})
+ replace.call(entities[:hashtags] || [],
+ -> entity {"<hashtag:#{CGI.escapeHTML(URI.encode(entity[:text]))}>"})
+ replace.call(entities[:user_mentions] || [],
+ -> entity {"<mention:#{CGI.escapeHTML(URI.encode(entity[:screen_name]))}>"})
+
+ return text
+ end
+
+ # Create or Update user by Twitter User Hash
+ def create_user_from_hash(user)
+ rec = User.find_or_initialize_by(:id => user[:id])
+ rec.screen_name = user[:screen_name]
+ rec.name = user[:name]
+ rec.profile_image_url = user[:profile_image_url_https]
+ rec.save! if rec.changed?
+
+ return rec
+ end
+
+ # Create tweet by Twitter Status Hash
+ def create_tweet_from_hash(status)
+ Tweet.find_by(:id => status[:id]) ||
+ Tweet.create!(:id => status[:id],
+ :text => format_text_from_hash(status),
+ :source => status[:source],
+ :tweeted_at => Time.parse(status[:created_at]),
+ :user => create_user_from_hash(status[:user]))
+ end
+
+ def destroy_tweet_from_hash(status)
+ Tweet.delete(status[:delete][:status][:id])
+ end
+
+ # Create Retweet by Twitter Status Hash
+ def create_retweet_from_hash(status)
+ Retweet.find_by(:id => status[:id]) ||
+ Retweet.create!(:id => status[:id],
+ :tweet => create_tweet_from_hash(status[:retweeted_status]),
+ :user => create_user_from_hash(status[:user]))
+ end
+
+ # Create Favorite by Streaming Event Hash
+ def create_favorite_from_hash(status)
+ user = create_user_from_hash(status[:source])
+ user.favorites.find_by(:tweet_id => status[:target_object][:id]) ||
+ user.favorites.create!(:tweet => create_tweet_from_hash(status[:target_object]))
+ end
+
+ def destroy_favorite_from_hash(status)
+ Favorite.delete_all("tweet_id = #{status[:target_object][:id]} AND " +
+ "user_id = #{status[:source][:id]}")
+ end
+
+ def start
+ EM.run do
+ # UserStreams connections
+ @connections = []
+
+ stop = Proc.new do
+ @connections.map(&:stop)
+ EM.stop
+ end
+ Signal.trap(:INT, &stop)
+ Signal.trap(:TERM, &stop)
+
+ register = -> account do
+ con = EM::Twitter::Client.connect({
+ :host => "userstream.twitter.com",
+ :path => "/1.1/user.json",
+ :oauth => {:consumer_key => Settings.consumer_key,
+ :consumer_secret => Settings.consumer_secret,
+ :token => account.oauth_token,
+ :token_secret => account.oauth_token_secret},
+ :method => "GET",
+ # user data
+ :user_id => account.id
+ })
+
+ con.on_reconnect do |timeout, count|
+ @logger.warn("Reconnected: #{con.options[:user_id]}/#{count}")
+ end
+
+ con.on_max_reconnects do |timeout, count|
+ @logger.error("Reached Max Reconnects: #{con.options[:user_id]}")
+ end
+
+ con.on_unauthorized do
+ @logger.error("Unauthorized: #{con.options[:user_id]}")
+ end
+
+ con.on_forbidden do
+ @logger.error("Forbidden: #{con.options[:user_id]}")
+ end
+
+ con.on_not_found do
+ @logger.error("Not Found: #{con.options[:user_id]}")
+ end
+
+ con.on_not_acceptable do
+ @logger.error("Not Acceptable: #{con.options[:user_id]}")
+ end
+
+ con.on_too_long do
+ @logger.error("Too Long: #{con.options[:user_id]}")
+ end
+
+ con.on_range_unacceptable do
+ @logger.error("Range Unacceptable: #{con.options[:user_id]}")
+ end
+
+ con.on_enhance_your_calm do
+ @logger.error("Enhance Your Calm: #{con.options[:user_id]}")
+ end
+
+ con.on_error do |message|
+ @logger.error("Unknown: #{con.options[:user_id]}/#{message}")
+ end
+
+ con.each do |json|
+ begin # convert error
+ begin
+ status = ::Yajl::Parser.parse(json, :symbolize_keys => true)
+ rescue ::Yajl::ParseError
+ @logger.warn("::Yajl::ParseError in stream: #{json}")
+ next
+ end
+
+ if status.is_a?(::Hash)
+ if status.key?(:user)
+ # Tweet or Retweet
+ if status[:user][:id] == con.options[:user_id] &&
+ !status.key?(:retweeted_status)
+ # Tweet
+ create_tweet_from_hash(status)
+ @logger.debug("Created Tweet")
+ elsif status.key?(:retweeted_status) &&
+ (status[:retweeted_status][:user][:id] == con.options[:user_id] ||
+ status[:user][:id] == con.options[:user_id])
+ # Retweet
+ create_retweet_from_hash(status)
+ @logger.debug("Created Retweet")
+ end
+ elsif status[:event] == "favorite"
+ # Favorite
+ create_favorite_from_hash(status)
+ @logger.debug("Created Favorite")
+ elsif status[:event] == "unfavorite"
+ # Unfavorite
+ destroy_favorite_from_hash(status)
+ @logger.debug("Destroyed Favorite")
+ elsif status.key?(:delete) && status[:delete].key?(:status)
+ # Delete
+ destroy_tweet_from_hash(status)
+ @logger.debug("Destroyed Tweet")
+ else
+ # Else - do nothing
+ # p status
+ end
+ else
+ @logger.warn("Unexpected object in stream: #{status}")
+ next
+ end
+ rescue # debug
+ @logger.error($!)
+ @logger.error($@)
+ end
+ end
+
+ @logger.info("User connected: #{con.options[:user_id]}")
+ @connections << con
+ end
+
+ # EventReceiver
+ EM.start_server("127.0.0.1", Settings.worker_port) do |server|
+ def server.receive_data(data)
+ d = data.split(/ /)
+
+ if handle_event(d[0].to_sym, s[1].to_i)
+ send_data "Accepted\r\n"
+ else
+ send_data "Denied\r\n"
+ end
+
+ close_connection_after_writing
+ end
+
+ def handle_event(command, id)
+ case command
+ when :REGISTER
+ if account = Account.find_by(:id => id)
+ register.call(account)
+ return true
+ else
+ return false
+ end
+ end
+ end
+ end
+
+ reconnect = -> do
+ Account.all.each do |account|
+ if con = @connections.find{|m| m.options[:user_id] == account.id}
+ con.immediate_reconnect
+ else
+ register.call(account)
+ end
+ end
+ end
+
+ EM.add_periodic_timer(30 * 60) do
+ reconnect.call
+ end
+
+ reconnect.call
+ end
+ end
+end
+
+