Purged git history and removed sensitive information.

This commit is contained in:
Luke Barratt 2014-03-23 00:22:25 +00:00
commit 6bcc8dc76b
862 changed files with 25312 additions and 0 deletions

8
.env.sample Normal file
View file

@ -0,0 +1,8 @@
UNICORN_WORKERS=3
UNICORN_PORT=5000
UNICORN_SOCKET=/tmp/unicorn.ensl.sock
APP_SECRET=
MYSQL_USERNAME=
MYSQL_PASSWORD=

40
.gitignore vendored Normal file
View file

@ -0,0 +1,40 @@
# Rails, etc
/coverage/
/log/*
/tmp/*
/spec/tmp/*
.env
.tmp*
.rspec
.sass-cache
*.sassc
*.rbc
*.sassc
# OS X
.DS_Store
# Assets
/public/system/*
/public/files
/public/files/*
/public/local
# RubyMine
/.idea
# VIM
**.swp
# Git junk
**.orig
# Bundler
/.bundle
/vendor/bundle/
.bundle
# Misc
/index/*
rerun.txt
pickle-email-*.html

1
.ruby-version Normal file
View file

@ -0,0 +1 @@
2.1.1

7
Capfile Normal file
View file

@ -0,0 +1,7 @@
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails'
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

52
Gemfile Normal file
View file

@ -0,0 +1,52 @@
source 'http://rubygems.org'
ruby '2.1.1'
gem 'rails', '~> 3.2.16'
gem 'mysql2', '~> 0.3.15'
# Deployment
gem 'foreman', '~> 0.63.0'
gem 'capistrano', '~> 3.1.0'
gem 'capistrano-rbenv', '~> 2.0.2'
gem 'capistrano-bundler', '~> 1.1.2'
gem 'capistrano-rails', '~> 1.1'
# Libraries
gem 'jquery-rails'
gem 'sass-rails'
gem 'coffee-rails'
gem 'gruff'
gem 'nokogiri'
gem 'carrierwave'
gem 'rbbcode'
gem 'tinymce-rails'
gem 'bluecloth', '~> 2.2.0'
gem 'bb-ruby'
gem 'therubyracer'
gem 'acts_as_indexed'
gem 'rmagick', require: false
gem 'will_paginate', git: 'https://github.com/p7r/will_paginate.git', branch: 'rails3'
gem 'newrelic_rpm', '~> 3.7.2.195'
group 'staging', 'production' do
gem 'unicorn', '~> 4.8.2'
end
group 'development' do
gem 'annotate', '~> 2.6.2'
end
group 'test' do
gem 'simplecov', '~> 0.7.1', require: false
gem 'rspec-rails', '~> 2.14.1'
gem 'rspec-given', '~> 3.5.4'
gem 'capybara', '~> 2.2.1'
gem 'poltergeist', '~> 1.5.0'
gem 'factory_girl_rails', '~> 4.4.1'
end
group 'development', 'test' do
gem 'pry-debugger', '~> 0.2.2'
gem 'dotenv-rails', '~> 0.10.0'
end

275
Gemfile.lock Normal file
View file

@ -0,0 +1,275 @@
GIT
remote: https://github.com/p7r/will_paginate.git
revision: 53d1da6da003dc172ee054e4cc416d0723f00b88
branch: rails3
specs:
will_paginate (3.0.pre3)
GEM
remote: http://rubygems.org/
specs:
actionmailer (3.2.17)
actionpack (= 3.2.17)
mail (~> 2.5.4)
actionpack (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
activerecord (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
activesupport (3.2.17)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
acts_as_indexed (0.7.8)
annotate (2.6.2)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
arel (3.0.3)
bb-ruby (0.9.5)
bluecloth (2.2.0)
builder (3.0.4)
capistrano (3.1.0)
i18n
rake (>= 10.0.0)
sshkit (~> 1.3)
capistrano-bundler (1.1.2)
capistrano (~> 3.0)
sshkit (~> 1.2)
capistrano-rails (1.1.1)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capistrano-rbenv (2.0.2)
capistrano (~> 3.1)
sshkit (~> 1.3)
capybara (2.2.1)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
carrierwave (0.6.2)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
cliver (0.3.2)
coderay (1.1.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.3.3)
columnize (0.3.6)
debugger (1.6.6)
columnize (>= 0.3.1)
debugger-linecache (~> 1.2.0)
debugger-ruby_core_source (~> 1.3.2)
debugger-linecache (1.2.0)
debugger-ruby_core_source (1.3.2)
diff-lcs (1.2.5)
dotenv (0.10.0)
dotenv-rails (0.10.0)
dotenv (= 0.10.0)
erubis (2.7.0)
execjs (1.4.0)
multi_json (~> 1.0)
factory_girl (4.4.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.4.1)
factory_girl (~> 4.4.0)
railties (>= 3.0.0)
foreman (0.63.0)
dotenv (>= 0.7)
thor (>= 0.13.6)
foreman (0.63.0-x86-mingw32)
dotenv (>= 0.7)
thor (>= 0.13.6)
win32console (~> 1.3.0)
given_core (3.5.4)
sorcerer (>= 0.3.7)
gruff (0.3.6)
hike (1.2.3)
i18n (0.6.9)
journey (1.0.4)
jquery-rails (2.0.2)
railties (>= 3.2.0, < 5.0)
thor (~> 0.14)
json (1.8.1)
kgio (2.9.2)
libv8 (3.16.14.3)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
method_source (0.8.2)
mime-types (1.25.1)
multi_json (1.8.4)
mysql2 (0.3.15)
net-scp (1.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.8.0)
newrelic_rpm (3.7.2.195)
nokogiri (1.5.5)
nokogiri (1.5.5-x86-mingw32)
poltergeist (1.5.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
polyglot (0.3.4)
pry (0.9.12.6)
coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
pry (0.9.12.6-x86-mingw32)
coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
win32console (~> 1.3)
pry-debugger (0.2.2)
debugger (~> 1.3)
pry (~> 0.9.10)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rails (3.2.17)
actionmailer (= 3.2.17)
actionpack (= 3.2.17)
activerecord (= 3.2.17)
activeresource (= 3.2.17)
activesupport (= 3.2.17)
bundler (~> 1.0)
railties (= 3.2.17)
railties (3.2.17)
actionpack (= 3.2.17)
activesupport (= 3.2.17)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.13.0)
rake (10.1.1)
rbbcode (0.1.11)
sanitize-url (>= 0.1.3)
rdoc (3.12.2)
json (~> 1.4)
ref (1.0.5)
rmagick (2.13.1)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.8)
rspec-expectations (2.14.5)
diff-lcs (>= 1.1.3, < 2.0)
rspec-given (3.5.4)
given_core (= 3.5.4)
rspec (>= 2.12)
rspec-mocks (2.14.6)
rspec-rails (2.14.1)
actionpack (>= 3.0)
activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
sanitize-url (0.1.4)
sass (3.1.20)
sass-rails (3.2.5)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
slop (3.4.7)
sorcerer (1.0.2)
sprockets (2.2.2)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sshkit (1.3.0)
net-scp (>= 1.1.2)
net-ssh
term-ansicolor
term-ansicolor (1.3.0)
tins (~> 1.0)
therubyracer (0.12.1)
libv8 (~> 3.16.14.0)
ref
thor (0.18.1)
tilt (1.4.1)
tins (1.0.1)
tinymce-rails (3.5.4.1)
railties (>= 3.1.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.38)
unicorn (4.8.2)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
websocket-driver (0.3.2)
win32console (1.3.2-x86-mingw32)
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS
ruby
x86-mingw32
DEPENDENCIES
acts_as_indexed
annotate (~> 2.6.2)
bb-ruby
bluecloth (~> 2.2.0)
capistrano (~> 3.1.0)
capistrano-bundler (~> 1.1.2)
capistrano-rails (~> 1.1)
capistrano-rbenv (~> 2.0.2)
capybara (~> 2.2.1)
carrierwave
coffee-rails
dotenv-rails (~> 0.10.0)
factory_girl_rails (~> 4.4.1)
foreman (~> 0.63.0)
gruff
jquery-rails
mysql2 (~> 0.3.15)
newrelic_rpm (~> 3.7.2.195)
nokogiri
poltergeist (~> 1.5.0)
pry-debugger (~> 0.2.2)
rails (~> 3.2.16)
rbbcode
rmagick
rspec-given (~> 3.5.4)
rspec-rails (~> 2.14.1)
sass-rails
simplecov (~> 0.7.1)
therubyracer
tinymce-rails
unicorn (~> 4.8.2)
will_paginate!

51
INSTALL.md Normal file
View file

@ -0,0 +1,51 @@
# Ubuntu 13.10 x64
## Capistrano setup
SSH as root, and install the basics
sudo apt-get update
sudo apt-get upgrade
Create a deploy user. Disable password authentication and add it to the www-data group.
sudo adduser deploy
sudo passwd -l deploy
sudo usermod -a -G www-data deploy
Add the following to `/etc/sudoers` to allow the `deploy` user to manage nginx and foreman via sudo without a password
# /etc/sudoers
Cmnd_Alias START_FOREMAN = /sbin/start foreman
deploy ALL=NOPASSWD:START_FOREMAN
deploy ALL=NOPASSWD:/etc/init.d/nginx
## Install rbenv, ruby and bundler
As root, install dependencies
sudo apt-get install nginx git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libmysql-ruby libmysqlclient-dev
Switch user to deploy, and install rbenv
su deploy
cd ~
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL
rbenv install 2.1.1
rbenv global 2.1.1
echo "gem: --no-ri --no-rdoc" > ~/.gemrc
gem install bundler
## Install the ENSL site
mkdir /var/www/virtual/ensl.org/deploy

1
LICENSE.md Normal file
View file

@ -0,0 +1 @@
Copyright 2014 ENSL.org

1
Procfile Normal file
View file

@ -0,0 +1 @@
web: bundle exec unicorn -p $UNICORN_PORT -l $UNICORN_SOCKET -c ./config/unicorn.rb

33
README.md Normal file
View file

@ -0,0 +1,33 @@
# ENSL Website
This is the source code of ENSL website. Currently deployed on [European NS League](http://www.ensl.org).
Features:
- Articles
- Commenting feature for most objects
- Movie database
- File database
- ENSL Plugin API
- Forums, usual forum features and ACL
- Contest management
- Teams and team member management
- Brackets
- Tournaments
- Match database
- Challenging system
- Instant webchat (shoutbox)
- Private messages
- Issue management
- Very popular AJAX-based pick-up system
- Map database
- Votable polls
- Twitter feed
- Server database and RCON interface
- Log file parsing (partially complete)
## Contributors
- [Ari Timonen](https://github.com/jirikivaari) - Original author
- [Florent Latombe](https://github.com/flatombe) - Improvements
- [Luke Barratt](https://github.com/lbarratt) - Improvements

13
Rakefile Normal file
View file

@ -0,0 +1,13 @@
# 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__)
require 'rake/dsl_definition'
require 'rake'
require 'rake/testtask'
require 'rake/task'
Ensl::Application.load_tasks

View file

@ -0,0 +1,15 @@
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require jquery.periodicalupdater
//= require jquery.jplayer.min
//= require flowplayer
//= require tinymce-jquery
//= require yetii
//= require local

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,97 @@
/*
* jPlayer Plugin for jQuery JavaScript Library
* http://www.jplayer.org
*
* Copyright (c) 2009 - 2011 Happyworm Ltd
* Dual licensed under the MIT and GPL licenses.
* - http://www.opensource.org/licenses/mit-license.php
* - http://www.gnu.org/copyleft/gpl.html
*
* Author: Mark J Panaghiston
* Version: 2.1.0
* Date: 1st September 2011
*/
(function(b,f){b.fn.jPlayer=function(a){var c=typeof a==="string",d=Array.prototype.slice.call(arguments,1),e=this,a=!c&&d.length?b.extend.apply(null,[!0,a].concat(d)):a;if(c&&a.charAt(0)==="_")return e;c?this.each(function(){var c=b.data(this,"jPlayer"),h=c&&b.isFunction(c[a])?c[a].apply(c,d):c;if(h!==c&&h!==f)return e=h,!1}):this.each(function(){var c=b.data(this,"jPlayer");c?c.option(a||{}):b.data(this,"jPlayer",new b.jPlayer(a,this))});return e};b.jPlayer=function(a,c){if(arguments.length){this.element=
b(c);this.options=b.extend(!0,{},this.options,a);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()});this._init()}};b.jPlayer.emulateMethods="load play pause";b.jPlayer.emulateStatus="src readyState networkState currentTime duration paused ended playbackRate";b.jPlayer.emulateOptions="muted volume";b.jPlayer.reservedEvent="ready flashreset resize repeat error warning";b.jPlayer.event={ready:"jPlayer_ready",flashreset:"jPlayer_flashreset",resize:"jPlayer_resize",repeat:"jPlayer_repeat",
click:"jPlayer_click",error:"jPlayer_error",warning:"jPlayer_warning",loadstart:"jPlayer_loadstart",progress:"jPlayer_progress",suspend:"jPlayer_suspend",abort:"jPlayer_abort",emptied:"jPlayer_emptied",stalled:"jPlayer_stalled",play:"jPlayer_play",pause:"jPlayer_pause",loadedmetadata:"jPlayer_loadedmetadata",loadeddata:"jPlayer_loadeddata",waiting:"jPlayer_waiting",playing:"jPlayer_playing",canplay:"jPlayer_canplay",canplaythrough:"jPlayer_canplaythrough",seeking:"jPlayer_seeking",seeked:"jPlayer_seeked",
timeupdate:"jPlayer_timeupdate",ended:"jPlayer_ended",ratechange:"jPlayer_ratechange",durationchange:"jPlayer_durationchange",volumechange:"jPlayer_volumechange"};b.jPlayer.htmlEvent="loadstart,abort,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,ratechange".split(",");b.jPlayer.pause=function(){b.each(b.jPlayer.prototype.instances,function(a,b){b.data("jPlayer").status.srcSet&&b.jPlayer("pause")})};b.jPlayer.timeFormat={showHour:!1,showMin:!0,showSec:!0,padHour:!1,padMin:!0,padSec:!0,
sepHour:":",sepMin:":",sepSec:""};b.jPlayer.convertTime=function(a){var c=new Date(a*1E3),d=c.getUTCHours(),a=c.getUTCMinutes(),c=c.getUTCSeconds(),d=b.jPlayer.timeFormat.padHour&&d<10?"0"+d:d,a=b.jPlayer.timeFormat.padMin&&a<10?"0"+a:a,c=b.jPlayer.timeFormat.padSec&&c<10?"0"+c:c;return(b.jPlayer.timeFormat.showHour?d+b.jPlayer.timeFormat.sepHour:"")+(b.jPlayer.timeFormat.showMin?a+b.jPlayer.timeFormat.sepMin:"")+(b.jPlayer.timeFormat.showSec?c+b.jPlayer.timeFormat.sepSec:"")};b.jPlayer.uaBrowser=
function(a){var a=a.toLowerCase(),b=/(opera)(?:.*version)?[ \/]([\w.]+)/,d=/(msie) ([\w.]+)/,e=/(mozilla)(?:.*? rv:([\w.]+))?/,a=/(webkit)[ \/]([\w.]+)/.exec(a)||b.exec(a)||d.exec(a)||a.indexOf("compatible")<0&&e.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}};b.jPlayer.uaPlatform=function(a){var b=a.toLowerCase(),d=/(android)/,e=/(mobile)/,a=/(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/.exec(b)||[],b=/(ipad|playbook)/.exec(b)||!e.exec(b)&&d.exec(b)||[];a[1]&&(a[1]=a[1].replace(/\s/g,
"_"));return{platform:a[1]||"",tablet:b[1]||""}};b.jPlayer.browser={};b.jPlayer.platform={};var i=b.jPlayer.uaBrowser(navigator.userAgent);if(i.browser)b.jPlayer.browser[i.browser]=!0,b.jPlayer.browser.version=i.version;i=b.jPlayer.uaPlatform(navigator.userAgent);if(i.platform)b.jPlayer.platform[i.platform]=!0,b.jPlayer.platform.mobile=!i.tablet,b.jPlayer.platform.tablet=!!i.tablet;b.jPlayer.prototype={count:0,version:{script:"2.1.0",needFlash:"2.1.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",
supplied:"mp3",preload:"metadata",volume:0.8,muted:!1,wmode:"opaque",backgroundColor:"#000000",cssSelectorAncestor:"#jp_container_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",volumeMax:".jp-volume-max",currentTime:".jp-current-time",duration:".jp-duration",fullScreen:".jp-full-screen",restoreScreen:".jp-restore-screen",
repeat:".jp-repeat",repeatOff:".jp-repeat-off",gui:".jp-gui",noSolution:".jp-no-solution"},fullScreen:!1,autohide:{restored:!1,full:!0,fadeIn:200,fadeOut:600,hold:1E3},loop:!1,repeat:function(a){a.jPlayer.options.loop?b(this).unbind(".jPlayerRepeat").bind(b.jPlayer.event.ended+".jPlayer.jPlayerRepeat",function(){b(this).jPlayer("play")}):b(this).unbind(".jPlayerRepeat")},nativeVideoControls:{},noFullScreen:{msie:/msie [0-6]/,ipad:/ipad.*?os [0-4]/,iphone:/iphone/,ipod:/ipod/,android_pad:/android [0-3](?!.*?mobile)/,
android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,webos:/webos/},noVolume:{ipad:/ipad/,iphone:/iphone/,ipod:/ipod/,android_pad:/android(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,webos:/webos/,playbook:/playbook/},verticalVolume:!1,idPrefix:"jp",noConflict:"jQuery",emulateHtml:!1,errorAlerts:!1,warningAlerts:!1},optionsAudio:{size:{width:"0px",height:"0px",cssClass:""},sizeFull:{width:"0px",height:"0px",cssClass:""}},
optionsVideo:{size:{width:"480px",height:"270px",cssClass:"jp-video-270p"},sizeFull:{width:"100%",height:"100%",cssClass:"jp-video-full"}},instances:{},status:{src:"",media:{},paused:!0,format:{},formatType:"",waitForPlay:!0,waitForLoad:!0,srcSet:!1,video:!1,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0,readyState:0,networkState:0,playbackRate:1,ended:0},internal:{ready:!1},solution:{html:!0,flash:!0},format:{mp3:{codec:'audio/mpeg; codecs="mp3"',flashCanPlay:!0,
media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:!0,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis"',flashCanPlay:!1,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:!1,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:!1,media:"audio"},fla:{codec:"audio/x-flv",flashCanPlay:!0,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!0,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',flashCanPlay:!1,
media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:!1,media:"video"},flv:{codec:"video/x-flv",flashCanPlay:!0,media:"video"}},_init:function(){var a=this;this.element.empty();this.status=b.extend({},this.status);this.internal=b.extend({},this.internal);this.internal.domNode=this.element.get(0);this.formats=[];this.solutions=[];this.require={};this.htmlElement={};this.html={};this.html.audio={};this.html.video={};this.flash={};this.css={};this.css.cs={};this.css.jq={};this.ancestorJq=
[];this.options.volume=this._limitValue(this.options.volume,0,1);b.each(this.options.supplied.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.format[e]){var f=!1;b.each(a.formats,function(a,b){if(e===b)return f=!0,!1});f||a.formats.push(e)}});b.each(this.options.solution.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.solution[e]){var f=!1;b.each(a.solutions,function(a,b){if(e===b)return f=!0,!1});f||a.solutions.push(e)}});this.internal.instance=
"jp_"+this.count;this.instances[this.internal.instance]=this.element;this.element.attr("id")||this.element.attr("id",this.options.idPrefix+"_jplayer_"+this.count);this.internal.self=b.extend({},{id:this.element.attr("id"),jq:this.element});this.internal.audio=b.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:f});this.internal.video=b.extend({},{id:this.options.idPrefix+"_video_"+this.count,jq:f});this.internal.flash=b.extend({},{id:this.options.idPrefix+"_flash_"+this.count,jq:f,swf:this.options.swfPath+
(this.options.swfPath.toLowerCase().slice(-4)!==".swf"?(this.options.swfPath&&this.options.swfPath.slice(-1)!=="/"?"/":"")+"Jplayer.swf":"")});this.internal.poster=b.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:f});b.each(b.jPlayer.event,function(b,c){a.options[b]!==f&&(a.element.bind(c+".jPlayer",a.options[b]),a.options[b]=f)});this.require.audio=!1;this.require.video=!1;b.each(this.formats,function(b,c){a.require[a.format[c].media]=!0});this.options=this.require.video?b.extend(!0,
{},this.optionsVideo,this.options):b.extend(!0,{},this.optionsAudio,this.options);this._setSize();this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullScreen=this._uaBlocklist(this.options.noFullScreen);this.status.noVolume=this._uaBlocklist(this.options.noVolume);this._restrictNativeVideoControls();this.htmlElement.poster=document.createElement("img");this.htmlElement.poster.id=this.internal.poster.id;this.htmlElement.poster.onload=function(){(!a.status.video||
a.status.waitForPlay)&&a.internal.poster.jq.show()};this.element.append(this.htmlElement.poster);this.internal.poster.jq=b("#"+this.internal.poster.id);this.internal.poster.jq.css({width:this.status.width,height:this.status.height});this.internal.poster.jq.hide();this.internal.poster.jq.bind("click.jPlayer",function(){a._trigger(b.jPlayer.event.click)});this.html.audio.available=!1;if(this.require.audio)this.htmlElement.audio=document.createElement("audio"),this.htmlElement.audio.id=this.internal.audio.id,
this.html.audio.available=!!this.htmlElement.audio.canPlayType&&this._testCanPlayType(this.htmlElement.audio);this.html.video.available=!1;if(this.require.video)this.htmlElement.video=document.createElement("video"),this.htmlElement.video.id=this.internal.video.id,this.html.video.available=!!this.htmlElement.video.canPlayType&&this._testCanPlayType(this.htmlElement.video);this.flash.available=this._checkForFlash(10);this.html.canPlay={};this.flash.canPlay={};b.each(this.formats,function(b,c){a.html.canPlay[c]=
a.html[a.format[c].media].available&&""!==a.htmlElement[a.format[c].media].canPlayType(a.format[c].codec);a.flash.canPlay[c]=a.format[c].flashCanPlay&&a.flash.available});this.html.desired=!1;this.flash.desired=!1;b.each(this.solutions,function(c,d){if(c===0)a[d].desired=!0;else{var e=!1,f=!1;b.each(a.formats,function(b,c){a[a.solutions[0]].canPlay[c]&&(a.format[c].media==="video"?f=!0:e=!0)});a[d].desired=a.require.audio&&!e||a.require.video&&!f}});this.html.support={};this.flash.support={};b.each(this.formats,
function(b,c){a.html.support[c]=a.html.canPlay[c]&&a.html.desired;a.flash.support[c]=a.flash.canPlay[c]&&a.flash.desired});this.html.used=!1;this.flash.used=!1;b.each(this.solutions,function(c,d){b.each(a.formats,function(b,c){if(a[d].support[c])return a[d].used=!0,!1})});this._resetActive();this._resetGate();this._cssSelectorAncestor(this.options.cssSelectorAncestor);!this.html.used&&!this.flash.used?(this._error({type:b.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+
this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SOLUTION,hint:b.jPlayer.errorHint.NO_SOLUTION}),this.css.jq.noSolution.length&&this.css.jq.noSolution.show()):this.css.jq.noSolution.length&&this.css.jq.noSolution.hide();if(this.flash.used){var c,d="jQuery="+encodeURI(this.options.noConflict)+"&id="+encodeURI(this.internal.self.id)+"&vol="+this.options.volume+"&muted="+this.options.muted;if(b.browser.msie&&Number(b.browser.version)<=8){d=['<param name="movie" value="'+this.internal.flash.swf+
'" />','<param name="FlashVars" value="'+d+'" />','<param name="allowScriptAccess" value="always" />','<param name="bgcolor" value="'+this.options.backgroundColor+'" />','<param name="wmode" value="'+this.options.wmode+'" />'];c=document.createElement('<object id="'+this.internal.flash.id+'" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0"></object>');for(var e=0;e<d.length;e++)c.appendChild(document.createElement(d[e]))}else e=function(a,b,c){var d=document.createElement("param");
d.setAttribute("name",b);d.setAttribute("value",c);a.appendChild(d)},c=document.createElement("object"),c.setAttribute("id",this.internal.flash.id),c.setAttribute("data",this.internal.flash.swf),c.setAttribute("type","application/x-shockwave-flash"),c.setAttribute("width","1"),c.setAttribute("height","1"),e(c,"flashvars",d),e(c,"allowscriptaccess","always"),e(c,"bgcolor",this.options.backgroundColor),e(c,"wmode",this.options.wmode);this.element.append(c);this.internal.flash.jq=b(c)}if(this.html.used){if(this.html.audio.available)this._addHtmlEventListeners(this.htmlElement.audio,
this.html.audio),this.element.append(this.htmlElement.audio),this.internal.audio.jq=b("#"+this.internal.audio.id);if(this.html.video.available)this._addHtmlEventListeners(this.htmlElement.video,this.html.video),this.element.append(this.htmlElement.video),this.internal.video.jq=b("#"+this.internal.video.id),this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):this.internal.video.jq.css({width:"0px",height:"0px"}),this.internal.video.jq.bind("click.jPlayer",
function(){a._trigger(b.jPlayer.event.click)})}this.options.emulateHtml&&this._emulateHtmlBridge();this.html.used&&!this.flash.used&&setTimeout(function(){a.internal.ready=!0;a.version.flash="n/a";a._trigger(b.jPlayer.event.repeat);a._trigger(b.jPlayer.event.ready)},100);this._updateNativeVideoControls();this._updateInterface();this._updateButtons(!1);this._updateAutohide();this._updateVolume(this.options.volume);this._updateMute(this.options.muted);this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();
b.jPlayer.prototype.count++},destroy:function(){this.clearMedia();this._removeUiClass();this.css.jq.currentTime.length&&this.css.jq.currentTime.text("");this.css.jq.duration.length&&this.css.jq.duration.text("");b.each(this.css.jq,function(a,b){b.length&&b.unbind(".jPlayer")});this.internal.poster.jq.unbind(".jPlayer");this.internal.video.jq&&this.internal.video.jq.unbind(".jPlayer");this.options.emulateHtml&&this._destroyHtmlBridge();this.element.removeData("jPlayer");this.element.unbind(".jPlayer");
this.element.empty();delete this.instances[this.internal.instance]},enable:function(){},disable:function(){},_testCanPlayType:function(a){try{return a.canPlayType(this.format.mp3.codec),!0}catch(b){return!1}},_uaBlocklist:function(a){var c=navigator.userAgent.toLowerCase(),d=!1;b.each(a,function(a,b){if(b&&b.test(c))return d=!0,!1});return d},_restrictNativeVideoControls:function(){if(this.require.audio&&this.status.nativeVideoControls)this.status.nativeVideoControls=!1,this.status.noFullScreen=!0},
_updateNativeVideoControls:function(){if(this.html.video.available&&this.html.used)this.htmlElement.video.controls=this.status.nativeVideoControls,this._updateAutohide(),this.status.nativeVideoControls&&this.require.video?(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height})):this.status.waitForPlay&&this.status.video&&(this.internal.poster.jq.show(),this.internal.video.jq.css({width:"0px",height:"0px"}))},_addHtmlEventListeners:function(a,
c){var d=this;a.preload=this.options.preload;a.muted=this.options.muted;a.volume=this.options.volume;a.addEventListener("progress",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.progress))},!1);a.addEventListener("timeupdate",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.timeupdate))},!1);a.addEventListener("durationchange",function(){if(c.gate)d.status.duration=this.duration,d._getHtmlStatus(a),d._updateInterface(),
d._trigger(b.jPlayer.event.durationchange)},!1);a.addEventListener("play",function(){c.gate&&(d._updateButtons(!0),d._html_checkWaitForPlay(),d._trigger(b.jPlayer.event.play))},!1);a.addEventListener("playing",function(){c.gate&&(d._updateButtons(!0),d._seeked(),d._trigger(b.jPlayer.event.playing))},!1);a.addEventListener("pause",function(){c.gate&&(d._updateButtons(!1),d._trigger(b.jPlayer.event.pause))},!1);a.addEventListener("waiting",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.waiting))},
!1);a.addEventListener("seeking",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.seeking))},!1);a.addEventListener("seeked",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.seeked))},!1);a.addEventListener("volumechange",function(){if(c.gate)d.options.volume=a.volume,d.options.muted=a.muted,d._updateMute(),d._updateVolume(),d._trigger(b.jPlayer.event.volumechange)},!1);a.addEventListener("suspend",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.suspend))},!1);a.addEventListener("ended",
function(){if(c.gate){if(!b.jPlayer.browser.webkit)d.htmlElement.media.currentTime=0;d.htmlElement.media.pause();d._updateButtons(!1);d._getHtmlStatus(a,!0);d._updateInterface();d._trigger(b.jPlayer.event.ended)}},!1);a.addEventListener("error",function(){if(c.gate&&(d._updateButtons(!1),d._seeked(),d.status.srcSet))clearTimeout(d.internal.htmlDlyCmdId),d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),
d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:b.jPlayer.error.URL,context:d.status.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL})},!1);b.each(b.jPlayer.htmlEvent,function(e,g){a.addEventListener(this,function(){c.gate&&d._trigger(b.jPlayer.event[g])},!1)})},_getHtmlStatus:function(a,b){var d=0,e=0,g=0,f=0;if(a.duration)this.status.duration=a.duration;d=a.currentTime;
e=this.status.duration>0?100*d/this.status.duration:0;typeof a.seekable==="object"&&a.seekable.length>0?(g=this.status.duration>0?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100,f=100*a.currentTime/a.seekable.end(a.seekable.length-1)):(g=100,f=e);b&&(e=f=d=0);this.status.seekPercent=g;this.status.currentPercentRelative=f;this.status.currentPercentAbsolute=e;this.status.currentTime=d;this.status.readyState=a.readyState;this.status.networkState=a.networkState;this.status.playbackRate=
a.playbackRate;this.status.ended=a.ended},_resetStatus:function(){this.status=b.extend({},this.status,b.jPlayer.prototype.status)},_trigger:function(a,c,d){a=b.Event(a);a.jPlayer={};a.jPlayer.version=b.extend({},this.version);a.jPlayer.options=b.extend(!0,{},this.options);a.jPlayer.status=b.extend(!0,{},this.status);a.jPlayer.html=b.extend(!0,{},this.html);a.jPlayer.flash=b.extend(!0,{},this.flash);if(c)a.jPlayer.error=b.extend({},c);if(d)a.jPlayer.warning=b.extend({},d);this.element.trigger(a)},
jPlayerFlashEvent:function(a,c){if(a===b.jPlayer.event.ready)if(this.internal.ready){if(this.flash.gate){if(this.status.srcSet){var d=this.status.currentTime,e=this.status.paused;this.setMedia(this.status.media);d>0&&(e?this.pause(d):this.play(d))}this._trigger(b.jPlayer.event.flashreset)}}else this.internal.ready=!0,this.internal.flash.jq.css({width:"0px",height:"0px"}),this.version.flash=c.version,this.version.needFlash!==this.version.flash&&this._error({type:b.jPlayer.error.VERSION,context:this.version.flash,
message:b.jPlayer.errorMsg.VERSION+this.version.flash,hint:b.jPlayer.errorHint.VERSION}),this._trigger(b.jPlayer.event.repeat),this._trigger(a);if(this.flash.gate)switch(a){case b.jPlayer.event.progress:this._getFlashStatus(c);this._updateInterface();this._trigger(a);break;case b.jPlayer.event.timeupdate:this._getFlashStatus(c);this._updateInterface();this._trigger(a);break;case b.jPlayer.event.play:this._seeked();this._updateButtons(!0);this._trigger(a);break;case b.jPlayer.event.pause:this._updateButtons(!1);
this._trigger(a);break;case b.jPlayer.event.ended:this._updateButtons(!1);this._trigger(a);break;case b.jPlayer.event.click:this._trigger(a);break;case b.jPlayer.event.error:this.status.waitForLoad=!0;this.status.waitForPlay=!0;this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"});this._validString(this.status.media.poster)&&this.internal.poster.jq.show();this.css.jq.videoPlay.length&&this.status.video&&this.css.jq.videoPlay.show();this.status.video?this._flash_setVideo(this.status.media):
this._flash_setAudio(this.status.media);this._updateButtons(!1);this._error({type:b.jPlayer.error.URL,context:c.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL});break;case b.jPlayer.event.seeking:this._seeking();this._trigger(a);break;case b.jPlayer.event.seeked:this._seeked();this._trigger(a);break;case b.jPlayer.event.ready:break;default:this._trigger(a)}return!1},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent;this.status.currentPercentRelative=a.currentPercentRelative;
this.status.currentPercentAbsolute=a.currentPercentAbsolute;this.status.currentTime=a.currentTime;this.status.duration=a.duration;this.status.readyState=4;this.status.networkState=0;this.status.playbackRate=1;this.status.ended=!1},_updateButtons:function(a){if(a!==f)this.status.paused=!a,this.css.jq.play.length&&this.css.jq.pause.length&&(a?(this.css.jq.play.hide(),this.css.jq.pause.show()):(this.css.jq.play.show(),this.css.jq.pause.hide()));this.css.jq.restoreScreen.length&&this.css.jq.fullScreen.length&&
(this.status.noFullScreen?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.hide()):this.options.fullScreen?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.show()):(this.css.jq.fullScreen.show(),this.css.jq.restoreScreen.hide()));this.css.jq.repeat.length&&this.css.jq.repeatOff.length&&(this.options.loop?(this.css.jq.repeat.hide(),this.css.jq.repeatOff.show()):(this.css.jq.repeat.show(),this.css.jq.repeatOff.hide()))},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+
"%");this.css.jq.playBar.length&&this.css.jq.playBar.width(this.status.currentPercentRelative+"%");this.css.jq.currentTime.length&&this.css.jq.currentTime.text(b.jPlayer.convertTime(this.status.currentTime));this.css.jq.duration.length&&this.css.jq.duration.text(b.jPlayer.convertTime(this.status.duration))},_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg")},
_resetGate:function(){this.html.audio.gate=!1;this.html.video.gate=!1;this.flash.gate=!1},_resetActive:function(){this.html.active=!1;this.flash.active=!1},setMedia:function(a){var c=this,d=!1,e=this.status.media.poster!==a.poster;this._resetMedia();this._resetGate();this._resetActive();b.each(this.formats,function(e,f){var i=c.format[f].media==="video";b.each(c.solutions,function(b,e){if(c[e].support[f]&&c._validString(a[f])){var g=e==="html";i?(g?(c.html.video.gate=!0,c._html_setVideo(a),c.html.active=
!0):(c.flash.gate=!0,c._flash_setVideo(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.show(),c.status.video=!0):(g?(c.html.audio.gate=!0,c._html_setAudio(a),c.html.active=!0):(c.flash.gate=!0,c._flash_setAudio(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.hide(),c.status.video=!1);d=!0;return!1}});if(d)return!1});if(d){if((!this.status.nativeVideoControls||!this.html.video.gate)&&this._validString(a.poster))e?this.htmlElement.poster.src=a.poster:this.internal.poster.jq.show();
this.status.srcSet=!0;this.status.media=b.extend({},a);this._updateButtons(!1);this._updateInterface()}else this._error({type:b.jPlayer.error.NO_SUPPORT,context:"{supplied:'"+this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SUPPORT,hint:b.jPlayer.errorHint.NO_SUPPORT})},_resetMedia:function(){this._resetStatus();this._updateButtons(!1);this._updateInterface();this._seeked();this.internal.poster.jq.hide();clearTimeout(this.internal.htmlDlyCmdId);this.html.active?this._html_resetMedia():this.flash.active&&
this._flash_resetMedia()},clearMedia:function(){this._resetMedia();this.html.active?this._html_clearMedia():this.flash.active&&this._flash_clearMedia();this._resetGate();this._resetActive()},load:function(){this.status.srcSet?this.html.active?this._html_load():this.flash.active&&this._flash_load():this._urlNotSetError("load")},play:function(a){a=typeof a==="number"?a:NaN;this.status.srcSet?this.html.active?this._html_play(a):this.flash.active&&this._flash_play(a):this._urlNotSetError("play")},videoPlay:function(){this.play()},
pause:function(a){a=typeof a==="number"?a:NaN;this.status.srcSet?this.html.active?this._html_pause(a):this.flash.active&&this._flash_pause(a):this._urlNotSetError("pause")},pauseOthers:function(){var a=this;b.each(this.instances,function(b,d){a.element!==d&&d.data("jPlayer").status.srcSet&&d.jPlayer("pause")})},stop:function(){this.status.srcSet?this.html.active?this._html_pause(0):this.flash.active&&this._flash_pause(0):this._urlNotSetError("stop")},playHead:function(a){a=this._limitValue(a,0,100);
this.status.srcSet?this.html.active?this._html_playHead(a):this.flash.active&&this._flash_playHead(a):this._urlNotSetError("playHead")},_muted:function(a){this.options.muted=a;this.html.used&&this._html_mute(a);this.flash.used&&this._flash_mute(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateMute(a),this._updateVolume(this.options.volume),this._trigger(b.jPlayer.event.volumechange))},mute:function(a){a=a===f?!0:!!a;this._muted(a)},unmute:function(a){a=a===f?!0:!!a;this._muted(!a)},_updateMute:function(a){if(a===
f)a=this.options.muted;this.css.jq.mute.length&&this.css.jq.unmute.length&&(this.status.noVolume?(this.css.jq.mute.hide(),this.css.jq.unmute.hide()):a?(this.css.jq.mute.hide(),this.css.jq.unmute.show()):(this.css.jq.mute.show(),this.css.jq.unmute.hide()))},volume:function(a){a=this._limitValue(a,0,1);this.options.volume=a;this.html.used&&this._html_volume(a);this.flash.used&&this._flash_volume(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateVolume(a),this._trigger(b.jPlayer.event.volumechange))},
volumeBar:function(a){if(this.css.jq.volumeBar.length){var b=this.css.jq.volumeBar.offset(),d=a.pageX-b.left,e=this.css.jq.volumeBar.width(),a=this.css.jq.volumeBar.height()-a.pageY+b.top,b=this.css.jq.volumeBar.height();this.options.verticalVolume?this.volume(a/b):this.volume(d/e)}this.options.muted&&this._muted(!1)},volumeBarValue:function(a){this.volumeBar(a)},_updateVolume:function(a){if(a===f)a=this.options.volume;a=this.options.muted?0:a;this.status.noVolume?(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.hide(),
this.css.jq.volumeBarValue.length&&this.css.jq.volumeBarValue.hide(),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.hide()):(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.show(),this.css.jq.volumeBarValue.length&&(this.css.jq.volumeBarValue.show(),this.css.jq.volumeBarValue[this.options.verticalVolume?"height":"width"](a*100+"%")),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.show())},volumeMax:function(){this.volume(1);this.options.muted&&this._muted(!1)},_cssSelectorAncestor:function(a){var c=
this;this.options.cssSelectorAncestor=a;this._removeUiClass();this.ancestorJq=a?b(a):[];a&&this.ancestorJq.length!==1&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.ancestorJq.length+" found for cssSelectorAncestor.",hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT});this._addUiClass();b.each(this.options.cssSelector,function(a,b){c._cssSelector(a,b)})},_cssSelector:function(a,c){var d=this;typeof c==="string"?b.jPlayer.prototype.options.cssSelector[a]?
(this.css.jq[a]&&this.css.jq[a].length&&this.css.jq[a].unbind(".jPlayer"),this.options.cssSelector[a]=c,this.css.cs[a]=this.options.cssSelectorAncestor+" "+c,this.css.jq[a]=c?b(this.css.cs[a]):[],this.css.jq[a].length&&this.css.jq[a].bind("click.jPlayer",function(c){d[a](c);b(this).blur();return!1}),c&&this.css.jq[a].length!==1&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:this.css.cs[a],message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.css.jq[a].length+" found for "+a+" method.",
hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT})):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_METHOD,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_METHOD,hint:b.jPlayer.warningHint.CSS_SELECTOR_METHOD}):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_STRING,context:c,message:b.jPlayer.warningMsg.CSS_SELECTOR_STRING,hint:b.jPlayer.warningHint.CSS_SELECTOR_STRING})},seekBar:function(a){if(this.css.jq.seekBar){var b=this.css.jq.seekBar.offset(),a=a.pageX-b.left,b=this.css.jq.seekBar.width();
this.playHead(100*a/b)}},playBar:function(a){this.seekBar(a)},repeat:function(){this._loop(!0)},repeatOff:function(){this._loop(!1)},_loop:function(a){if(this.options.loop!==a)this.options.loop=a,this._updateButtons(),this._trigger(b.jPlayer.event.repeat)},currentTime:function(){},duration:function(){},gui:function(){},noSolution:function(){},option:function(a,c){var d=a;if(arguments.length===0)return b.extend(!0,{},this.options);if(typeof a==="string"){var e=a.split(".");if(c===f){for(var d=b.extend(!0,
{},this.options),g=0;g<e.length;g++)if(d[e[g]]!==f)d=d[e[g]];else return this._warning({type:b.jPlayer.warning.OPTION_KEY,context:a,message:b.jPlayer.warningMsg.OPTION_KEY,hint:b.jPlayer.warningHint.OPTION_KEY}),f;return d}for(var g=d={},h=0;h<e.length;h++)h<e.length-1?(g[e[h]]={},g=g[e[h]]):g[e[h]]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,c){var d=this;switch(a){case "volume":this.volume(c);
break;case "muted":this._muted(c);break;case "cssSelectorAncestor":this._cssSelectorAncestor(c);break;case "cssSelector":b.each(c,function(a,b){d._cssSelector(a,b)});break;case "fullScreen":this.options[a]!==c&&(this._removeUiClass(),this.options[a]=c,this._refreshSize());break;case "size":!this.options.fullScreen&&this.options[a].cssClass!==c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "sizeFull":this.options.fullScreen&&this.options[a].cssClass!==
c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "autohide":this.options[a]=b.extend({},this.options[a],c);this._updateAutohide();break;case "loop":this._loop(c);break;case "nativeVideoControls":this.options[a]=b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this._restrictNativeVideoControls();this._updateNativeVideoControls();break;case "noFullScreen":this.options[a]=
b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullScreen=this._uaBlocklist(this.options.noFullScreen);this._restrictNativeVideoControls();this._updateButtons();break;case "noVolume":this.options[a]=b.extend({},this.options[a],c);this.status.noVolume=this._uaBlocklist(this.options.noVolume);this._updateVolume();this._updateMute();break;case "emulateHtml":this.options[a]!==c&&((this.options[a]=c)?this._emulateHtmlBridge():
this._destroyHtmlBridge())}return this},_refreshSize:function(){this._setSize();this._addUiClass();this._updateSize();this._updateButtons();this._updateAutohide();this._trigger(b.jPlayer.event.resize)},_setSize:function(){this.options.fullScreen?(this.status.width=this.options.sizeFull.width,this.status.height=this.options.sizeFull.height,this.status.cssClass=this.options.sizeFull.cssClass):(this.status.width=this.options.size.width,this.status.height=this.options.size.height,this.status.cssClass=
this.options.size.cssClass);this.element.css({width:this.status.width,height:this.status.height})},_addUiClass:function(){this.ancestorJq.length&&this.ancestorJq.addClass(this.status.cssClass)},_removeUiClass:function(){this.ancestorJq.length&&this.ancestorJq.removeClass(this.status.cssClass)},_updateSize:function(){this.internal.poster.jq.css({width:this.status.width,height:this.status.height});!this.status.waitForPlay&&this.html.active&&this.status.video||this.html.video.available&&this.html.used&&
this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):!this.status.waitForPlay&&this.flash.active&&this.status.video&&this.internal.flash.jq.css({width:this.status.width,height:this.status.height})},_updateAutohide:function(){var a=this,b=function(){a.css.jq.gui.fadeIn(a.options.autohide.fadeIn,function(){clearTimeout(a.internal.autohideId);a.internal.autohideId=setTimeout(function(){a.css.jq.gui.fadeOut(a.options.autohide.fadeOut)},a.options.autohide.hold)})};
this.css.jq.gui.length&&(this.css.jq.gui.stop(!0,!0),clearTimeout(this.internal.autohideId),this.element.unbind(".jPlayerAutohide"),this.css.jq.gui.unbind(".jPlayerAutohide"),this.status.nativeVideoControls?this.css.jq.gui.hide():this.options.fullScreen&&this.options.autohide.full||!this.options.fullScreen&&this.options.autohide.restored?(this.element.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.hide()):this.css.jq.gui.show())},
fullScreen:function(){this._setOption("fullScreen",!0)},restoreScreen:function(){this._setOption("fullScreen",!1)},_html_initMedia:function(){this.htmlElement.media.src=this.status.src;this.options.preload!=="none"&&this._html_load();this._trigger(b.jPlayer.event.timeupdate)},_html_setAudio:function(a){var c=this;b.each(this.formats,function(b,e){if(c.html.support[e]&&a[e])return c.status.src=a[e],c.status.format[e]=!0,c.status.formatType=e,!1});this.htmlElement.media=this.htmlElement.audio;this._html_initMedia()},
_html_setVideo:function(a){var c=this;b.each(this.formats,function(b,e){if(c.html.support[e]&&a[e])return c.status.src=a[e],c.status.format[e]=!0,c.status.formatType=e,!1});if(this.status.nativeVideoControls)this.htmlElement.video.poster=this._validString(a.poster)?a.poster:"";this.htmlElement.media=this.htmlElement.video;this._html_initMedia()},_html_resetMedia:function(){this.htmlElement.media&&(this.htmlElement.media.id===this.internal.video.id&&!this.status.nativeVideoControls&&this.internal.video.jq.css({width:"0px",
height:"0px"}),this.htmlElement.media.pause())},_html_clearMedia:function(){if(this.htmlElement.media)this.htmlElement.media.src="",this.htmlElement.media.load()},_html_load:function(){if(this.status.waitForLoad)this.status.waitForLoad=!1,this.htmlElement.media.load();clearTimeout(this.internal.htmlDlyCmdId)},_html_play:function(a){var b=this;this._html_load();this.htmlElement.media.play();if(!isNaN(a))try{this.htmlElement.media.currentTime=a}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.play(a)},
100);return}this._html_checkWaitForPlay()},_html_pause:function(a){var b=this;a>0?this._html_load():clearTimeout(this.internal.htmlDlyCmdId);this.htmlElement.media.pause();if(!isNaN(a))try{this.htmlElement.media.currentTime=a}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.pause(a)},100);return}a>0&&this._html_checkWaitForPlay()},_html_playHead:function(a){var b=this;this._html_load();try{if(typeof this.htmlElement.media.seekable==="object"&&this.htmlElement.media.seekable.length>0)this.htmlElement.media.currentTime=
a*this.htmlElement.media.seekable.end(this.htmlElement.media.seekable.length-1)/100;else if(this.htmlElement.media.duration>0&&!isNaN(this.htmlElement.media.duration))this.htmlElement.media.currentTime=a*this.htmlElement.media.duration/100;else throw"e";}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.playHead(a)},100);return}this.status.waitForLoad||this._html_checkWaitForPlay()},_html_checkWaitForPlay:function(){if(this.status.waitForPlay)this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&
this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height}))},_html_volume:function(a){if(this.html.audio.available)this.htmlElement.audio.volume=a;if(this.html.video.available)this.htmlElement.video.volume=a},_html_mute:function(a){if(this.html.audio.available)this.htmlElement.audio.muted=a;if(this.html.video.available)this.htmlElement.video.muted=a},_flash_setAudio:function(a){var c=this;try{if(b.each(this.formats,
function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4a":case "fla":c._getMovie().fl_setAudio_m4a(a[d]);break;case "mp3":c._getMovie().fl_setAudio_mp3(a[d])}c.status.src=a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),this.options.preload==="auto")this._flash_load(),this.status.waitForLoad=!1}catch(d){this._flashError(d)}},_flash_setVideo:function(a){var c=this;try{if(b.each(this.formats,function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4v":case "flv":c._getMovie().fl_setVideo_m4v(a[d])}c.status.src=
a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),this.options.preload==="auto")this._flash_load(),this.status.waitForLoad=!1}catch(d){this._flashError(d)}},_flash_resetMedia:function(){this.internal.flash.jq.css({width:"0px",height:"0px"});this._flash_pause(NaN)},_flash_clearMedia:function(){try{this._getMovie().fl_clearMedia()}catch(a){this._flashError(a)}},_flash_load:function(){try{this._getMovie().fl_load()}catch(a){this._flashError(a)}this.status.waitForLoad=!1},_flash_play:function(a){try{this._getMovie().fl_play(a)}catch(b){this._flashError(b)}this.status.waitForLoad=
!1;this._flash_checkWaitForPlay()},_flash_pause:function(a){try{this._getMovie().fl_pause(a)}catch(b){this._flashError(b)}if(a>0)this.status.waitForLoad=!1,this._flash_checkWaitForPlay()},_flash_playHead:function(a){try{this._getMovie().fl_play_head(a)}catch(b){this._flashError(b)}this.status.waitForLoad||this._flash_checkWaitForPlay()},_flash_checkWaitForPlay:function(){if(this.status.waitForPlay)this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&
(this.internal.poster.jq.hide(),this.internal.flash.jq.css({width:this.status.width,height:this.status.height}))},_flash_volume:function(a){try{this._getMovie().fl_volume(a)}catch(b){this._flashError(b)}},_flash_mute:function(a){try{this._getMovie().fl_mute(a)}catch(b){this._flashError(b)}},_getMovie:function(){return document[this.internal.flash.id]},_checkForFlash:function(a){var b=!1,d;if(window.ActiveXObject)try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+a),b=!0}catch(e){}else navigator.plugins&&
navigator.mimeTypes.length>0&&(d=navigator.plugins["Shockwave Flash"])&&navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/,"$1")>=a&&(b=!0);return b},_validString:function(a){return a&&typeof a==="string"},_limitValue:function(a,b,d){return a<b?b:a>d?d:a},_urlNotSetError:function(a){this._error({type:b.jPlayer.error.URL_NOT_SET,context:a,message:b.jPlayer.errorMsg.URL_NOT_SET,hint:b.jPlayer.errorHint.URL_NOT_SET})},_flashError:function(a){var c;c=this.internal.ready?"FLASH_DISABLED":
"FLASH";this._error({type:b.jPlayer.error[c],context:this.internal.flash.swf,message:b.jPlayer.errorMsg[c]+a.message,hint:b.jPlayer.errorHint[c]});this.internal.flash.jq.css({width:"1px",height:"1px"})},_error:function(a){this._trigger(b.jPlayer.event.error,a);this.options.errorAlerts&&this._alert("Error!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_warning:function(a){this._trigger(b.jPlayer.event.warning,f,a);this.options.warningAlerts&&this._alert("Warning!"+
(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_alert:function(a){alert("jPlayer "+this.version.script+" : id='"+this.internal.self.id+"' : "+a)},_emulateHtmlBridge:function(){var a=this;b.each(b.jPlayer.emulateMethods.split(/\s+/g),function(b,d){a.internal.domNode[d]=function(b){a[d](b)}});b.each(b.jPlayer.event,function(c,d){var e=!0;b.each(b.jPlayer.reservedEvent.split(/\s+/g),function(a,b){if(b===c)return e=!1});e&&a.element.bind(d+".jPlayer.jPlayerHtml",
function(){a._emulateHtmlUpdate();var b=document.createEvent("Event");b.initEvent(c,!1,!0);a.internal.domNode.dispatchEvent(b)})})},_emulateHtmlUpdate:function(){var a=this;b.each(b.jPlayer.emulateStatus.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.status[d]});b.each(b.jPlayer.emulateOptions.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.options[d]})},_destroyHtmlBridge:function(){var a=this;this.element.unbind(".jPlayerHtml");b.each((b.jPlayer.emulateMethods+" "+b.jPlayer.emulateStatus+
" "+b.jPlayer.emulateOptions).split(/\s+/g),function(b,d){delete a.internal.domNode[d]})}};b.jPlayer.error={FLASH:"e_flash",FLASH_DISABLED:"e_flash_disabled",NO_SOLUTION:"e_no_solution",NO_SUPPORT:"e_no_support",URL:"e_url",URL_NOT_SET:"e_url_not_set",VERSION:"e_version"};b.jPlayer.errorMsg={FLASH:"jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ",FLASH_DISABLED:"jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ",
NO_SOLUTION:"No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.",NO_SUPPORT:"It is not possible to play any media format provided in setMedia() on this browser using your current options.",URL:"Media URL could not be loaded.",URL_NOT_SET:"Attempt to issue media playback commands, while no media url is set.",VERSION:"jPlayer "+b.jPlayer.prototype.version.script+" needs Jplayer.swf version "+b.jPlayer.prototype.version.needFlash+" but found "};b.jPlayer.errorHint=
{FLASH:"Check your swfPath option and that Jplayer.swf is there.",FLASH_DISABLED:"Check that you have not display:none; the jPlayer entity or any ancestor.",NO_SOLUTION:"Review the jPlayer options: support and supplied.",NO_SUPPORT:"Video or audio formats defined in the supplied option are missing.",URL:"Check media URL is valid.",URL_NOT_SET:"Use setMedia() to set the media URL.",VERSION:"Update jPlayer files."};b.jPlayer.warning={CSS_SELECTOR_COUNT:"e_css_selector_count",CSS_SELECTOR_METHOD:"e_css_selector_method",
CSS_SELECTOR_STRING:"e_css_selector_string",OPTION_KEY:"e_option_key"};b.jPlayer.warningMsg={CSS_SELECTOR_COUNT:"The number of css selectors found did not equal one: ",CSS_SELECTOR_METHOD:"The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",CSS_SELECTOR_STRING:"The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",OPTION_KEY:"The option requested in jPlayer('option') is undefined."};b.jPlayer.warningHint={CSS_SELECTOR_COUNT:"Check your css selector and the ancestor.",
CSS_SELECTOR_METHOD:"Check your method name.",CSS_SELECTOR_STRING:"Check your css selector is a string.",OPTION_KEY:"Check your option name."}})(jQuery);

View file

@ -0,0 +1,175 @@
/**
* PeriodicalUpdater - jQuery plugin for timed, decaying ajax calls
*
* http://www.360innovate.co.uk/blog/2009/03/periodicalupdater-for-jquery/
* http://enfranchisedmind.com/blog/posts/jquery-periodicalupdater-ajax-polling/
*
* Copyright (c) 2009 by the following:
* Frank White (http://customcode.info)
* Robert Fischer (http://smokejumperit.com)
* 360innovate (http://www.360innovate.co.uk)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function($) {
var pu_log = function(msg) {
try {
console.log(msg);
} catch(err) {}
}
// Now back to our regularly scheduled work
$.PeriodicalUpdater = function(url, options, callback, autoStopCallback){
var settings = jQuery.extend(true, {
url: url, // URL of ajax request
cache: false, // By default, don't allow caching
method: 'GET', // method; get or post
data: '', // array of values to be passed to the page - e.g. {name: "John", greeting: "hello"}
minTimeout: 1000, // starting value for the timeout in milliseconds
maxTimeout: 8000, // maximum length of time between requests
multiplier: 2, // if set to 2, timerInterval will double each time the response hasn't changed (up to maxTimeout)
maxCalls: 0, // maximum number of calls. 0 = no limit.
autoStop: 0 // automatically stop requests after this many returns of the same data. 0 = disabled
}, options);
// set some initial values, then begin
var timer = null;
var timerInterval = settings.minTimeout;
var maxCalls = settings.maxCalls;
var autoStop = settings.autoStop;
var calls = 0;
var noChange = 0;
var originalMaxCalls = maxCalls;
var reset_timer = function(interval) {
if (timer != null) {
clearTimeout(timer);
}
timerInterval = interval;
pu_log('resetting timer to '+ timerInterval +'.');
timer = setTimeout(getdata, timerInterval);
}
// Function to boost the timer
var boostPeriod = function() {
if(settings.multiplier >= 1) {
before = timerInterval;
timerInterval = timerInterval * settings.multiplier;
if(timerInterval > settings.maxTimeout) {
timerInterval = settings.maxTimeout;
}
after = timerInterval;
pu_log('adjusting timer from '+ before +' to '+ after +'.');
reset_timer(timerInterval);
}
};
// Construct the settings for $.ajax based on settings
var ajaxSettings = jQuery.extend(true, {}, settings);
if(settings.type && !ajaxSettings.dataType) ajaxSettings.dataType = settings.type;
if(settings.sendData) ajaxSettings.data = settings.sendData;
ajaxSettings.type = settings.method; // 'type' is used internally for jQuery. Who knew?
ajaxSettings.ifModified = true;
var handle = {
restart: function() {
maxCalls = originalMaxCalls;
calls = 0;
reset_timer(timerInterval);
return;
},
stop: function() {
maxCalls = -1;
return;
}
};
// Create the function to get data
// TODO It'd be nice to do the options.data check once (a la boostPeriod)
function getdata() {
var toSend = jQuery.extend(true, {}, ajaxSettings); // jQuery screws with what you pass in
if(typeof(options.data) == 'function') {
toSend.data = options.data();
if(toSend.data) {
// Handle transformations (only strings and objects are understood)
if(typeof(toSend.data) == "number") {
toSend.data = toSend.data.toString();
}
}
}
if(maxCalls == 0) {
$.ajax(toSend);
} else if(maxCalls > 0 && calls < maxCalls) {
$.ajax(toSend);
calls++;
}
}
// Implement the tricky behind logic
var remoteData = null;
var prevData = null;
ajaxSettings.success = function(data) {
pu_log("Successful run! (In 'success')");
remoteData = data;
// timerInterval = settings.minTimeout;
};
ajaxSettings.complete = function(xhr, success) {
//pu_log("Status of call: " + success + " (In 'complete')");
if(maxCalls == -1) return;
if(success == "success" || success == "notmodified") {
var rawData = $.trim(xhr.responseText);
if(rawData == 'STOP_AJAX_CALLS') {
handle.stop();
return;
}
if(prevData == rawData) {
if(autoStop > 0) {
noChange++;
if(noChange == autoStop) {
handle.stop();
if(autoStopCallback) autoStopCallback(noChange);
return;
}
}
boostPeriod();
} else {
noChange = 0;
reset_timer(settings.minTimeout);
prevData = rawData;
if(remoteData == null) remoteData = rawData;
// jQuery 1.4+ $.ajax() automatically converts "data" into a JS Object for "type:json" requests now
// For compatibility with 1.4+ and pre1.4 jQuery only try to parse actual strings, skip when remoteData is already an Object
if((ajaxSettings.dataType === 'json') && (typeof(remoteData) === 'string') && (success == "success")) {
remoteData = JSON.parse(remoteData);
}
if(settings.success) { settings.success(remoteData, success, xhr, handle); }
if(callback) callback(remoteData, success, xhr, handle);
}
}
remoteData = null;
}
ajaxSettings.error = function (xhr, textStatus) {
//pu_log("Error message: " + textStatus + " (In 'error')");
if(textStatus != "notmodified") {
prevData = null;
reset_timer(settings.minTimeout);
}
if(settings.error) { settings.error(xhr, textStatus); }
};
// Make the first call
$(function() { reset_timer(timerInterval); });
return handle;
};
})(jQuery);

View file

@ -0,0 +1,290 @@
$(document).ready(function(){
//
//function showNews(source, cat, content){
// new Ajax.Updater(content, '/categories/' + cat, {
// method: 'get'
// });
// var thisChild = source.parentNode.firstChild;
// while (thisChild != source.parentNode.lastChild) {
// if (thisChild.nodeType == 1 && thisChild.getAttribute("class") != "unread") {
// thisChild.setAttribute("class", "");
// }
// thisChild = thisChild.nextSibling;
// }
// source.setAttribute("class", "active");
//}
//function goToTheEnd(){
// var ed = tinyMCE.activeEditor;
// // This gets the root node of the editor window
// var root = ed.dom.getRoot();
// // And this gets the last node inside of it, so the last <p>...</p> tag
// var lastnode = root.childNodes[root.childNodes.length - 1];
//
// if (tinymce.isGecko) {
// // But firefox places the selection outside of that tag, so we need to go one level deeper:
// lastnode = lastnode.childNodes[lastnode.childNodes.length - 1];
// }
// // Now, we select the node
// ed.selection.select(lastnode);
// // And collapse the selection to the end to put the caret there:
// ed.selection.collapse(false);
//}
//
//var myrules = {
// '.remove': function(e){
// el = Event.findElement(e);
// target = el.href.replace(/.*#/, '.')
// el.up(target).hide();
// if (hidden_input = el.previous("input[type=hidden]")) {
// hidden_input.value = '1'
// }
// }
//};
//
//Event.observe(window, 'load', function(){
// $('container').delegate('click', myrules);
//});
//
//function changeCssClass(id, newclass){
// var obj = document.getElementById(id)
// obj.setAttribute("class", newclass);
// obj.setAttribute("className", newclass);
// obj.className = newclass;
//};
//
//function changeTab(container, tab){
// $(tab).style.visibility = 'hidden';
//};
//
//function Trash(source){
// var input = document.createElement("input");
// input.name = "deleted[reason]";
// input.type = "hidden";
// input.value = prompt('Enter reason', 'Violation of rule #');
// if (input.value == null) {
// return
// }
// source.appendChild(input);
// source.submit();
//}
// User popup
var userInfoTimeout;
function ShowUserPopup(source, user){
clearInterval(userInfoTimeout);
hp = document.getElementById("userPopup");
hp.style.top = source.offsetTop + "px";
hp.style.left = source.offsetLeft - 170 + "px";
hp.style.visibility = "Visible";
$.ajax({
type: "GET",
url: "/users/popup/" + user + ".js",
dataType: "script"
});
}
function HideUserPopup(){
userInfoTimeout = setTimeout("HideUserPopupRunner();", 1000);
}
function HideUserPopupRunner(){
document.getElementById("userPopup").style.visibility = "Hidden";
}
// Shoutbox
$.PeriodicalUpdater("/shoutmsgs/index.js", {
method: "GET",
type: "script",
minTimeout: 10000,
multiplier: 2
});
});
$( function() {
var menuContests;
var menuGather;
var menuMaterial;
var menuForums;
$( function() {
$('div#indexMenu div.contests').hover(function(){
});
});
$("div#shoutbox").bind("mousewheel",function(ev, delta) {
var scrollTop = $(this).scrollTop();
$(this).scrollTop(scrollTop-Math.round(delta));
});
// Contests
$("div#indexMenu div.contests").mouseenter(function(){
$("div#indexItems div.contests").fadeIn(100);
});
$("div#indexMenu div.contests").mouseout(function(){
menuContests = setTimeout(function(){
$("div#indexItems div.contests").fadeOut(100);
}, 100);
});
$("div#indexItems div.contests").mouseenter(function(){
clearTimeout(menuContests);
});
$("div#indexItems div.contests").mouseleave(function(){
$("div#indexItems div.contests").fadeOut(100);
});
// Gather
$("div#indexMenu div.gather").mouseenter(function(){
$("div#indexItems div.gather").fadeIn(100);
});
$("div#indexMenu div.gather").mouseout(function(){
menuGather = setTimeout(function(){
$("div#indexItems div.gather").fadeOut(100);
}, 100);
});
$("div#indexItems div.gather").mouseenter(function(){
clearTimeout(menuGather);
});
$("div#indexItems div.gather").mouseleave(function(){
$("div#indexItems div.gather").fadeOut(100);
});
// Forums
$("div#indexMenu div.material").mouseenter(function(){
$("div#indexItems div.material").fadeIn(100);
});
$("div#indexMenu div.material").mouseout(function(){
menuMaterial = setTimeout(function(){
$("div#indexItems div.material").fadeOut(100);
}, 100);
});
$("div#indexItems div.material").mouseenter(function(){
clearTimeout(menuMaterial);
});
$("div#indexItems div.material").mouseleave(function(){
$("div#indexItems div.material").fadeOut(100);
});
// Forums
$("div#indexMenu div.forums").mouseenter(function(){
$("div#indexItems div.forums").fadeIn(100);
});
$("div#indexMenu div.forums").mouseout(function(){
menuForums = setTimeout(function(){
$("div#indexItems div.forums").fadeOut(100);
}, 100);
});
$("div#indexItems div.forums").mouseenter(function(){
clearTimeout(menuForums);
});
$("div#indexItems div.forums").mouseleave(function(){
$("div#indexItems div.forums").fadeOut(100);
});
// Gather stuff
$("a#gatherInfoHide").live('click', function() {
$("div#gatherInfo").fadeOut('slow', 0);
});
$("a#gatherJoinBtn").live('click', function() {
$('form#new_gatherer').submit();
});
// Submit TODO
$("a.submit").live('click', function() {
$(this).closest('form').submit()
});
$('form.new_shoutmsg').submit(function(){
$('input[type=submit]', this).attr('disabled', 'disabled');
});
$('form.new_shoutmsg').submit(function(){
$('input[type=submit]', this).attr('disabled', 'disabled');
});
$('form.new_shoutmsg').live("ajax:complete", function(event,xhr,status){
$(this)[0].reset();
});
// User page
$("td#userNavi > div > a").click(function(){
$("td#userData").fadeOut("fast");
$.ajax({
type: "GET",
url: window.location.protocol + "//" + window.location.host + "/" + window.location.pathname + ".js?page=" + $(this).attr('id'),
dataType: "script"
});
});
// Users page
$("#users th a, #users .pagination a").live("click", function() {
$.getScript(this.href);
return false;
});
$("#users_search input").keyup(function() {
$.get($("#users_search").attr("action"), $("#users_search").serialize(), null, "script");
return false;
});
// Poll page
$("a#option").click(function() {
});
});
// User search
var findUserWindow = "";
function findUser(source) {
findUserWindow = window.open("/users/find?source=" + source, 'findUser', 'height=400,width=400,menubar=false');
if (window.focus) {
findUserWindow.focus();
}
if (findUserWindow.opener == null) {
childWindow.opener = self;
}
return false;
}
function QuoteText(id) {
$.ajax({
type: "GET",
url: "/posts/quote/" + id + ".js",
dataType: "script"
});
}
// Fields removing and adding dynamically
function remove_fields(link) {
$(link).prev("input[type=hidden]").val("1");
$(link).closest(".fields").hide();
}
function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).parent().before(content.replace(regexp, new_id));
}

View file

@ -0,0 +1,198 @@
/*
Yetii - Yet (E)Another Tab Interface Implementation
version 1.5
http://www.kminek.pl/lab/yetii/
Copyright (c) 2007-2008 Grzegorz Wojcik
Code licensed under the BSD License:
http://www.kminek.pl/bsdlicense.txt
*/
function Yetii() {
this.defaults = {
id: null,
active: 1,
interval: null,
wait: null,
persist: null,
tabclass: 'tab',
activeclass: 'active',
callback: null,
leavecallback: null
};
this.activebackup = null;
for (var n in arguments[0]) { this.defaults[n]=arguments[0][n]; };
this.getTabs = function() {
var retnode = [];
var elem = document.getElementById(this.defaults.id).getElementsByTagName('*');
var regexp = new RegExp("(^|\\s)" + this.defaults.tabclass.replace(/\-/g, "\\-") + "(\\s|$)");
for (var i = 0; i < elem.length; i++) {
if (regexp.test(elem[i].className)) retnode.push(elem[i]);
}
return retnode;
};
this.links = document.getElementById(this.defaults.id + '-nav').getElementsByTagName('a');
this.listitems = document.getElementById(this.defaults.id + '-nav').getElementsByTagName('li');
this.show = function(number) {
for (var i = 0; i < this.tabs.length; i++) {
this.tabs[i].style.display = ((i+1)==number) ? 'block' : 'none';
if ((i+1)==number) {
this.addClass(this.links[i], this.defaults.activeclass);
this.addClass(this.listitems[i], this.defaults.activeclass + 'li');
} else {
this.removeClass(this.links[i], this.defaults.activeclass);
this.removeClass(this.listitems[i], this.defaults.activeclass + 'li');
}
}
if (this.defaults.leavecallback && (number != this.activebackup)) this.defaults.leavecallback(this.defaults.active);
this.activebackup = number;
this.defaults.active = number;
if (this.defaults.callback) this.defaults.callback(number);
};
this.rotate = function(interval) {
this.show(this.defaults.active);
this.defaults.active++;
if (this.defaults.active > this.tabs.length) this.defaults.active = 1;
var self = this;
if (this.defaults.wait) clearTimeout(this.timer2);
this.timer1 = setTimeout(function(){self.rotate(interval);}, interval*1000);
};
this.next = function() {
this.defaults.active++;
if(this.defaults.active > this.tabs.length) this.defaults.active = 1;
this.show(this.defaults.active);
};
this.previous = function() {
this.defaults.active--;
if(!this.defaults.active) this.defaults.active = this.tabs.length;
this.show(this.defaults.active);
};
this.gup = function(name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if (results == null) return null;
else return results[1];
};
this.parseurl = function(tabinterfaceid) {
var result = this.gup(tabinterfaceid);
if (result==null) return null;
if (parseInt(result)) return parseInt(result);
if (document.getElementById(result)) {
for (var i=0;i<this.tabs.length;i++) {
if (this.tabs[i].id == result) return (i+1);
}
}
return null;
};
this.createCookie = function(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
};
this.readCookie = function(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
};
this.contains = function(el, item, from) {
return el.indexOf(item, from) != -1;
};
this.hasClass = function(el, className){
return this.contains(el.className, className, ' ');
};
this.addClass = function(el, className){
if (!this.hasClass(el, className)) el.className = (el.className + ' ' + className).replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
};
this.removeClass = function(el, className){
el.className = el.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
el.className.replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
};
this.tabs = this.getTabs();
this.defaults.active = (this.parseurl(this.defaults.id)) ? this.parseurl(this.defaults.id) : this.defaults.active;
if (this.defaults.persist && this.readCookie(this.defaults.id)) this.defaults.active = this.readCookie(this.defaults.id);
this.activebackup = this.defaults.active;
this.show(this.defaults.active);
var self = this;
for (var i = 0; i < this.links.length; i++) {
this.links[i].customindex = i+1;
this.links[i].onclick = function(){
if (self.timer1) clearTimeout(self.timer1);
if (self.timer2) clearTimeout(self.timer2);
self.show(this.customindex);
if (self.defaults.persist) self.createCookie(self.defaults.id, this.customindex, 0);
if (self.defaults.wait) self.timer2 = setTimeout(function(){self.rotate(self.defaults.interval);}, self.defaults.wait*1000);
return false;
};
}
if (this.defaults.interval) this.rotate(this.defaults.interval);
};

View file

@ -0,0 +1,7 @@
/*
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*= require_tree .
*/

View file

@ -0,0 +1,36 @@
$text: #333333
$bg_box: #fbfbfb
$bg_sub: #fdfdfd
@mixin header
font-weight: bold
margin: 0
@mixin thin
padding: 0
margin: 0
@mixin rounded-corners
border: 1px solid #cecece
border-radius: 5px
@mixin shadow
-moz-box-shadow: 0 0 5px #cbcbcb
-webkit-box-shadow: 0 0 5px #cbcbcb
box-shadow: 0 0 5px #cbcbcb
@mixin shadow-10px
-moz-box-shadow: 0 0 10px #cbcbcb
-webkit-box-shadow: 0 0 10px #cbcbcb
box-shadow: 0 0 10px #cbcbcb
@mixin shadow-none
-moz-box-shadow: none
-webkit-box-shadow: none
box-shadow: none
@mixin shaded-top
padding: 5px 10px 0px 10px
border-radius: 5px 5px 0px 0px
background: url('/images/icons/article_head.png') repeat-x
color: #ffffff

View file

@ -0,0 +1,43 @@
@import _mixins.sass
div
&#matches
min-height: 100px
&.article
@include rounded-corners
@include shadow
width: 650px
padding: 0px
margin-bottom: 20px
border: 1px solid #d7d7d7
background-color: $bg_box
&.articleLinks
height: 30px
&.article
> h1
@include shaded-top
margin: 0
width: 630px
font-size: 140%
h1 a
color: #ffffff
h4
margin: 0 3px 3px 5px
font-size: 90%
font-weight: bold
color: black
a
font-size: 90%
font-weight: bold
color: black
&:hover
color: #707070
div.content
padding: 5px 10px 10px 10px
div
margin: 5px 3px 0 3px
&.indented
margin: 2px 2px 2px 15px
&.article div.footer
margin: 0
padding: 10px

View file

@ -0,0 +1,24 @@
@mixin bracket-cell
border: 1px solid #D9D9D9
border-width: 1px 1px 1px 0
width: 110px
height: 14px
table.brackets
border-collapse: collapse
td
font-size: 11px
overflow: hidden
&.empty
width: 90px
height: 14px
&.team
@include bracket-cell
border-width: 1px 1px 1px 0
background-color: #fdfdfd
&.connector
@include bracket-cell
border-width: 0 1px 0 0
select
width: 100px

View file

@ -0,0 +1,36 @@
@import _mixins.sass
div
&.commentNew
width: 340px
height: 300px
&.comments
width: 410px
&.commentHidden
top: auto
position: fixed
visibility: hidden
display: none
&.commentBox
margin: 5px auto 30px auto
width: 400px
h5
@include shadow
width: 400px
height: 15px
padding: 2px 5px 1px 5px
background: url('/images/icons/article_head.png') repeat
color: white
font-size: 11px
a
color: black
&:hover
color: #d4d4d4
div
padding: 5px
width: 400px
background-color: $bg_sub
overflow-x: hidden
blockquote.commentQuote:first-line
font-weight: bold

View file

@ -0,0 +1,26 @@
div.fieldWithErrors
display: inline-block
margin: 0
padding: 0
color: red
#errorExplanation
width: 400px
margin-bottom: 20px
padding: 7px 7px 7px 7px
background-color: #f0f0f0
h2
margin: -7px
padding: 5px
background-color: #c00
color: #fff
text-align: left
font-weight: bold
font-size: 12px
p
padding: 5px
visibility: hidden
color: #333
ul li
font-size: 12px
list-style: url('/images/icons/list-black.gif')

View file

@ -0,0 +1,17 @@
/**
* Flash messages
*/
div
&.loginMsg, &.flashMsg
padding: 5px
font-weight: bold
&.loginOk
color: green
&.loginFail
color: red
&.flashMsg
background-color: green
color: white
&.flashError
background-color: red

View file

@ -0,0 +1,107 @@
@import _mixins.sass
div
&#indexForums
width: 940px
padding-bottom: 5px
margin: 0 auto 0 auto
&.forums
width: 100%
margin-left: auto
margin-right: auto
> div.category
width: 100%
margin-left: auto
margin-right: auto
padding: 0px
margin: 5px
> table.body
width: 100%
margin: 0 auto 0 auto
padding: 0
border: 1px solid #d8e4eb
border-collapse: collapse
th
margin: 0
padding: 3px
border: 1px solid #d8e4eb
background: #cde7f2 repeat-x url('/images/forums/forum_gradient2.png')
vertical-align: middle
font-size: 13px
text-align: left
&.header
padding: 5px 5px 5px 3px
background: url('/images/forums/forum_gradient.jpg') repeat-x center #2a536d
color: #f7fafd
font-size: 14px
font-weight: bold
text-align: left
td
padding: 0px 4px 2px 8px
border: 1px solid #d8e4eb
height: 38px
background-color: #f9fafb
vertical-align: middle
text-align: left
&.forum
height: 48px
&.bullet
background: url('/images/forums/forum_icon_read.png') no-repeat center #f9fafb
width: 38px
height: 36px
&.hl
background: url('/images/forums/forum_icon_unread.png') no-repeat center #f9fafb
table
&#topic
border: 1px solid #d8e4eb
border-collapse: collapse
width: 100%
&#topic>thead>tr>th, &#topic>tbody>tr>td, &#topic>tbody>tr>th, &#topic>tfoot>tr>th
border: 1px solid #d8e4eb
background-color: #f9fafb
padding: 5px
&#topic>thead>tr>th, &#topic>tfoot>tr>th
background: url('/images/forums/forum_gradient.jpg') repeat-x center #2a536d
color: #f7fafd
font-size: 14px
font-weight: bold
&#topic>thead>tr>th a, &#topic>tfoot>tr>th a
color: #e3f0fd
font-weight: bold
&#topic
th.seperator
height: 5px
padding: 0
background: url('/images/forums/forum_gradient.jpg') repeat-x center #2a536d
font-size: 11px
td.avatar
width: 160px
vertical-align: top
th.header
background: url('/images/forums/forum_gradient2.png') repeat-x #cde7f2
height: 10px
font-size: 11px
td
&.actions
font-weight: bold
&.signature
font-size: 10px
&.text
vertical-align: top
padding-top: 2px
tr#reply
display: none
blockquote
padding: 5px
fieldset
margin: 3px 5px 3px 5px
padding: 3px 5px 5px 13px
display: block
border: 1px solid #ccc
background-color: #fbfdff
blockquote
border: 0
padding: 3px 2px 2px 2px
margin: 0

View file

@ -0,0 +1,19 @@
div
&#gatherInfo table td
vertical-align: top
&.gatherLeftBox
width: 170px
height: 320px
&.gatherMiddleBox, &.gatherRightBox
width: 170px
height: 320px
&#gatherStatus
table
&#gatherVotes
border-collapse: collapse
&.gatherVotes td
overflow: hidden
margin: 0px
padding: 1px 0px 0px 1px

View file

@ -0,0 +1,203 @@
@import _mixins.sass
html, body
padding: 0
margin: 0
height: 100%
background: repeat url('/images/index/index_pattern.png')
color: $text
font-family: Verdana, Arial, sans-serif
font-size: 11px
h1
width: 100%
height: 25px
font-size: 20px
h2
@include header
padding: 8px 0 3px 0
font-size: 16px
h3
@include header
padding: 3px 0 3px 0px
font-size: 13px
h4
@include header
padding: 0 0 3px 0
font-size: 11px
h5
@include header
padding: 0 0 3px 0
font-size: 9px
div, form
@thin
p
margin: 0
padding: 3px 2px 3px 2px
img
margin: 0
padding: 3px
border: 0
a
color: #2f79ab
text-decoration: none
&:visited
color: #2f79ab
text-decoration: none
&:hover
color: #6890ab
text-decoration: none
&[name]
color: black
&:hover
text-decoration: none
ol
margin: 0
ul
margin: 0
padding: 0 2px 5px 10px
li
margin: 0 0 0 10px
list-style-type: square
ol li
margin: 0 0 0 10px
blockquote
@include rounded-corners
margin: 3px 5px 3px 7px
padding: 3px 3px 3px 13px
display: block
border: 1px solid #ccc
background-color: #fcfcfc
@mixin input-general
@include shadow-10px
@include rounded-corners
margin-top: 3px
background-color: #f7f7f7
color: #3a3a3a
input
margin: 2px
padding: 2px 3px 2px 3px
&[type=text], &[type=password]
@include input-general
&[type=text]:focus
@include input-general
border: 1px solid #ce6f6f
&[type=submit]
@include input-general
@include rounded-corners
padding: 0px 5px 2px 5px
background-color: #f7f7f7
&:hover
cursor: pointer
border: 1px solid #dddbdb
&:disabled
background-color: #f7f7f7
.clear
clear: both
.minitext
font-size: 80%
.center
text-align: center
.centered
display: block
margin-right: auto
margin-left: auto
.box
@include shadow
@include rounded-corners
background: url('/images/icons/article_background.png') no-repeat $bg_box
margin: 4px
padding: 10px 10px 10px 15px
color: #3a3a3a
overflow-x: hidden
h2:first-of-type
@include shaded-top
margin: -10px auto 10px -18px
width: 110%
padding-top: 5px
padding-bottom: 5px
font-size: 140%
> a
color: #fff
.nbox
margin: 4px
padding: 10px 10px 10px 15px
overflow-x: hidden
.sub
@include shadow-none
border: 0
background: none
margin: 5px
padding: 5px
.left
display: inline-block
left: 0
float: left
.right
display: inline-block
right: 0
float: right
.big
width: 65%
.big2
width: 62%
.small
width: 18%
.small2
width: 30%
.equal
width: 48%
.wide
width: 95%
.wide2
width: 100%
.bold
font-weight: bold
.hidden
visibility: hidden
.green
color: green
.yellow
color: #ceb006
.red
color: #ff0000 !important
span.description
color: #5c5c5c

View file

@ -0,0 +1,203 @@
@import _mixins.sass
div
&#indexContainer
min-height: 100%
position: relative
background: repeat-x url('/images/index/index_bg.png')
padding-bottom: 30px
&#indexMain
margin: 0 auto 0 auto
width: 1200px
padding-bottom: 20px
&#indexBanner
width: 100%
height: 194px
background: no-repeat url('/images/index/index_header.png')
position: relative
&#indexLogo
position: absolute
top: 0px
left: 100px
width: 330px
height: 194px
//top: 130px
//left: 265px
//width: 250px
//height: 50px
visibility: hidden
background-color: transparent
&#indexLinks
width: 850px
height: 25px
padding-top: 3px
margin-left: 250px
color: #ffffff
text-align: right
span.gather
color: #CC6600
> a
color: #ffffff
&:hover
color: #d5d5d5
span
color: #cc0000
> a
color: #cc0000
&#indexLogin
height: 45px
margin: 5px auto auto 710px
font-size: 10px
color: #ffffff
div
&.logged
text-align: center
font-size: 11px
&.button
width: 75px
height: 18px
padding-top: 5px
margin: 10px 1px 0px 2px
background-image: url('/images/icons/button.png')
font-size: 12px
font-weight: bold
float: left
&:hover
background-image: url('/images/icons/button_hl.png')
a
color: #ffffff
td#links
text-align: right
input
&[type=text], &[type=password]
width: 100px
&[type=submit]
@include shadow
height: 21px
width: 20px
border: 1px solid #cecece
background-color: #f7f7f7
color: #3a3a3a
cursor: pointer
&#indexMenu
margin-top: 8px
margin-left: 500px
height: 33px
div
width: 143px
height: 33px
color: #ffffff
float: left
&.contests
background-image: url('/images/index/menu_contests.png')
&:hover
background-image: url('/images/index/menu_contests_shaded.png')
cursor: pointer
&.gather
margin-left: 5px
background-image: url('/images/index/menu_gather.png')
&:hover
background-image: url('/images/index/menu_gather_shaded.png')
cursor: pointer
&.material
margin-left: 5px
background-image: url('/images/index/menu_material.png')
&:hover
background-image: url('/images/index/menu_material_shaded.png')
cursor: pointer
&.forums
margin-left: 5px
background-image: url('/images/index/menu_forums.png')
&:hover
background-image: url('/images/index/menu_forums_shaded.png')
cursor: pointer
&#indexItems div
display: none
position: absolute
left: 495px
margin-top: 6px
width: 143px
text-align: right
font-size: 13px
&.gather
left: 645px
&.material
left: 795px
&.forums
left: 943px
a
color: #ffffff
&:hover
color: #d6d5d5
&#indexMainarea
padding: 10px 100px 10px 150px
&#indexContent
width: 650px
margin-left: 15px
margin-right: 15px
float: left
padding: 0
&#indexRight
padding-top: 15px
float: left
&.indexBox
@include rounded-corners
@include shadow
width: 220px
padding-bottom: 10px
margin-bottom: 15px
background-color: $bg_box
div
&.header
@include shaded-top
margin: 0
padding-top: 5px
height: 25px
font-size: 14px
font-weight: bold
&.body
width: 100%
text-align: left
&.content
margin: 0
padding: 6px 5px 0 10px
font-size: 10px
h3
margin: 0 2px 2px 2px
padding-top: 7px
font-size: 10px
ol, li
padding: 1px 2px 2px 0px
list-style-type: none
div.movie
padding-left: 10px
width: 110px
text-align: center
&#indexPosts
padding: 5px
&#indexFooter
position: absolute
width: 100%
height: 20px
bottom: 0
padding-top: 5px
background: url('/images/index/index_footer.png') repeat-x center #2a536d
text-align: center
font-size: 80%
color: #fff
a
font-weight: bold
color: #fff
text-transform: uppercase

View file

@ -0,0 +1,40 @@
div
&#roundEvents
margin: 0 auto 0 auto
width: 530px
&#roundTimeline
background-color: black
background-image: url('/images/icons/round_timeline.gif')
background-repeat: repeat-y
width: 5px
height: 100px
margin-top: 0
float: left
&#roundAliens, &#roundMarines
float: left
width: 250px
background-color: black
&.roundEvent
height: 15px
width: 100px
padding: 0 2px 0 2px
font-size: 8px
text-align: center
overflow: visible
white-space: nowrap
vertical-align: middle
background: black
&.roundFrag
span
display: inline-block
padding-top: 2px
vertical-align: top
img
padding: 0 1px 0 1px
margin: 0
&#roundAliens div.roundEvent
color: #fdbf31
text-align: right
&#roundMarines div.roundEvent
color: #0080c0
text-align: left

View file

@ -0,0 +1,28 @@
div#shoutbox
width: 150px
padding: 2px
margin: 2px
overflow-y: hidden
overflow-x: hidden
input
&#shoutbox_text
width: 150px
&.counter
width: 25px !important
border: 0
background: transparent
div
&.shoutmsgBox
height: 100px
overflow-y: scroll
&.shoutmsg
display: block
padding-left: 5px
font-size: 90%
text-indent: -5px
a
&.shoutmsgDel, &[data-method="delete"]
color: red

View file

@ -0,0 +1,72 @@
div
&#matchesTab div.tabs
min-height: 100px
&#indexPoll
font-size: 80%
margin-left: 10px
&#pollOptions
img
padding-top: 5px
span
vertical-align: top
&#userFinder
padding: 8px 8px 0 8px
margin: 10px
&.userDataBox
min-height: 220px
td
&#userNavi
vertical-align: top
padding: 5px
&#userData
padding-left: 15px
padding-top: 20px
vertical-align: top
width: 450px
div
&.userFields
margin-left: 10px
display: block
&#userAvatar
display: inline-block
margin-left: 13px
width: 150px
&#userPopup
visibility: hidden
position: absolute
width: 150px
height: 180px
font-size: 80%
&#userInfo h4
margin: 1px auto 1px auto
display: block
padding: 0
&#serverLog
width: 560px
height: 200px
padding: 3px
border: 2px inset #e6e6e6
overflow-y: scroll
overflow-x: hidden
pre
&.command
display: block
background-color: #eaffef
font-weight: bold
&.response
display: block
background-color: #fbfdff
&#stream
width: 800px
img.bar
table#movie td
padding-left: 15px
padding-right: 15px
min-width: 166px
div.article > h1.sender
background: #8a2d27

View file

@ -0,0 +1,36 @@
@import _mixins.sass
table
&.data
@include shadow
width: 100%
margin: 5px 3px 8px 3px
border-collapse: collapse
background-color: #fafafa
text-align: left
border: 1px solid #cecece
th
color: white
background-image: url('/images/icons/article_head.png')
background-repeat: repeat-x
a
color: white
tr
&.odd
background-color: #b0d1e8
&.even
background-color: #FFFFFF
td, th
padding: 2px 5px 2px 5px
tr
&.red
background-color: #FFC0CB
color: black
&.green
background-color: #bfffbf
color: black
&.split
width: 100%
th
text-align: right
width: 50%

View file

@ -0,0 +1,37 @@
@import _mixins.sass
ul.tabs
padding-bottom: 4px
padding-left: 20px
li
margin: 0 2px 0 0
float: left
list-style-type: none
list-style-image: none
a
@include shadow-10px
display: block
float: left
height: 18px
padding-top: 5px
padding: 5px 10px 0px 10px
-webkit-border-top-left-radius: 5px
-webkit-border-top-right-radius: 5px
-moz-border-radius-topleft: 5px
-moz-border-radius-topright: 5px
border-top-left-radius: 5px
border-top-right-radius: 5px
background-color: #255278
font-weight: bold
text-decoration: none
text-align: center
color: #ffffff
&:hover
background-color: #0e5490
&.active
cursor: default
background-color: #891a06
div.tabs
margin: 5px
margin-top: 19px

View file

@ -0,0 +1,10 @@
class AboutController < ApplicationController
def staff
end
def adminpanel
end
def statistics
end
end

View file

@ -0,0 +1,74 @@
class ApplicationController < ActionController::Base
helper :all
helper_method :cuser, :strip, :return_here
before_filter :update_user
before_filter :set_controller_and_action_names
protect_from_forgery
respond_to :html, :js
include Exceptions
# Global methods
def cuser
@cuser ||= User.find(session[:user]) if session[:user]
end
def return_here
session[:return_to] = request.url
end
def return_to
addr = session[:return_to]
session[:return_to] = nil
redirect_to addr
end
def redirect_to_back
if request.env["HTTP_REFERER"]
redirect_to request.env["HTTP_REFERER"]
else
redirect_to "/"
end
rescue
redirect_to "/"
end
def redirect_to_home
redirect_to :controller => "articles", :action => "news_index"
end
def rescue_action(exception)
case exception
when AccessError
render :text => t(:access_denied), :layout => true
when Error
render :text => exception.message, :layout => true
when ActiveRecord::StaleObjectError
render :text => t(:application_stale)
else
super exception
end
end
private
def update_user
if cuser
Time.zone = cuser.time_zone
cuser.update_attribute :lastvisit, DateTime.now if cuser.lastvisit < 2.minutes.ago
if cuser.banned? Ban::TYPE_SITE
session[:user] = nil
@cuser = nil
end
end
end
def set_controller_and_action_names
@current_controller = controller_name
@current_action = action_name
end
end

View file

@ -0,0 +1,85 @@
class ArticlesController < ApplicationController
before_filter :get_article, :only => [:show, :edit, :update, :cleanup, :destroy]
def index
@categories = Category.ordered.nospecial.domain Category::DOMAIN_ARTICLES
end
def news_index
@cat = params[:cat] ? Category.find(params[:cat]) : Article.onlynews.ordered.first.category
@news = Article.with_comments.ordered.limited.nodrafts.category @cat
@categories = Category.ordered.domain Category::DOMAIN_NEWS
@nobody = true
end
def news_archive
@news = Article.with_comments.ordered.nodrafts.onlynews
end
def admin
raise AccessError unless cuser and cuser.admin?
@articles = {"Drafts" => Article.drafts.ordered, "Special" => Article.category(Category::SPECIAL).ordered}
end
def show
raise AccessError unless @article.can_show? cuser
@article.read_by! cuser if cuser
# @article.record_view_count(request.remote_ip, cuser.nil?)
@nobody = true
end
def new
@article = Article.new
@article.text_coding = Article::CODING_HTML
raise AccessError unless @article.can_create? cuser
end
def edit
raise AccessError unless @article.can_update? cuser
@file = DataFile.new
@file.directory_id = Directory::ARTICLES
@file.article = @article
end
def create
@article = Article.new params[:article]
@article.user = cuser
raise AccessError unless @article.can_create? cuser
if @article.save
flash[:notice] = t(:articles_create)
redirect_to @article
else
render :action => "new"
end
end
def update
raise AccessError unless @article.can_update? cuser, params[:article]
if @article.update_attributes params[:article]
flash[:notice] = t(:articles_update)
redirect_to @article
else
render :action => "edit"
end
end
def cleanup
raise AccessError unless @article.can_update? cuser
@article.text = strip(@article.text)
@article.save!
redirect_to @article
end
def destroy
raise AccessError unless @article.can_destroy? cuser
@article.destroy
redirect_to_back
end
private
def get_article
@article = Article.find params[:id]
end
end

View file

@ -0,0 +1,57 @@
class BansController < ApplicationController
before_filter :get_ban, :only => [:show, :edit, :update, :destroy]
def index
@bans = Ban.ordered
end
def show
end
def refresh
Ban.refresh
end
def new
@ban = Ban.new
raise AccessError unless @ban.can_create? cuser
end
def edit
raise AccessError unless @ban.can_update? cuser
end
def create
@ban = Ban.new(params[:ban])
raise AccessError unless @ban.can_create? cuser
if @ban.save
flash[:notice] = t(:bans_create)
redirect_to(@ban)
else
render :action => "new"
end
end
def update
raise AccessError unless @ban.can_update? cuser
if @ban.update_attributes(params[:ban])
flash[:notice] = t(:bans_update)
redirect_to(@ban)
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @ban.can_destroy? cuser
@ban.destroy
redirect_to(bans_url)
end
private
def get_ban
@ban = Ban.find(params[:id])
end
end

View file

@ -0,0 +1,40 @@
class BracketsController < ApplicationController
before_filter :get_bracket, :only => [:show, :edit, :update, :destroy]
def edit
raise AccessError unless @bracket.can_update? cuser
end
def create
@bracket = Bracket.new params[:bracket]
raise AccessError unless @bracket.can_create? cuser
if @bracket.save
flash[:notice] = t(:brackets_create)
end
redirect_to edit_contest_path(@bracket.contest)
end
def update
raise AccessError unless @bracket.can_update? cuser
if @bracket.update_attributes params[:bracket] and @bracket.update_cells(params[:cell])
flash[:notice] = t(:brackets_update)
end
render :action => "edit"
end
def destroy
raise AccessError unless @bracket.can_destroy? cuser
@bracket.destroy
redirect_to edit_contest_path(@bracket.contest)
end
private
def get_bracket
@bracket = Bracket.find(params[:id])
end
end

View file

@ -0,0 +1,67 @@
class CategoriesController < ApplicationController
before_filter :get_category, :except => [:index, :new, :create]
def show
if [Category::DOMAIN_ARTICLES, Category::DOMAIN_NEWS].include? @category.domain
@articles = Article.with_comments.ordered.limited.nodrafts.category params[:id]
Category.find(params[:id]).read_by! cuser if cuser
render :partial => "articles/article", :collection => @articles.to_a
end
end
def index
@categories = Category.ordered
end
def new
@category = Category.new
raise AccessError unless @category.can_create? cuser
end
def edit
raise AccessError unless @category.can_update? cuser
end
def create
@category = Category.new params[:category]
raise AccessError unless @category.can_create? cuser
if @category.save
@category.update_attribute :sort, @category.id
flash[:notice] = t(:articles_category)
redirect_to :categories
end
end
def update
raise AccessError unless @category.can_update? cuser
if @category.update_attributes params[:category]
flash[:notice] = t(:articles_category_update)
redirect_to :categories
end
end
def up
raise AccessError unless @category.can_update? cuser
@category.move_up(["domain = ?", @category.domain], "sort")
redirect_to :categories
end
def down
raise AccessError unless @category.can_update? cuser
@category.move_down(["domain = ?", @category.domain], "sort")
redirect_to :categories
end
def destroy
raise AccessError unless @category.can_destroy? cuser
@category.destroy
redirect_to :categories
end
private
def get_category
@category = Category.find params[:id]
end
end

View file

@ -0,0 +1,73 @@
class ChallengesController < ApplicationController
before_filter :get_challenge, :only => ['show', 'edit', 'update', 'destroy']
def index
@challenges = Challenge.all
end
def show
return_here
end
def refresh
Challenge.past.pending.each do |c|
c.destroy
end
render :text => t(:challenges_cleared)
end
def new
@challenge = Challenge.new
@challenge.user = cuser
@challenge.contester2 = Contester.active.find params[:id]
@challenge.get_contester1
raise AccessError unless @challenge.can_create? cuser
end
def create
@challenge = Challenge.new params[:challenge]
@challenge.user = cuser
raise AccessError unless @challenge.can_create? cuser
if @challenge.valid? and @challenge.save
flash[:notice] = t(:challenges_create)
redirect_to @challenge
else
render :action => "new"
end
end
def update
@challenge = Challenge.find params[:id]
raise AccessError unless @challenge.can_update? cuser
case params[:commit]
when "Accept"
@challenge.status = Challenge::STATUS_ACCEPTED
when "Default time"
@challenge.status = Challenge::STATUS_DEFAULT
when "Forfeit"
@challenge.status = Challenge::STATUS_FORFEIT
when "Decline"
@challenge.status = Challenge::STATUS_DECLINED
end
if @challenge.update_attributes params[:challenge]
flash[:notice] = t(:challenges_update)
end
render :action => "show"
end
def destroy
raise AccessError unless @challenge.can_destroy? cuser
@challenge.destroy
return_to
end
private
def get_challenge
@challenge = Challenge.find params[:id]
end
end

View file

@ -0,0 +1,55 @@
class CommentsController < ApplicationController
before_filter :get_comment, :only => [:raw, 'edit', 'update', 'destroy']
respond_to :html, :js
def index
@comments = Comment.recent.filtered
end
def show
@comments = Comment.recent5.all :conditions => {:commentable_id => params[:id2], :commentable_type => params[:id]}
render :partial => 'list', :layout => false
end
def edit
raise AccessError unless @comment.can_update? cuser
end
def create
@comment = Comment.new params[:comment]
@comment.user = cuser
raise AccessError unless @comment.can_create? cuser
respond_to do |format|
if @comment.save
flash[:notice] = t(:comments_create)
format.js { render }
else
flash[:error] = t(:comments_invalid) + @comment.errors.full_messages.to_s
format.html { redirect_to(:back)}
end
end
end
def update
raise AccessError unless @comment.can_update? cuser
if @comment.update_attributes params[:comment]
flash[:notice] = t(:comments_update)
return_to
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @comment.can_destroy? cuser
@comment.destroy
redirect_to_back
end
private
def get_comment
@comment = Comment.find params[:id]
end
end

View file

@ -0,0 +1,62 @@
class ContestersController < ApplicationController
before_filter :get_contester, :only => ['show', 'edit', 'update', :recover, :destroy, :recalc]
def show
@matches = Match.future.unfinished.ordered.of_contester @contester
@results = Match.finished.ordered.of_contester @contester
raise AccessError unless @contester and @contester.contest and @contester.team
if @contester.contest.status == Contest::STATUS_CLOSED
@members = @contester.team.teamers.distinct.ordered
else
@members = @contester.team.teamers.active.distinct.ordered
end
end
def edit
raise AccessError unless @contester.can_update? cuser
end
def create
@contester = Contester.new params[:contester]
@contester.user = cuser
raise AccessError unless @contester.can_create? cuser
if @contester.save
flash[:notice] = t(:contests_join)
redirect_to contest_path(@contester.contest_id)
else
flash[:error] = t(:errors) + @contester.errors.full_messages.to_s
redirect_to_back
end
end
def update
raise AccessError unless @contester.can_update? cuser
if @contester.update_attributes params[:contester]
flash[:notice] = t(:contests_contester_update)
redirect_to @contester
else
render :action => "edit"
end
end
def recover
raise AccessError unless @contester.can_destroy? cuser
@contester.recover
redirect_to_back
end
def destroy
raise AccessError unless @contester.can_destroy? cuser
@contester.destroy
redirect_to_back
end
private
def get_contester
@contester = Contester.find params[:id]
end
end

View file

@ -0,0 +1,110 @@
class ContestsController < ApplicationController
before_filter :get_contest, :only => ['show', 'edit', 'update', 'destroy', 'del_map', 'scores', 'recalc']
def index
#@contests = Contest.all
@contests_active = Contest.active
@contests_inactive = Contest.inactive
end
def historical
case params[:id]
when "NS1"
@contests = Contest.with_contesters.ordered.where ["name LIKE ? OR name LIKE ?", "S%:%", "%Night%"]
else
@contests = Contest.with_contesters.ordered.where ["id > ?", "113"]
end
end
def current
@contests = Contest.active
end
def show
# TODO
# @friendly = cuser.active_contesters.of_contest(@contest).active.first if cuser
end
def scores
raise AccessError unless @contest.contest_type == Contest::TYPE_LADDER
@friendly = params[:friendly] ? @contest.contesters.find(params[:friendly]) : @contest.contesters.first
@rounds = [@contest.modulus_even, @contest.modulus_3to1, @contest.modulus_4to0]
@rounds.each_index do |key|
if params["rounds"] and params["rounds"]["#{key}"]
@rounds[key] = params["rounds"]["#{key}"].to_f
end
end
@weight = params[:weight] ? params[:weight].to_f : @contest.weight
end
def recalc
@contest.recalculate
render :text => t(:score_recalc), :layout => true
end
def new
@contest = Contest.new
raise AccessError unless @contest.can_create? cuser
end
def edit
raise AccessError unless @contest.can_update? cuser
end
def create
@contest = Contest.new params[:contest]
raise AccessError unless @contest.can_create? cuser
if @contest.save
flash[:notice] = t(:contests_create)
redirect_to @contest
else
render :action => "new"
end
end
def update
raise AccessError unless @contest.can_update? cuser
if params[:commit] == "Save"
if @contest.update_attributes(params[:contest])
flash[:notice] = t(:contests_update)
redirect_to @contest
else
render :action => "edit"
end
elsif params[:commit] == "Add map"
@contest.maps << Map.find(params[:map])
render :action => "edit"
elsif params[:commit] == "Add team"
contester = Contester.new
contester.team = Team.find params[:team]
contester.contest = @contest
contester.active = true
if contester.valid?
contester.save(false)
else
@contest.errors.add_to_base contester.errors.full_messages.to_s
end
render :action => "edit"
end
end
def del_map
raise AccessError unless @contest.can_update? cuser
@contest.maps.delete(Map.find(params[:id2]))
render :action => "edit"
end
def destroy
raise AccessError unless @contest.can_destroy? cuser
@contest.destroy
redirect_to contests_url
end
private
def get_contest
@contest = Contest.find params[:id]
end
end

View file

@ -0,0 +1,105 @@
class DataFilesController < ApplicationController
before_filter :get_file, :only => ['show', 'edit', 'update', 'destroy', 'rate', :addFile, :delFile]
def show
end
def admin
raise AccessError unless cuser and cuser.admin?
@files = []
DataFile.all.each do |f|
@files << f unless File.exists?(f.path)
end
@movies = []
DataFile.movies.each do |f|
@movies << f unless f.movie or f.preview or (f.related and f.related.movie)
end
end
def new
@file = DataFile.new
@file.directory = Directory.find params[:id]
raise AccessError unless @file.can_create? cuser
end
def edit
raise AccessError unless @file.can_update? cuser
end
def create
@file = DataFile.new params[:data_file]
@file.size = 0
raise AccessError unless @file.can_create? cuser
if @file.save
flash[:notice] = t(:files_create)
if @file.article
redirect_to @file.article
elsif @file.movie
redirect_to @file.movie
else
redirect_to @file
end
else
render :action => "new"
end
end
def update
raise AccessError unless @file.can_update? cuser
if @file.update_attributes params[:data_file]
flash[:notice] = t(:files_update)
redirect_to(@file)
else
render :action => "edit"
end
end
def addFile
raise AccessError unless @file.can_update? cuser
@related = @file.directory.files.not(@file).find params[:data_file][:related_id]
@related.related = @file
@related.save
redirect_to edit_data_file_url(@file)
end
def delFile
raise AccessError unless @file.can_update? cuser
@related = @file.related_files.first params[:related_id]
@related.related = nil
@related.save
redirect_to edit_data_file_url(@file)
end
def destroy
raise AccessError unless @file.can_destroy? cuser
@file.destroy
redirect_to_back
end
def rate
raise AccessError unless cuser
if params[:id2].to_i > 0 and params[:id2].to_i <= 5
@file.rate_it(params[:id2], cuser.id)
end
head :ok
end
def trash
raise AccessError unless cuser and cuser.admin?
@result = ""
DataFile.all.each do |file|
unless File.exists?(file.path)
file.destroy
@result << file.to_s + "<br />"
end
end
render :text => @result, :layout => true
end
private
def get_file
@file = DataFile.find params[:id]
end
end

View file

@ -0,0 +1,61 @@
class DirectoriesController < ApplicationController
before_filter :get_directory, :except => [:new, :create]
def show
if @directory.hidden
@files = @directory.files
render :partial => "data_files/list", :layout => true
else
@directories = Directory.ordered.filtered.all :conditions => {:parent_id => 1}
end
end
def new
@directory = Directory.new
@directory.parent = Directory.find params[:id]
raise AccessError unless @directory.can_create? cuser
end
def edit
raise AccessError unless @directory.can_update? cuser
end
def refresh
@directory.process_dir
render :text => t(:directories_update)
end
def create
@directory = Directory.new params[:directory]
raise AccessError unless @directory.can_create? cuser
if @directory.save
flash[:notice] = t(:directories_create)
redirect_to(@directory)
else
render :action => "new"
end
end
def update
raise AccessError unless @directory.can_update? cuser
if @directory.update_attributes(params[:directory])
flash[:notice] = t(:directories_update)
redirect_to @directory
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @directory.can_destroy? cuser
@directory.destroy
redirect_to directories_url
end
private
def get_directory
@directory = Directory.find params[:id]
end
end

View file

@ -0,0 +1,35 @@
class ForumersController < ApplicationController
def create
@forumer = Forumer.new params[:forumer]
raise AccessError unless @forumer.can_create? cuser
if @forumer.save
flash[:notice] = t(:groups_added)
else
flash[:error] = @forumer.errors.full_messages.to_s
end
redirect_to_back
end
def update
@forumer = Forumer.find params[:id]
raise AccessError unless @forumer.can_update? cuser
if @forumer.update_attributes params[:forumer]
flash[:notice] = t(:groups_acl_update)
else
flash[:error] = @forumer.errors.full_messages.to_s
end
redirect_to_back
end
def destroy
@forumer = Forumer.find params[:id]
raise AccessError unless @forumer.can_destroy? cuser
@forumer.destroy
redirect_to_back
end
end

View file

@ -0,0 +1,70 @@
class ForumsController < ApplicationController
before_filter :get_forum, :only => [:show, :edit, :update, :up, :down, :destroy]
def index
@categories = Category.domain(Category::DOMAIN_FORUMS).ordered
@nobody = true
end
def show
raise AccessError unless @forum.can_show? cuser
@topics = @forum.topics.all
@forum.read_by! cuser if cuser
@nobody = true
end
def new
@forum = Forum.new
raise AccessError unless @forum.can_create? cuser
end
def edit
raise AccessError unless @forum.can_update? cuser
end
def create
@forum = Forum.new(params[:forum])
raise AccessError unless @forum.can_create? cuser
if @forum.save
flash[:notice] = t(:forums_create)
redirect_to(@forum)
else
render :action => "new"
end
end
def update
raise AccessError unless @forum.can_update? cuser
if @forum.update_attributes(params[:forum])
flash[:notice] = t(:forums_update)
redirect_to(@forum)
else
render :action => "edit"
end
end
def up
raise AccessError unless @forum.can_update? cuser
@forum.move_up :category_id => @forum.category.id
redirect_to_back
end
def down
raise AccessError unless @forum.can_update? cuser
@forum.move_down :category_id => @forum.category.id
redirect_to_back
end
def destroy
raise AccessError unless @forum.can_destroy? cuser
@forum.destroy
redirect_to(forums_url)
end
private
def get_forum
@forum = Forum.find(params[:id])
end
end

View file

@ -0,0 +1,47 @@
class GatherersController < ApplicationController
before_filter :get_gatherer, :except => [:create]
def create
Gather.transaction do
Gatherer.transaction do
@gatherer = Gatherer.new params[:gatherer]
@gatherer.gather.lock!
raise AccessError unless @gatherer.can_create? cuser, params[:gatherer]
if @gatherer.save
flash[:notice] = t(:gathers_join)
else
flash[:error] = @gatherer.errors.full_messages.to_s
end
end
end
redirect_to @gatherer.gather
end
def update
@gatherer = Gatherer.find params[:gatherer][:id]
raise AccessError unless @gatherer.can_update? cuser, params[:gatherer]
if @gatherer.update_attributes params[:gatherer]
flash[:notice] = t(:gatherers_update)
else
flash[:error] = @gatherer.errors.full_messages.to_s
end
redirect_to_back
end
def destroy
raise AccessError unless @gatherer.can_destroy? cuser
@gatherer.destroy
redirect_to @gatherer.gather
end
private
def get_gatherer
@gatherer = Gatherer.find params[:id]
end
end

View file

@ -0,0 +1,75 @@
class GathersController < ApplicationController
before_filter :get_gather, :except => [:latest, :index, :create]
respond_to :html, :js
def index
@gathers = Gather.ordered.limit(50).all
end
def show
end
def latest
@gather = Gather.last(params[:game])
redirect_to @gather
end
def edit
@gather.admin = true
end
def create
@gather = Gather.new
@gather.category_id = params[:gather][:category_id]
raise AccessError unless @gather.can_create? cuser
if @gather.save
flash[:notice] = t(:gather_create)
end
redirect_to_back
end
def update
@gather = Gather.basic.find(params[:id])
raise AccessError unless @gather.can_update? cuser
Gatherer.transaction do
Gather.transaction do
if @gather.update_attributes params[:gather]
flash[:notice] = 'Gather was successfully updated.'
end
end
end
redirect_to @gather
end
def pick
@gatherer = @gather.gatherers.find(params[:player])
raise AccessError unless @gatherer.can_update? cuser, params
Gatherer.transaction do
Gather.transaction do
if @gatherer.update_attribute :team, @gatherer.gather.turn
flash[:notice] = t(:gathers_user_pick)
else
flash[:error] = @gatherer.errors.full_messages.to_s
end
end
end
redirect_to @gather
end
private
def get_gather
Gather.transaction do
@gather = Gather.basic.find(params[:id], :lock => true)
@gather.refresh cuser
end
@gatherer = @gather.gatherers.of_user(cuser).first if cuser
end
end

View file

@ -0,0 +1,35 @@
class GroupersController < ApplicationController
def create
@grouper = Grouper.new params[:grouper]
raise AccessError unless @grouper.can_create? cuser
if @grouper.save
flash[:notice] = t(:groups_user_add)
else
flash[:error] = @grouper.errors.full_messages.to_s
end
redirect_to_back
end
def update
@grouper = Grouper.find params[:id]
raise AccessError unless @grouper.can_update? cuser
if @grouper.update_attributes params[:grouper]
flash[:notice] = t(:groups_user_update)
else
flash[:error] = @grouper.errors.full_messages.to_s
end
redirect_to_back
end
def destroy
@grouper = Grouper.find params[:id]
raise AccessError unless @grouper.can_destroy? cuser
@grouper.destroy
redirect_to_back
end
end

View file

@ -0,0 +1,71 @@
class GroupsController < ApplicationController
before_filter :get_group, :except => [:index, :new, :create]
def index
@groups = Group.all
end
def show
end
def new
@group = Group.new
raise AccessError unless @group.can_create? cuser
end
def edit
@group.users.all
raise AccessError unless @group.can_update? cuser
end
def create
@group = Group.new params[:group]
@group.founder = cuser
raise AccessError unless @group.can_create? cuser
if @group.save
flash[:notice] = t(:groups_create)
redirect_to @group
else
render :action => "new"
end
end
def update
raise AccessError unless @group.can_update? cuser
if @group.update_attributes params[:group]
flash[:notice] = t(:groups_update)
redirect_to @group
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @group.can_destroy? cuser
@group.destroy
redirect_to groups_url
end
def addUser
@user = User.first :conditions => {:username => params[:username]}
raise AccessError unless @group.can_update? cuser
raise Error, t(:duplicate_user) if @group.users.include? @user
@group.users << @user if @user
redirect_to edit_group_url(@group, :groupTab => "groupTabMembers")
end
def delUser
@user = User.find params[:id2]
raise AccessError unless @group.can_update? cuser
@group.users.delete @user
redirect_to edit_group_url(@group, :groupTab => "groupTabMembers")
end
private
def get_group
@group = Group.find params[:id]
end
end

View file

@ -0,0 +1,72 @@
class IssuesController < ApplicationController
before_filter :get_issue, :only => [:show, :edit, :update, :destroy]
def index
raise AccessError unless cuser and cuser.admin?
sort = case params['sort']
when "title" then "title"
when "status" then "status"
when "assigned" then "assigned_id"
when "category" then "category_id"
else "created_at DESC"
end
@open = Issue.with_status(Issue::STATUS_OPEN).all :order => sort
@solved = Issue.with_status(Issue::STATUS_SOLVED).all :order => sort
@rejected = Issue.with_status(Issue::STATUS_REJECTED).all :order => sort
end
def show
raise AccessError unless @issue.can_show? cuser
@issue.read_by! cuser
end
def new
@issue = Issue.new
raise AccessError unless @issue.can_create? cuser
end
def edit
raise AccessError unless @issue.can_update? cuser
end
def create
@issue = Issue.new(params[:issue])
@issue.author = cuser if cuser
raise AccessError unless @issue.can_create? cuser
if @issue.save
flash[:notice] = t(:issues_create)
if cuser
redirect_to(@issue)
else
redirect_to_home
end
else
render :action => "new"
end
end
def update
raise AccessError unless @issue.can_update? cuser
if @issue.update_attributes(params[:issue])
flash[:notice] = t(:issues_update)
redirect_to(@issue)
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @issue.can_destroy? cuser
@issue.destroy
redirect_to(issues_url)
end
private
def get_issue
@issue = Issue.find params[:id]
end
end

View file

@ -0,0 +1,22 @@
class LocksController < ApplicationController
def create
@lock = Lock.new params[:lock]
raise AccessError unless @lock.can_create? cuser
if @lock.save
flash[:notice] = t(:topics_locked)
else
flash[:error] = @lock.errors.full_messages.to_s
end
redirect_to_back
end
def destroy
@lock = Lock.find params[:id]
raise AccessError unless @lock.can_destroy? cuser
@lock.destroy
redirect_to_back
end
end

View file

@ -0,0 +1,85 @@
class LogEventsController < ApplicationController
# GET /log_events
# GET /log_events.xml
def index
@log_events = LogEvent.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @log_events }
end
end
# GET /log_events/1
# GET /log_events/1.xml
def show
@log_event = LogEvent.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @log_event }
end
end
# GET /log_events/new
# GET /log_events/new.xml
def new
@log_event = LogEvent.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @log_event }
end
end
# GET /log_events/1/edit
def edit
@log_event = LogEvent.find(params[:id])
end
# POST /log_events
# POST /log_events.xml
def create
@log_event = LogEvent.new(params[:log_event])
respond_to do |format|
if @log_event.save
flash[:notice] = t(:logevent_create)
format.html { redirect_to(@log_event) }
format.xml { render :xml => @log_event, :status => :created, :location => @log_event }
else
format.html { render :action => "new" }
format.xml { render :xml => @log_event.errors, :status => :unprocessable_entity }
end
end
end
# PUT /log_events/1
# PUT /log_events/1.xml
def update
@log_event = LogEvent.find(params[:id])
respond_to do |format|
if @log_event.update_attributes(params[:log_event])
flash[:notice] = t(:logevent_update)
format.html { redirect_to(@log_event) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @log_event.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /log_events/1
# DELETE /log_events/1.xml
def destroy
@log_event = LogEvent.find(params[:id])
@log_event.destroy
respond_to do |format|
format.html { redirect_to(log_events_url) }
format.xml { head :ok }
end
end
end

View file

@ -0,0 +1,42 @@
class LogFilesController < ApplicationController
def index
LogFile.process
render :text => "Ok"
end
def handle
LogFile.find(params[:id]).deal
render :text => "Ok"
end
def refresh
LogFile.unhandled.each do |lf|
lf.deal
end
end
def fix
Rounder.find_in_batches(:batch_size => 100) do |rounders|
rounders.each do |r|
r.team_id = nil
if r.user and t = Teamer.historic(r.user, r.round.start).first
r.team_id = t.team_id
end
r.save
end
end
end
def pix
Round.all.each do |r|
r.team1_id = nil
r.team2_id = nil
[1, 2].each do |team|
if s = r.rounders.team(team).stats.first
r["team#{team}_id"] = s["team_id"]
end
end
r.save
end
end
end

View file

@ -0,0 +1,53 @@
class MapsController < ApplicationController
before_filter :get_map, :only => [:show, :edit, :update, :destroy]
def index
@maps = Map.basic
end
def show
end
def new
@map = Map.new
raise AccessError unless @map.can_create? cuser
end
def edit
raise AccessError unless @map.can_update? cuser
end
def create
@map = Map.new params[:map]
raise AccessError unless @map.can_create? cuser
if @map.save
flash[:notice] = t(:maps_create)
redirect_to @map
else
render :action => "new"
end
end
def update
raise AccessError unless @map.can_update? cuser
if @map.update_attributes(params[:map])
flash[:notice] = t(:maps_update)
redirect_to @map
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @map.can_destroy? cuser
@map.destroy
redirect_to(maps_url)
end
private
def get_map
@map = Map.find params[:id]
end
end

View file

@ -0,0 +1,105 @@
class MatchesController < ApplicationController
before_filter :get_match, :except => [:index, :new, :create]
def index
@matches = Match.active
end
def show
@ownpred = @match.predictions.first :conditions => {:user_id => cuser.id} if cuser
@newpred = @match.predictions.build
end
def new
@match = Match.new
@match.contest = Contest.find params[:id]
raise AccessError unless @match.can_create? cuser
end
def extra
end
def score
raise AccessError unless @match.can_update? cuser, [:matchers_attributes]
@contester = @match.contester1.team.is_leader?(cuser) ? @match.contester1 : @match.contester2
@n = 0
end
def ref
raise AccessError unless @match.can_update? cuser, [:report]
@n = 0
end
def edit
raise AccessError unless @match.can_update? cuser, [:contester1_id]
end
def create
@match = Match.new params[:match]
raise AccessError unless @match.can_create? cuser
if @match.save
flash[:notice] = t(:matches_create)
redirect_to :controller => "contests", :action => "edit", :id => @match.contest
else
render :action => "new"
end
end
def update
raise AccessError unless @match.can_update? cuser, params[:match]
if params[:match][:matchers_attributes]
params[:match][:matchers_attributes].each do |key, matcher|
matcher['_destroy'] = matcher['_destroy'] == "keep" ? false : true
if matcher['user_id'] == ""
params[:match][:matchers_attributes].delete key
elsif matcher['user_id'].to_i == 0
matcher['user_id'] = User.find_by_username(matcher['user_id']).id
end
end
end
if @match.update_attributes params[:match]
respond_to do |format|
format.xml { head :ok }
format.html do
flash[:notice] = t(:matches_update)
#redirect_to_back
redirect_to @match
end
end
else
render :action => "edit"
end
end
def hltv
raise AccessError unless @match.can_update? cuser, [:hltv]
if params[:commit].include? t(:hltv_send)
@match.hltv_record params[:addr], params[:pwd]
flash[:notice] = t(:hltv_recording)
elsif params[:commit].include? t(:hltv_move)
sleep(90) if params[:wait] == "1"
@match.hltv_move params[:addr], params[:pwd]
flash[:notice] = t(:hltv_moved)
elsif params[:commit].include? t(:hltv_stop)
sleep(90) if params[:wait] == "1"
@match.hltv_stop
flash[:notice] = t(:hltv_stopped)
end
redirect_to :action => "show"
end
def destroy
raise AccessError unless @match.can_destroy? cuser
@match.destroy
redirect_to :controller => "contests", :action => "edit", :id => @match.contest
end
private
def get_match
@match = Match.find params[:id]
end
end

View file

@ -0,0 +1,49 @@
class MessagesController < ApplicationController
before_filter :get_message, :only => [:show, :edit, :update, :destroy]
def index
raise AccessError unless cuser
end
def show
raise AccessError unless @message.can_show? cuser
@message.read_by! cuser
@messages = @message.thread
end
def new
@message = Message.new
raise AccessError unless @message.can_create? cuser
case params[:id]
when "User"
@message.recipient = User.find(params[:id2])
when "Team"
@message.recipient = Team.find(params[:id2])
when "Group"
@message.recipient = Group.find(params[:id2])
else
raise Error, "Illegible recipient"
end
@message.title = params[:title]
end
def create
@message = Message.new(params[:message])
@message.sender = @message.sender_raw == "" ? cuser : cuser.active_teams.find(@message.sender_raw)
raise AccessError unless @message.can_create? cuser
if @message.save
flash[:notice] = t(:message_create)
redirect_to(@message)
else
render :action => "new"
end
end
private
def get_message
@message = Message.find(params[:id])
end
end

View file

@ -0,0 +1,97 @@
class MoviesController < ApplicationController
before_filter :get_movie, :except => [:index, :new, :create]
def index
@movies = []
order = case params[:order]
when "date" then "data_files.created_at DESC"
when "author" then "users.username ASC"
when "ratings" then "total_ratings DESC"
else "total_ratings DESC"
end
if params[:filter]
Movie.index(order).each do |movie|
if movie.file and movie.file.average_rating_round >= params[:filter].to_i
@movies << movie
end
end
else
@movies = Movie.index(order)
end
end
def show
@movie.read_by! cuser if cuser
@movie.record_view_count(request.remote_ip, cuser.nil?)
redirect_to @movie.file.related if @movie.file and @movie.file.related
end
def refresh
@movie.update_status
end
def new
@movie = Movie.new
raise AccessError unless @movie.can_create? cuser
end
def edit
raise AccessError unless @movie.can_update? cuser
end
def create
@movie = Movie.new(params[:movie])
raise AccessError unless @movie.can_create? cuser
if @movie.save
flash[:notice] = t(:movies_create)
redirect_to(@movie)
else
render :action => "new"
end
end
def update
raise AccessError unless @movie.can_update? cuser
if @movie.update_attributes(params[:movie])
flash[:notice] = t(:movies_update)
redirect_to(@movie)
else
render :action => "edit"
end
end
def preview
raise AccessError unless @movie.can_update? cuser
x = params[:x].to_i <= 1280 ? params[:x].to_i : 800
y = params[:y].to_i <= 720 ? params[:y].to_i : 600
render :text => t(:executed) + "<br />" + @movie.make_preview(x, y), :layout => true
end
def snapshot
raise AccessError unless @movie.can_update? cuser
secs = params[:secs].to_i > 0 ? params[:secs].to_i : 5
render :text => t(:executed) + "<br />" + @movie.make_snapshot(secs), :layout => true
end
def download
raise AccessError unless cuser.admin?
@movie.stream_ip = params[:ip]
@movie.stream_port = params[:port]
render :text => t(:executed) + "<br />" + @movie.make_stream, :layout => true
end
def destroy
raise AccessError unless @movie.can_destroy? cuser
@movie.destroy
redirect_to(movies_url)
end
private
def get_movie
@movie = Movie.find(params[:id])
end
end

View file

@ -0,0 +1,43 @@
class PollsController < ApplicationController
before_filter :get_poll, :except => [:index, :new, :create]
respond_to :js
def add
end
def create
@poll = Poll.new params[:poll]
@poll.user = cuser
raise AccessError unless @poll.can_create? cuser
if @poll.save
flash[:notice] = t(:polls_create)
redirect_to @poll
else
render :action => "new"
end
end
def update
raise AccessError unless @poll.can_update? cuser
if @poll.update_attributes params[:poll]
flash[:notice] = t(:polls_update)
redirect_to @poll
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @poll.can_destroy? cuser
@poll.destroy
redirect_to polls_url
end
private
def get_poll
@poll = Poll.find params[:id]
end
end

View file

@ -0,0 +1,128 @@
class PluginController < ApplicationController
def esi
buffer = []
out = []
buffer << Time.now.utc.to_i
buffer << "1.2"
buffer << params[:ch] ? params[:ch] : ""
out << "#ESI#"
out << Verification.verify(buffer.join)
out << buffer.join("\r")
render_out out
end
def user
buffer = []
out = []
if ban = Ban.first(:conditions => ["expiry > UTC_TIMESTAMP() AND steamid = ? AND ban_type = ?", params[:id], Ban::TYPE_SERVER])
out << "#USER#"
out << "BANNED"
out << ban.expiry.utc.to_i
out << ban.reason
out << "\r\r\r\r\r\r\r"
elsif user = User.first(:conditions => {:steamid => params[:id]})
teamer = (user.team ? user.teamers.active.of_team(user.team).first : nil)
icon = 0
rank = "User"
if Group.find(Group::DONORS).users.exists?(user)
rank = "Donor"
icon = icon | 1
end
if Group.find(Group::CHAMPIONS).users.exists?(user)
icon = icon | 2
end
if user.ref?
rank = "Referee"
icon = icon | 4
end
if user.admin?
rank = "Admin"
icon = icon | 8
end
buffer << user.steamid
buffer << user.username
buffer << user.lastip
buffer << (user.team ? Verification.uncrap(user.team.to_s) : "No Team")
buffer << user.id
buffer << user.team_id
buffer << rank
buffer << (teamer ? teamer.ranks[teamer.rank] : "")
buffer << icon
buffer << params[:ch] ? params[:ch] : ""
buffer << (user.can_play? ? "1" : "0")
out << "#USER#"
out << Verification.verify(buffer.join)
out << buffer.join("\r")
else
out << "#FAIL#"
end
render_out out
end
#def admin
# areq = AdminRequest.new
# areq.addr = params[:addr]
# areq.pwd = params[:pwd]
# areq.msg = params[:msg]
# areq.player = params[:player]
# areq.user_id = params[:user]
# areq.save!
# render :text => "Ok"
#end
def ban
ban = Ban.new
ban.steamid = params[:id]
ban.ts = params[:ts]
ban.sign = params[:sign]
ban.expiry = DateTime.now.ago(-(params[:len].to_i*60))
ban.addr = params[:addr]
ban.reason = params[:reason]
ban.ban_type = Ban::TYPE_SERVER
ban.save!
render :text => "Ok"
end
def hltv_req
if params[:game].to_i > 0
if match = Match.first(:conditions => {:id => params[:game]})
match.hltv_record params[:addr], params[:pwd]
hltv = match.hltv
else
render :text => t(:matches_notfound)
end
else
hltv = Server.hltvs.active.unreserved_now.unreserved_hltv_around(DateTime.now).first unless hltv
render :text => t(:hltv_notavailable) unless hltv
hltv.recording = params[:game]
hltv.reservation = params[:addr]
hltv.pwd = params[:pwd]
hltv.save!
end
render :text => t(:hltv_sent)
end
def hltv_move
Server.move params[:addr], params[:newaddr], params[:newpwd]
render :text => t(:hltv_movedd) + params[:newaddr]
end
def hltv_stop
Server.stop params[:addr]
render :text => t(:hltv_stopped)
end
private
def render_out out
@text = out.join("\r")
render :layout => false
end
end

View file

@ -0,0 +1,56 @@
class PollsController < ApplicationController
before_filter :get_poll, :except => [:index, :new, :create]
def index
@polls = Poll.all
end
def show
end
def new
@poll = Poll.new
@poll.options.build
raise AccessError unless @poll.can_create? cuser
end
def edit
raise AccessError unless @poll.can_update? cuser
end
def create
@poll = Poll.new params[:poll]
@poll.user = cuser
raise AccessError unless @poll.can_create? cuser
if @poll.save
flash[:notice] = t(:polls_create)
redirect_to @poll
else
render :action => "new"
end
end
def update
raise AccessError unless @poll.can_update? cuser
if @poll.update_attributes params[:poll]
flash[:notice] = t(:polls_update)
redirect_to @poll
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @poll.can_destroy? cuser
@poll.destroy
redirect_to polls_url
end
private
def get_poll
@poll = Poll.find params[:id]
end
end

View file

@ -0,0 +1,72 @@
class PostsController < ApplicationController
before_filter :get_post, :except => [:new, :create]
respond_to :html, :js
def quote
raise AccessError unless @post.can_show? cuser
end
def new
@post = Post.new
@post.topic = Topic.find(params[:id])
raise AccessError unless @post.can_create? cuser
render :layout => "forums"
end
def edit
raise AccessError unless @post.can_update? cuser
render :layout => "forums"
end
def create
@post = Post.new(params[:post])
@post.user = cuser
raise AccessError unless @post.can_create? cuser
respond_to do |format|
if @post.save
flash[:notice] = t(:posts_create)
format.js { render }
else
flash[:error] = t(:posts_invalid) + @post.errors.full_messages.to_s
format.html { return_to }
end
end
end
def update
raise AccessError unless @post.can_update? cuser, params[:post]
if @post.update_attributes(params[:post])
flash[:notice] = t(:posts_update)
redirect_to @post.topic
else
render :action => "edit"
end
end
def trash
raise AccessError unless @post.can_destroy? cuser
@post.trash
if Topic.exists? @post.topic
redirect_to @post.topic
else
redirect_to @post.topic.forum
end
end
def destroy
raise AccessError unless @post.can_destroy? cuser
@post.destroy
if Topic.exists? @post.topic
redirect_to @post.topic
else
redirect_to @post.topic.forum
end
end
private
def get_post
@post = Post.find(params[:id])
end
end

View file

@ -0,0 +1,15 @@
class PredictionsController < ApplicationController
def create
@prediction = Prediction.new params[:prediction]
@prediction.user = cuser
raise AccessError unless @prediction.can_create? cuser
if @prediction.save
flash[:notice] = t(:predictions_create)
else
flash[:error] = @prediction.errors.full_messages.to_s
end
redirect_to @prediction.match
end
end

View file

@ -0,0 +1,26 @@
class RoundsController < ApplicationController
def index
sort = case params['sort']
when "start" then "start"
when "server" then "server_id"
when "team1" then "team1_id"
when "team2" then "team2_id"
when "map" then "map_name"
when "commander" then "commander_id"
end
@rounds = Round.basic.paginate \
:order => sort,
:page => params[:page],
:per_page => 30
if params[:ajax]
render :partial => "list", :layout => false
return
end
end
def show
@round = Round.find(params[:id])
end
end

View file

@ -0,0 +1,78 @@
class ServersController < ApplicationController
before_filter :get_server, :except => [:index, :refresh, :new, :create]
def refresh
Server.refresh
render :text => t(:servers_updated)
end
def index
@servers = Server.hlds.active.ordered.all :include => :user
@ns2 = Server.ns2.active.ordered.all :include => :user
@hltvs = Server.hltvs.active.ordered.all :include => :user
@officials = Server.ns2.active.ordered.where ["name LIKE ?", "%NSL%"]
end
def show
end
def new
@server = Server.new
raise AccessError unless @server.can_create? cuser
end
def edit
raise AccessError unless @server.can_update? cuser
end
def admin
@result = @server.execute params[:query] if params[:query]
raise AccessError unless @server.can_update? cuser
if request.xhr?
render :partial => "response", :layout => false
end
end
def create
@server = Server.new params[:server]
@server.user = cuser
raise AccessError unless @server.can_create? cuser
if @server.save
flash[:notice] = t(:server_create)
redirect_to @server
else
render :action => "new"
end
end
def update
raise AccessError unless @server.can_update? cuser
if @server.update_attributes params[:server]
flash[:notice] = t(:server_update)
redirect_to @server
else
render :action => "edit"
end
end
def default
raise AccessError unless @server.can_update? cuser
@server.default_record
render :text => "Ok"
end
def destroy
raise AccessError unless @server.can_destroy? cuser
@server.destroy
redirect_to(servers_url)
end
private
def get_server
@server = Server.find params[:id]
end
end

View file

@ -0,0 +1,39 @@
class ShoutmsgsController < ApplicationController
respond_to :html, :js
def index
@shoutmsgs = Shoutmsg.lastXXX.typebox
end
def show
if params[:id2]
@shoutmsgs = Shoutmsg.recent.of_object(params[:id], params[:id2]).reverse
else
@shoutmsgs = Shoutmsg.recent.box
end
end
def create
@shoutmsg = Shoutmsg.new params[:shoutmsg]
@shoutmsg.user = cuser
raise AccessError unless @shoutmsg.can_create? cuser
unless @shoutmsg.save
flash[:error] = t(:invalid_message)
end
end
def destroy
@shoutmsg = Shoutmsg.find params[:id]
raise AccessError unless @shoutmsg.can_destroy? cuser
@shoutmsg.destroy
redirect_to_back
end
private
def render_shoutmsgs shoutable_type = nil, shoutable_id = nil
end
end

View file

@ -0,0 +1,23 @@
class TeamersController < ApplicationController
def create
@teamer = Teamer.new params[:teamer]
raise AccessError unless @teamer.can_create? cuser, params[:teamer]
@teamer.user = cuser unless cuser.admin?
if @teamer.save
flash[:notice] = t(:applying_team) + @teamer.team.to_s
else
flash[:error] = @teamer.errors.full_messages.to_s
end
redirect_to_back
end
def destroy
@teamer = Teamer.find params[:id]
raise AccessError unless @teamer.can_destroy? cuser
@teamer.destroy
redirect_to_back
end
end

View file

@ -0,0 +1,72 @@
class TeamsController < ApplicationController
before_filter :get_team, :only => ['show', 'edit', 'update', 'destroy', 'recover']
def index
@teams = Team.with_teamers_num(0).ordered
end
def show
end
def new
@team = Team.new
raise AccessError unless @team.can_create? cuser
end
def edit
raise AccessError unless @team.can_update? cuser
end
def create
@team = Team.new params[:team]
@team.founder = cuser
raise AccessError unless @team.can_create? cuser
if @team.save
flash[:notice] = t(:teams_create)
redirect_to @team
else
render :action => "new"
end
end
def update
raise AccessError unless @team.can_update? cuser
if @team.update_attributes params[:team]
if params[:rank]
@team.teamers.present.each do |member|
rank = params[:rank]["#{member.id}"]
if cuser.admin? or (rank.to_i <= cuser.teamers.active.of_team(@team).first.rank)
if member.rank == Teamer::RANK_JOINER
member.user.update_attribute :team, @team
end
member.update_attribute :rank, rank
member.update_attribute :comment, params[:comment]["#{member.id}"]
end
end
end
flash[:notice] = t(:teams_update)
redirect_to edit_team_path(@team)
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @team.can_destroy? cuser
@team.destroy
redirect_to(teams_url)
end
def recover
raise AccessError unless @team.can_destroy? cuser
@team.recover
redirect_to(teams_url)
end
private
def get_team
@team = Team.find params[:id]
end
end

View file

@ -0,0 +1,81 @@
class TopicsController < ApplicationController
before_filter :get_topic, :only => [:show, :reply, :edit, :update, :destroy]
def index
render :partial => true, :locals => {:page => params[:p].to_i}
end
def show
raise AccessError unless @topic.can_show? cuser
@posts = @topic.posts.basic.paginate \
:page => params[:page],
:per_page => Topic::POSTS_PAGE
return_here
@topic.record_view_count(request.remote_ip, cuser.nil?)
@topic.read_by! cuser if cuser
@topic.forum.read_by! cuser if cuser
@newpost = Post.new
@newpost.topic = @topic
@newpost.user = cuser
@lock = (@topic.lock ? @topic.lock : Lock.new(:lockable => @topic))
render :layout => "forums"
end
def reply
@post = @topic.posts.build
raise AccessError unless @post.can_create? cuser
if request.xhr?
render "quickreply", :layout => false
else
render :layout => "forums"
end
end
def new
@topic = Topic.new
@topic.forum = Forum.find(params[:id])
raise AccessError unless @topic.can_create? cuser
render :layout => "forums"
end
def edit
raise AccessError unless @topic.can_update? cuser
render :layout => "forums"
end
def create
@topic = Topic.new(params[:topic])
@topic.user = cuser
raise AccessError unless @topic.can_create? cuser
if @topic.save
flash[:notice] = t(:topics_create)
redirect_to(@topic)
else
render :action => "new"
end
end
def update
raise AccessError unless @topic.can_update? cuser
if @topic.update_attributes(params[:topic])
flash[:notice] = t(:topics_update)
redirect_to(@topic)
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @topic.can_destroy? cuser
@topic.destroy
redirect_to(topics_url)
end
private
def get_topic
@topic = Topic.find(params[:id])
end
end

View file

@ -0,0 +1,29 @@
require 'rss/2.0'
require 'open-uri'
class TweetsController < ApplicationController
def index
@tweets = Tweet.all :order => "created_at DESC"
@nobody = true
end
def show
@tweet = Tweet.find(params[:id])
end
def refresh
open('http://twitter.com/statuses/user_timeline/16676427.rss') do |http|
RSS::Parser.parse(http.read, false).items.each do |item|
unless Tweet.first :conditions => {:link => item.link}
tweet = Tweet.new
tweet.link = item.link
tweet.msg = item.title.gsub(/NS2: /, "")
tweet.created_at = DateTime.parse item.pubDate.to_s
tweet.save
end
end
end
render :text => t(:tweets_refresh)
end
end

View file

@ -0,0 +1,130 @@
class UsersController < ApplicationController
before_filter :get_user, :only => [:show, :history, :popup, :agenda, :edit, :update, :destroy]
respond_to :html, :js
def index
@users = User.search(params[:search]).paginate(:per_page => 40, :page => params[:page])
end
def show
@page = "general"
respond_to do |format|
format.js do
pages = ["general", "favorites", "computer", "articles", "movies", "teams", "matches", "predictions", "comments"]
if pages.include?(params[:page])
@page = params[:page]
end
end
format.html {}
end
end
def agenda
@teamer = Teamer.new
@teamer.user = @user
end
def history
raise AccessError unless cuser and cuser.admin?
end
def popup
render :layout => false
end
def new
@user = User.new
@user.profile = Profile.new
@user.lastip = request.env['REMOTE_ADDR']
@user.can_create? cuser
end
def edit
raise AccessError unless @user.can_update? cuser
end
def create
@user = User.new params[:user]
@user.lastvisit = Date.today
@user.lastip = request.env['REMOTE_ADDR']
raise AccessError unless @user.can_create? cuser
if @user.valid? and @user.save
@user.profile = Profile.new
@user.profile.user = @user
@user.profile.save()
redirect_to :action => :show, :id => @user.id
save_session @user
else
render :action => "new"
end
end
def update
raise AccessError unless @user.can_update? cuser
if @user.update_attributes params[:user]
flash[:notice] = t(:users_update)
redirect_to_back
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @user.can_destroy? cuser
@user.destroy
redirect_to users_url
end
def login
return unless request.post?
if u = User.authenticate(params[:login][:username], params[:login][:password])
raise Error, t(:accounts_locked) if u.banned? Ban::TYPE_SITE
flash[:notice] = t(:login_successful)
save_session u
if session[:return_to]
return_to
else
redirect_to_back
end
else
flash[:error] = t(:login_unsuccessful)
redirect_to_back
end
end
def logout
if request.post?
session[:user] = nil
flash[:notice] = t(:login_out)
redirect_to :root
end
end
def forgot
if request.post?
if u = User.first(:conditions => {:username => params[:username], :email => params[:email]}) and u.send_new_password
flash[:notice] = t(:passwords_sent)
else
flash[:error] = t(:incorrect_information)
end
end
end
private
def get_user
@user = User.find(params[:id])
end
def save_session user
session[:user] = user.id
user.lastip = request.ip
user.lastvisit = DateTime.now
user.save()
end
end

View file

@ -0,0 +1,32 @@
class VersionsController < ApplicationController
before_filter :get_article
def index
@versions = @article.versions
render "articles/history"
end
def show
@version = @article.versions.find params[:id]
@nobody = true
render "articles/version"
end
def update
raise AccessError unless @article.can_update? cuser
@version = @article.versions.find params[:id]
@nobody = true
if @article.revert_to! @version.version
flash[:notice] = t(:articles_revert, :version => @version.version)
end
redirect_to @article
end
private
def get_article
@article = Article.find(params[:article_id])
end
end

View file

@ -0,0 +1,13 @@
class VotesController < ApplicationController
def create
@vote = Vote.new params[:vote]
@vote.user = cuser
raise AccessError unless @vote.can_create? cuser
if @vote.save
flash[:notice] = t(:votes_success)
end
redirect_to_back
end
end

View file

@ -0,0 +1,48 @@
class WeeksController < ApplicationController
before_filter :get_week, :except => [:new, :create]
def new
@week = Week.new
@week.contest = Contest.find params[:id]
raise AccessError unless @week.can_create? cuser
end
def edit
raise AccessError unless @week.can_update? cuser
end
def create
@week = Week.new(params[:week])
raise AccessError unless @week.can_create? cuser
if @week.save
flash[:notice] = t(:weeks_create)
redirect_to @week.contest
else
render :action => "new"
end
end
def update
raise AccessError unless @week.can_update? cuser
if @week.update_attributes(params[:week])
flash[:notice] = t(:weeks_update)
redirect_to @week.contest
else
render :action => "edit"
end
end
def destroy
raise AccessError unless @week.can_destroy? cuser
@week.destroy
redirect_to_back
end
private
def get_week
@week = Week.find params[:id]
end
end

View file

@ -0,0 +1,133 @@
module ApplicationHelper
def namelink model, length = nil
return if model.nil?
model = case model.class.to_s
when "DataFile"
model.movie ? model.movie : model
when "Comment"
model.commentable
when "Post"
model.topic
else
model
end
str = model.to_s
if length and str.length > length
link_to raw(str.to_s[0, length] + "..."), model
else
link_to raw(str), model
end
end
def shorten str, length
if length and str and str.to_s.length > length
str = str.to_s[0, length] + "..."
end
str
end
def longtime time
printtime time, "%d %B %y %H:%M"
end
def shorttime time
printtime time, "%d/%b/%y %H:%M"
end
def shortdate time
printtime time, "%d %b %y"
end
def longdate time
printtime time, "%d %B %Y"
end
def printtime time, format
return unless time
out = ""
out << '<span style="font-style: italic; ">'
out << time.strftime(format)
out << '</span>'
raw out
end
def cascade model, list
out = ""
list.each do |element|
name = key = element
result = ""
if element.instance_of?(Array)
name = element[0]
key = element[1]
end
if m = key.to_s.match(/^(.*)_b$/)
name = m[1]
key = m[1]
end
str = eval("model.#{key}")
next if str == "" or str.nil?
if model[key].instance_of?(Time)
result << shorttime(str)
elsif element.instance_of?(Symbol)
result << namelink(str)
elsif key.to_s.match(/^(.*)_b$/)
result << str.bbcode_to_html
else
result << h(str)
end
out << "<p>"
out << "<b>#{name.to_s.capitalize.gsub(/_s/, '').gsub(/_/, ' ')}</b>: "
out << result
out << "</p>"
end
raw out
end
def abslink text, url
raw link_to text, url
end
def flag country
if country and country.to_s.length > 0
image_tag "/images/flags/" + country.downcase + ".gif", :width => 18, :height => 12
else
image_tag "/images/flags/eu.gif"
end
end
def add_comments object
@comment = Comment.new :commentable => object
@comments = object.comments.ordered.with_userteam
return_here
render :partial => "comments/index"
end
def bbcode
link_to "(BBCode)", article_url(:id => 536)
end
def sortable(column, title = nil)
title ||= column.titleize
css_class = (column == sort_column) ? "current #{sort_direction}" : nil
direction = (column == sort_column && sort_direction == "asc") ? "desc" : "asc"
link_to title, {:sort => column, :direction => direction}, {:class => css_class}
end
def link_to_remove_fields(name, f)
f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
end
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
render(association.to_s.singularize, :f => builder)
end
link_to_function(name, ("add_fields(this, '#{association}', '#{escape_javascript(fields)}')"))
end
end

View file

@ -0,0 +1,18 @@
module GathersHelper
def render_gather
if @gather.status == Gather::STATE_RUNNING
headers["Gather"] = "running"
render :partial => "running", :layout => false
elsif @gather.status == Gather::STATE_VOTING
if @gatherer and @gather.gatherer_votes.first(:conditions => {:user_id => cuser.id})
headers["Gather"] = "voted"
else
headers["Gather"] = "voting"
end
render :partial => "voting", :layout => false
elsif @gather.status == Gather::STATE_PICKING or @gather.status == Gather::STATE_FINISHED
headers["Gather"] = "picking"
render :partial => "picking", :layout => false
end
end
end

View file

@ -0,0 +1,11 @@
module PollsHelper
def add_option_link(name, form)
link_to_function name do |page|
option = render :partial => 'option', :locals => { :pf => form, :options => Option.new }
page << %{
this.counter = typeof this.counter == 'undefined' ? 0 : this.counter + 1;
$('options').insert({ bottom: "#{ escape_javascript option }".replace(/\\[\\d+\\]/g, "[" + this.counter + "]") });
}
end
end
end

View file

@ -0,0 +1,5 @@
module TopicsHelper
def lastpost topic
topic_url(topic, :page => topic.last_page, :anchor => "post_#{topic.posts.last.id}")
end
end

View file

@ -0,0 +1,21 @@
module UsersHelper
def sort_link text, param
key = param
key += "_reverse" if params[:sort] == param
options = {
:url => {:params => params.merge({:sort => key, :page => nil})},
:with => "`_method=get`",
:update => 'usersTable',
:before => "Element.show('spinner')",
:success => "Element.hide('spinner')",
}
html_options = {
:title => "Sort by this field",
:href => url_for(:params => params.merge({:sort => key, :page => nil})),
}
# link_to_remote text, options, html_options
end
end

View file

@ -0,0 +1,59 @@
class Notifications < ActionMailer::Base
default :from => "staff@ensl.org"
def password user, password
@user = user
@pass = password
mail :to => user.email,
:subject => 'ENSL account password'
end
def pm user, pm
@user = user
@pm = pm
mail :to => user.email,
:subject => 'New ENSL private message'
end
def gather user, gather
@user = user
@gather = gather
mail :to => user.email,
:subject => 'ENSL gather running'
end
def comments user, object
@user = user
@object = object
mail :to => user.email,
:subject => 'New ENSL comments'
end
def challenge user, challenge
@user = user
@challenge = challenge
mail :to => user.email,
:subject => 'New ENSL challenge'
end
def match user, match
@user = user
@match = match
mail :to => user.email,
:subject => 'New ENSL match'
end
def news user, news
@user = user
@news = news
mail :to => user.email,
:subject => 'News on ENSL: ' + news.title
end
def article user, article
@user = user
@article = article
mail :to => user.email,
:subject => 'News on ENSL: ' + article.title
end
end

130
app/models/article.rb Normal file
View file

@ -0,0 +1,130 @@
require File.join(Rails.root, 'vendor', 'plugins', 'has_view_count', 'init.rb')
require 'rbbcode'
class Article < ActiveRecord::Base
include Exceptions
include Extra
STATUS_PUBLISHED = 0
STATUS_DRAFT = 1
RULES = 400
HISTORY = 401
HOF = 402
SPONSORS = 403
LINKS = 404
COMPETITIVE = 405
PLUGIN = 426
EXTRA = 428
SB_RULES = 450
G_RULES = 464
attr_protected :id, :updated_at, :created_at, :user_id, :version
scope :recent, :order => "created_at DESC", :limit => 8
scope :with_comments,
:select => "articles.*, COUNT(C.id) AS comment_num",
:joins => "LEFT JOIN comments C ON C.commentable_type = 'Article' AND C.commentable_id = articles.id",
:group => "articles.id"
scope :ordered, :order => "articles.created_at DESC"
scope :limited, :limit => 5
scope :nodrafts, :conditions => {:status => STATUS_PUBLISHED}
scope :drafts, :conditions => {:status => STATUS_DRAFT}
scope :articles, :conditions => ["category_id IN (SELECT id FROM categories WHERE domain = ?)", Category::DOMAIN_ARTICLES]
scope :onlynews, :conditions => ["category_id IN (SELECT id FROM categories WHERE domain = ?)", Category::DOMAIN_NEWS]
scope :category, lambda { |cat| {:conditions => {:category_id => cat}} }
scope :domain, lambda { |domain| {:include => "category", :conditions => {"categories.domain" => domain}} }
scope :nospecial, :conditions => ["category_id != ?", Category::SPECIAL]
scope :interviews, :conditions => ["category_id = ?", Category::INTERVIEWS]
belongs_to :user
belongs_to :category
has_many :comments, :as => :commentable, :order => "created_at ASC", :dependent => :destroy
has_many :files, :class_name => "DataFile", :order => "created_at DESC", :dependent => :destroy
validates_length_of :title, :in => 1..50
validates_length_of :text, :in => 1..64000
validates_presence_of :user, :category
validate :validate_status
before_validation :init_variables, :if => Proc.new{ |model| model.new_record? }
before_save :format_text
after_save :send_notifications
after_destroy :remove_readings
has_view_count
acts_as_readable
acts_as_versioned
non_versioned_columns << 'category_id'
non_versioned_columns << 'status'
non_versioned_columns << 'user_id'
def to_s
title
end
def previous_article
category.articles.nodrafts.first(:conditions => ["id < ?", self.id], :order => "id DESC")
end
def next_article
category.articles.nodrafts.first(:conditions => ["id > ?", self.id], :order => "id ASC")
end
def statuses
{STATUS_PUBLISHED => "Published", STATUS_DRAFT => "Draft"}
end
def validate_status
errors.add :status, I18n.t(:invalid_status) unless statuses.include? status
end
def init_variables
self.status = STATUS_DRAFT unless user.admin?
self.text_coding = CODING_BBCODE if !user.admin? and text_coding = CODING_HTML
end
def format_text
if text_coding == CODING_BBCODE
self.text_parsed = RbbCode::Parser.new.parse(text)
elsif text_coding == CODING_MARKDOWN
self.text_parsed = BlueCloth.new(text).to_html
end
end
def send_notifications
if (new_record? or status_changed?) and status == STATUS_PUBLISHED
case category.domain
when Category::DOMAIN_NEWS
Profile.all(:include => :user, :conditions => "notify_news = 1").each do |p|
Notifications.news p.user, self if p.user
end
when Category::DOMAIN_ARTICLES
Profile.all(:include => :user, :conditions => "notify_articles = 1").each do |p|
Notifications.article p.user, self if p.user
end
end
end
end
def remove_readings
Reading.delete_all ["readable_type = 'Category' AND readable_id = ?", category_id]
end
def can_show? cuser
status != STATUS_DRAFT or (cuser and (user == cuser or cuser.admin?))
end
def can_create? cuser
cuser and !cuser.banned?(Ban::TYPE_MUTE)
end
def can_update? cuser, params = {}
cuser and !cuser.banned?(Ban::TYPE_MUTE) and (cuser.admin? or (user == cuser and !params.keys.include? "status"))
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

88
app/models/ban.rb Normal file
View file

@ -0,0 +1,88 @@
class Ban < ActiveRecord::Base
include Extra
TYPE_SITE = 0
TYPE_MUTE = 1
TYPE_LEAGUE = 2
TYPE_SERVER = 3
TYPE_VENT = 4
TYPE_GATHER = 5
VENT_BANS = "tmp/bans.txt"
attr_protected :id, :created_at, :updated_at
attr_accessor :ts, :sign, :len, :user_name
scope :ordered, :order => "created_at DESC"
scope :effective, :conditions => "expiry > UTC_TIMESTAMP()"
scope :ineffective, :conditions => "expiry < UTC_TIMESTAMP()"
validate :validate_ts
validate :validate_type
validate :validate_ventban
validates_format_of :steamid, :with => /\A([0-9]{1,10}:){2}[0-9]{1,10}\Z/, :allow_blank => true
validates_format_of :addr, :with => /\A([0-9]{1,3}\.){3}[0-9]{1,3}:?[0-9]{0,5}\z/, :allow_blank => true
validates_length_of :reason, :maximum => 255, :allow_nil => true, :allow_blank => true
before_validation :check_user
belongs_to :user
belongs_to :server
def color
expiry.past? ? "green" : "red"
end
def types
{TYPE_SITE => "Website Logon",
TYPE_MUTE => "Commenting",
TYPE_LEAGUE => "Contests",
TYPE_SERVER => "NS Servers",
TYPE_VENT => "Ventrilo",
TYPE_GATHER => "Gather"}
end
def validate_ts
if ts and Verification.verify(steamid + ts.to_s) != sign
errors.add :ts, I18n.t(:wrong_verification_code)
end
end
def validate_type
errors.add :ban_type, I18n.t(:invalid_ban_type) unless types.include? ban_type
end
def validate_ventban
if ban_type == TYPE_VENT and !ip.match(/\A([0-9]{1,3}\.){3}[0-9]{1,3}\z/)
errors.add :ip, I18n.t(:ventrilos_ip_ban)
end
end
def check_user
if user_name
self.user = User.find_by_username(user_name)
else
self.user = User.first(:conditions => {:steamid => steamid})
self.server = Server.first(:conditions => ["CONCAT(ip, ':', port) = ?", addr])
end
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
def self.refresh
#file = File.new(VENT_BANS, "w")
#Ban.all(:conditions => ["ban_type = ? AND expiry > UTC_TIMESTAMP()", TYPE_VENT]).each do |ban|
# file.write "#{ban.ip},,,"
#end
#file.close
end
end

69
app/models/bracket.rb Normal file
View file

@ -0,0 +1,69 @@
class Bracket < ActiveRecord::Base
include Extra
attr_protected :id, :created_at, :updated_at
belongs_to :contest
has_many :bracketers
def to_s
"#" + self.id.to_s
end
def get_bracketer row, col
b = bracketers.pos(row, col).first
unless b
b = bracketers.build
b.row = row.to_i
b.column = col.to_i
b.save
end
return b
end
def options
["-- Matches"] \
+ contest.matches.collect{|c| [c, "match_#{c.id}"]} \
+ ["-- Teams"] \
+ contest.contesters.collect{|c| [c, "contester_#{c.id}"]}
end
def default row, col
if b = bracketers.pos(row, col).first
if b.match
return "match_#{b.match_id}"
elsif b.contester
return "contester_#{b.team_id}"
end
end
end
def update_cells params
params.each do |row, cols|
cols.each do |col, val|
unless val.include? "--"
b = get_bracketer(row, col)
if m = val.match(/match_(\d*)/)
b.update_attribute :match_id, m[1].to_i
b.update_attribute :team_id, nil
elsif m = val.match(/contester_(\d*)/)
b.update_attribute :team_id, m[1].to_i
b.update_attribute :match_id, nil
end
end
end
end
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

25
app/models/bracketer.rb Normal file
View file

@ -0,0 +1,25 @@
class Bracketer < ActiveRecord::Base
include Exceptions
include Extra
attr_protected :id, :updated_at, :created_at
belongs_to :contest
belongs_to :match
belongs_to :contester, :foreign_key => "team_id"
scope :pos, lambda { |row, col| {:conditions => {"row" => row, "column" => col}} }
def to_s
if self.match_id
if match.match_time.past? and (match.score1 and match.score2)
winner = match.score1 > match.score2 ? match.contester1.team : match.contester2.team
return "#{self.match.score1} - #{self.match.score2}"
else
return self.match.match_time.strftime("%H:%M %d/%b")
end
elsif self.contester
return self.contester.to_s[0, 10]
end
end
end

70
app/models/category.rb Normal file
View file

@ -0,0 +1,70 @@
class Category < ActiveRecord::Base
include Extra
MAIN = 1
SPECIAL = 10
INTERVIEWS = 11
RULES = 36
DOMAIN_NEWS = 0
DOMAIN_ARTICLES = 1
DOMAIN_ISSUES = 2
DOMAIN_SITES = 3
DOMAIN_FORUMS = 4
DOMAIN_MOVIES = 5
DOMAIN_GAMES = 6
PER_PAGE = 3
attr_protected :id, :updated_at, :created_at, :sort
validates_length_of :name, :in => 1..30
validate :validate_domain
scope :ordered, :order => "sort ASC, created_at DESC"
scope :domain, lambda { |domain| {:conditions => {:domain => domain}} }
scope :nospecial, :conditions => ["name != 'Special'"]
scope :newest, :include => :articles, :order => "articles.created_at DESC"
scope :page, lambda { |page| {:limit => "#{(page-1)*PER_PAGE}, #{(page-1)*PER_PAGE+PER_PAGE}"} }
scope :of_user, lambda { |user| {:conditions => {"articles.user_id" => user.id}, :include => :articles} }
has_many :articles, :order => "created_at DESC"
has_many :issues, :order => "created_at DESC"
has_many :forums, :order => "forums.position"
has_many :movies
has_many :maps
has_many :gathers
has_many :servers
acts_as_readable
def to_s
name
end
def domains
{DOMAIN_NEWS => 'News',
DOMAIN_ARTICLES => 'Articles',
DOMAIN_ISSUES => 'Issues',
DOMAIN_SITES => "Sites",
DOMAIN_FORUMS => "Forums",
DOMAIN_MOVIES => "Movies",
DOMAIN_GAMES => "Games"}
end
def validate_domain
errors.add :domain, I18n.t(:invalid_domain) unless domains.include? domain
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

239
app/models/challenge.rb Normal file
View file

@ -0,0 +1,239 @@
class Challenge < ActiveRecord::Base
include Extra
STATUS_PENDING = 0
STATUS_ACCEPTED = 1
STATUS_DEFAULT = 2
STATUS_FORFEIT = 3
STATUS_DECLINED = 4
AUTO_DEFAULT_TIME = 10800 # Normal default time: 3 hours
CHALLENGE_BEFORE_MANDATORY = 432000 # Min. time threshold for mandatory matches: 5 days
CHALLENGE_BEFORE_VOLUNTARY = 900 # Min. time threshold for voluntary matches: 15 mins
ACCEPT_BEFORE_MANDATORY = 86400 # Time to accept before mandatory match time: 1 day
ACCEPT_BEFORE_VOLUNTARY = 300 # Time to accept before voluntary match time: 5 mins
MATCH_LENGTH = 7200 # Usual match length (for servers): 2 hours
attr_protected :id, :updated_at, :created_at, :default_time, :user_id, :status
validates_presence_of :contester1, :contester2, :server, :map1
validates_presence_of :map2, :on => :update
#validates_datetime :match_time, :default_time
#validates_length_of [:details, :response], :maximum => 255, :allow_blank => true, :allow_nil => true
#validate_on_create:validate_teams
#validate_on_create:validate_contest
#validate_on_create:validate_mandatory
#validate_on_create:validate_match_time
#validate_on_create:validate_server
#validate_on_create:validate_map1
#validate_on_update :validate_map2
#validate_on_update :validate_status
scope :of_contester,
lambda { |contester| {:conditions => ["contester1_id = ? OR contester2_id = ?", contester.id, contester.id]} }
scope :within_time,
lambda { |from, to| {:conditions => ["match_time > ? AND match_time < ?", from.utc, to.utc]} }
scope :around,
lambda { |time| {:conditions => ["match_time > ? AND match_time < ?", time.ago(MATCH_LENGTH).utc, time.ago(-MATCH_LENGTH).utc]} }
scope :on_week,
lambda { |time| {:conditions => ["match_time > ? and match_time < ?", time.beginning_of_week, time.end_of_week]} }
scope :pending, :conditions => {:status => STATUS_PENDING}
scope :mandatory, :conditions => {:mandatory => true}
scope :future, :conditions => "match_time > UTC_TIMESTAMP()"
scope :past, :conditions => "match_time < UTC_TIMESTAMP()"
has_one :match
belongs_to :map1, :class_name => "Map"
belongs_to :map2, :class_name => "Map"
belongs_to :user
belongs_to :server
belongs_to :contester1, :class_name => "Contester", :include => 'team'
belongs_to :contester2, :class_name => "Contester", :include => 'team'
def statuses
{STATUS_PENDING => "Pending response",
STATUS_ACCEPTED => "Accepted",
STATUS_DEFAULT => "Default Time",
STATUS_FORFEIT => "Forfeited",
STATUS_DECLINED => "Declined"}
end
def autodefault
match_time - (mandatory ? ACCEPT_BEFORE_MANDATORY : ACCEPT_BEFORE_VOLUNTARY)
end
def get_margin
mandatory ? CHALLENGE_BEFORE_MANDATORY : CHALLENGE_BEFORE_VOLUNTARY
end
def get_deadline
mandatory ? ACCEPT_BEFORE_MANDATORY : ACCEPT_BEFORE_VOLUNTARY
end
def get_contester1
self.contester1 = user.active_contesters.of_contest(contester2.contest).first
end
def before_validation_on_create
self.status = STATUS_PENDING
self.default_time = match_time.end_of_week.change \
:hour => contester1.contest.default_time.hour,
:minute => contester1.contest.default_time.strftime("%M").to_i
end
def after_create
contester2.team.teamers.active.leaders.each do |teamer|
if teamer.user.profile.notify_pms
Notifications.challenge teamer.user, self
end
end
end
def validate_teams
if contester1.team == contester2.team
errors.add_to_base I18n.t(:challenges_yourself)
end
if contester1.contest != contester2.contest
errors.add_to_base I18n.t(:challenges_opponent_contest)
end
if !contester2.active or !contester2.team.active
errors.add_to_base I18n.t(:challenges_opponent_inactive)
end
if !contester1.active or !contester1.team.active
errors.add_to_base I18n.t(:challenges_inactive)
end
end
def validate_contest
if contester1.contest.end.past? or contester1.contest.status == Contest::STATUS_CLOSED
errors.add_to_base I18n.t(:contests_closed)
end
if contester1.contest.contest_type != Contest::TYPE_LADDER and !match
errors.add_to_base I18n.t(:contests_notladder)
end
end
def validate_mandatory
return unless mandatory
if contester2.score < contester1.score
errors.add_to_base I18n.t(:challenges_mandatory)
end
if Challenge.pending.count(:conditions => \
["contester1_id = ? AND contester2_id = ? AND mandatory = true AND default_time < UTC_TIMESTAMP()",
contester1.id, contester2.id]) > 0
errors.add_to_base I18n.t(:challenges_mandatory_handled)
end
if Match.of_contester(contester2).on_week(match_time).count > 0
errors.add_to_base I18n.t(:challenges_opponent_week)
end
if Challenge.of_contester(contester2).mandatory.on_week(match_time).count > 0
errors.add_to_base I18n.t(:challenges_opponent_mandatory_week)
end
if Challenge.of_contester(contester2).mandatory.on_week(default_time).count > 0
errors.add_to_base I18n.t(:challenges_opponent_mandatory_week_defaulttime)
end
if Match.of_contester(contester2).around(default_time).count > 0
errors.add_to_base I18n.t(:challenges_opponent_defaulttime)
end
end
def validate_match_time
if (match_time-get_margin).past?
if get_margin > 86400
errors.add_to_base I18n.t(:matches_time1) + get_margin / 60 / 60 / 24 + I18n.t(:matches_time2)
else
errors.add_to_base I18n.t(:matches_time1) + get_margin / 60 + I18n.t(:matches_time3)
end
end
if Challenge.of_contester(contester2).around(match_time).pending.count > 0
errors.add_to_base I18n.t(:challenges_opponent_specifictime)
end
if Match.of_contester(contester2).around(match_time).count > 0
errors.add_to_base I18n.t(:challenges_opponent_match_specifictime)
end
if match_time > contester1.contest.end
errors.add_to_base I18n.t(:contests_end)
end
end
def validate_server
unless server and server.official
errors.add_to_base I18n.t(:servers_notavailable)
end
unless server.is_free match_time
errors.add_to_base I18n.t(:servers_notfree_specifictime)
end
if !server.is_free default_time
errors.add_to_base I18n.t(:servers_notfree_defaulttime)
end
end
def validate_map1
unless contester1.contest.maps.exists?(map1)
errors.add_to_base I18n.t(:contests_map_notavailable)
end
end
def validate_map2
unless contester2.contest.maps.exists?(map2)
errors.add_to_base I18n.t(:contests_map_notavailable)
end
end
def validate_status
if mandatory and ![STATUS_ACCEPTED, STATUS_DEFAULT, STATUS_FORFEIT].include? status
errors.add_to_base I18n.t(:challenges_mandatory_invalidresult)
end
unless statuses.include? status
errors.add_to_base I18n.t(:challenges_mandatory_invalidresult)
end
end
def after_update
if status_changed?
if status == STATUS_ACCEPTED
make_match.save
elsif status == STATUS_DEFAULT
m = make_match
m.match_time = default_time
m.save
elsif status == STATUS_FORFEIT
m = make_match
m.forfeit = true
m.score1 = 4
m.score2 = 0
m.match_time = default_time
m.save
end
end
end
def make_match
match = Match.new
match.contester1 = contester1
match.contester2 = contester2
match.map1 = map1
match.map2 = map2
match.contest = contester1.contest
match.challenge = self
match.server = server
match.match_time = match_time
match
end
def can_create? cuser
return false unless cuser
return false if cuser.banned?(Ban::TYPE_LEAGUE)
validate_teams
validate_contest
true if (contester1.team.is_leader?(cuser) or cuser.admin?) and errors.size == 0
end
def can_update? cuser
cuser and (contester2.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING and autodefault.future?
end
def can_destroy? cuser
cuser and (contester1.team.is_leader? cuser or cuser.admin?) and status == STATUS_PENDING and autodefault.future?
end
end

50
app/models/comment.rb Normal file
View file

@ -0,0 +1,50 @@
require 'rbbcode'
class Comment < ActiveRecord::Base
include Extra
attr_protected :id, :updated_at, :created_at, :user_id
scope :with_userteam, :include => {:user => :team}
scope :recent, :order => "id DESC", :limit => 10
scope :recent3, :order => "id DESC", :limit => 3
scope :recent5, :order => "id DESC", :limit => 5, :group => "commentable_id, commentable_type"
scope :filtered, :conditions => ["commentable_type != 'Issue'"]
scope :ordered, :order => "id ASC"
belongs_to :user
belongs_to :commentable, :polymorphic => true
validates_presence_of :commentable, :user
validates_length_of :text, :in => 1..10000
before_save :parse_text
# acts_as_indexed :fields => [:text]
def parse_text
self.text_parsed = RbbCode::Parser.new.parse(text)
end
def after_create
# if commentable_type == "Movie" or commentable_type == "Article" and commentable.user and commentable.user.profile.notify_own_stuff
# Notifications.deliver_comments commentable.user, commentable
# end
end
def can_create? cuser
return false unless cuser
#errors.add_to_base I18n.t(:comments_locked) if !commentable.lock.nil? and commentable.lock
errors.add_to_base I18n.t(:bans_mute) if cuser.banned? Ban::TYPE_MUTE
errors.add_to_base I18n.t(:registered_for_week) unless cuser.verified?
return errors.count == 0
end
def can_update? cuser
cuser and user == cuser or cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

114
app/models/contest.rb Normal file
View file

@ -0,0 +1,114 @@
class Contest < ActiveRecord::Base
include Extra
WEIGHT = 30.0
STATUS_OPEN = 0
STATUS_PROGRESS = 1
STATUS_CLOSED = 3
TYPE_LADDER = 0
TYPE_LEAGUE = 1
TYPE_BRACKET = 2
attr_protected :id, :updated_at, :created_at
scope :active, :conditions => ["status != ?", STATUS_CLOSED]
scope :inactive, :conditions => {:status => STATUS_CLOSED}
scope :joinable, :conditions => {:status => STATUS_OPEN}
scope :with_contesters, :include => :contesters
scope :ordered, :order => "start DESC"
scope :nsls1, :conditions => ["name LIKE ?", "NSL S1:%"]
scope :nsls2, :conditions => ["name LIKE ?", "NSL S2:%"]
scope :ns1seasons, :conditions => ["name LIKE ?", "S%:%"]
has_many :matches, :dependent => :destroy
has_many :weeks, :dependent => :destroy
has_many :contesters, :dependent => :destroy, :include => :team
has_many :predictions, :through => :matches
has_many :brackets
has_many :preds_with_score,
:source => :predictions,
:through => :matches,
:select => "predictions.id, predictions.user_id,
SUM(result) AS correct,
SUM(result)/COUNT(*)*100 AS score,
COUNT(*) AS total",
:conditions => "result IS NOT NULL",
:group => "predictions.user_id",
:order => "correct DESC"
has_and_belongs_to_many :maps
belongs_to :demos, :class_name => "Directory"
belongs_to :winner, :class_name => "Contester"
belongs_to :rules, :class_name => "Article"
validates_presence_of :name, :start, :end, :status, :default_time
validates_length_of :name, :in => 1..50
validates_length_of :short_name, :in => 1..8, :allow_nil => true
validate :validate_status
validate :validate_contest_type
def to_s
name
end
def status_s
statuses[status]
end
def default_s
"Sunday " + default_time.to_s
end
def statuses
{STATUS_OPEN => "In Progress (signups open)", STATUS_PROGRESS => "In Progress (signups closed)", STATUS_CLOSED => "Closed"}
end
def types
{TYPE_LADDER => "Ladder", TYPE_LEAGUE => "League", TYPE_BRACKET => "Bracket"}
end
def validate_status
errors.add :status, I18n.t(:invalid_status) unless statuses.include? status
end
def validate_contest_type
errors.add :contest_type, I18n.t(:contests_invalidtype) unless types.include? contest_type
end
def recalculate
Match.update_all("diff = null, points1 = null, points2 = null", {:contest_id => self.id})
Contester.update_all("score = 0, win = 0, loss = 0, draw = 0, extra = 0", {:contest_id => self.id})
matches.finished.chrono.each do |match|
match.recalculate
match.save
end
end
def elo_score score1, score2, diff, level = self.modulus_base, weight = self.weight, moduluses = [self.modulus_even, self.modulus_3to1, self.modulus_4to0]
points = (score2-score1).abs
modulus = moduluses[0].to_f if points <= 1
modulus = moduluses[1].to_f if points == 2
modulus = moduluses[2].to_f if points >= 3
if score1 == score2
result = 0.5
elsif score1 > score2
result = 1.0
elsif score2 > score1
result = 0.0
end
prob = 1.0/(10**(diff.to_f/weight.to_f)+1.0)
total = (level.to_f*modulus*(result-prob)).round
return total
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

100
app/models/contester.rb Normal file
View file

@ -0,0 +1,100 @@
class Contester < ActiveRecord::Base
include Extra
TREND_FLAT = 0
TREND_UP = 1
TREND_DOWN = 2
attr_protected :id, :updated_at, :created_at, :trend
attr_accessor :user
scope :active, :include => :team, :conditions => {"contesters.active" => true}
scope :ordered, :select => "contesters.*, (score + extra) AS total_score", :order => "total_score DESC, score DESC, win DESC, loss ASC"
scope :chronological, :order => "created_at DESC"
scope :of_contest, lambda { |contest| {:conditions => {"contesters.contest_id" => contest.id}} }
has_many :challenges_sent, :class_name => "Challenge", :foreign_key => "contester1_id"
has_many :challenges_received, :class_name => "Challenge", :foreign_key => "contester2_id"
has_many :matches, :through => :contest, :conditions => "(contester1_id = contesters.id OR contester2_id = contesters.id)"
belongs_to :team
belongs_to :contest
validates_presence_of :team, :contest
validates_inclusion_of [:score, :win, :loss, :draw, :extra], :in => 0..9999, :allow_nil => true
validates_uniqueness_of :team_id, :scope => :contest_id, :message => "You can't join same contest twice."
#validate_on_create:validate_member_participation
#validate_on_create:validate_contest
#validate_on_create:validate_playernumber
before_create :init_variables
def to_s
team.to_s
end
def total
score + extra.to_i
end
def statuses
{false => "Inactive", true => "Active"}
end
def lineup
contest.status == Contest::STATUS_CLOSED ? team.teamers.distinct : team.teamers.active
end
def get_matches
contest.matches.all :conditions => ["contester1_id = ? OR contester2_id = ?", id, id]
end
def init_variables
self.active = true
self.trend = Contester::TREND_FLAT
self.extra = 0
end
def validate_member_participation
# TODO joku erhe
# for member in team.teamers.present do
# for team in member.user.active_teams do
# if team.contesters.active.exists?(:contest_id => contest_id)
# errors.add_to_base "Member #{member.user} is already participating with team #{team.name}"
# end
# end
# end
end
def validate_contest
if contest.end.past? or contest.status == Contest::STATUS_CLOSED
errors.add :contest, I18n.t(:contests_closed)
end
end
def validate_playernumber
if team.teamers.active.distinct.count < 6
errors.add :team, I18n.t(:contests_join_need6)
end
end
def destroy
update_attribute :active, false
end
def can_create? cuser, params = {}
return false unless cuser
return false if cuser.banned?(Ban::TYPE_LEAGUE)
return true if cuser.admin?
return true if team.is_leader? cuser and Verification.contain params, [:team_id, :contest_id]
return false
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and team.is_leader? cuser or cuser.admin?
end
end

137
app/models/data_file.rb Normal file
View file

@ -0,0 +1,137 @@
require File.join(Rails.root, 'vendor', 'plugins', 'acts_as_rateable', 'init.rb')
require 'digest/md5'
class DataFile < ActiveRecord::Base
include Extra
MEGABYTE = 1048576
attr_accessor :related_id
attr_protected :id, :updated_at, :created_at, :path, :size, :md5
scope :recent, :order => "created_at DESC", :limit => 8
scope :demos, :order => "created_at DESC", :conditions => ["directory_id IN (SELECT id FROM directories WHERE parent_id = ?)", Directory::DEMOS]
scope :ordered, :order => "created_at DESC"
scope :movies, :order => "created_at DESC", :conditions => {:directory_id => Directory::MOVIES}
scope :not, lambda { |file| {:conditions => ["id != ?", file.id]} }
scope :unrelated, :conditions => "related_id is null"
has_many :related_files, :class_name => "DataFile", :foreign_key => :related_id
has_many :comments, :as => :commentable
has_one :movie, :foreign_key => :file_id, :dependent => :destroy
has_one :preview, :class_name => "Movie", :foreign_key => :preview_id, :dependent => :nullify
has_one :match, :foreign_key => :demo_id
belongs_to :directory
belongs_to :related, :class_name => "DataFile"
belongs_to :article
validates_length_of [:description, :path], :maximum => 255
before_save :process_file
after_create :create_movie, :if => Proc.new {|file| file.directory_id == Directory::MOVIES and !file.location.include?("_preview.mp4") }
after_save :update_relations, :if => Proc.new { |file| file.related_id_changed? and related_files.count > 0 }
acts_as_rateable
mount_uploader :name, FileUploader
def to_s
(description.nil? or description.empty?) ? File.basename(name.to_s) : description
end
def md5_s
md5.upcase
end
def extra_url
url.to_s.gsub(/^\/files/, "http://extra.ensl.org/static")
end
def size_s
(size.to_f/MEGABYTE).round(2).to_s + " MB"
end
def location
name.current_path
end
def url
name.url
end
def process_file
self.md5 = "e948c22100d29623a1df48e1760494df"
if article
self.directory_id = Directory::ARTICLES
end
if File.exists?(location) and (size != File.size(location) or created_at != File.mtime(location))
self.md5 = Digest::MD5.hexdigest(File.read(location))
self.size = File.size(location)
self.created_at = File.mtime(location)
end
if path.nil? or directory_id_changed?
self.path = File.join(directory.path, File.basename(name.to_s))
end
if !new_record? and directory_id_changed? and File.exists?(name.current_path)
FileUtils.mv(location, path)
end
if description.nil? or description.empty?
self.description = File.basename(location).gsub(/[_\-]/, " ").gsub(/\.\w{1,5}$/, "")
self.description = description.split(/\s+/).each{ |word| word.capitalize! }.join(' ')
end
if match
self.description = match.contester1.to_s + " vs " + match.contester2.to_s
end
if location.include? "_preview.mp4" and !related
stripped = location.gsub(/_preview\.mp4/, "")
DataFile.all(:conditions => ["path LIKE ?", stripped + "%"]).each do |r|
if r.location.match(/#{stripped}\.\w{1,5}$/)
self.related = r
end
end
end
if movie and (new_record? or md5_changed?)
movie.get_length
end
end
def create_movie
movie = Movie.new
movie.file = self
movie.make_snapshot 5
movie.save
end
def update_relations
related_files.each do |rf|
rf.related = self.related
rf.save
end
end
def rateable? user
user and !rated_by?(user)
end
def can_create? cuser
return false unless cuser
return false if cuser.banned?(Ban::TYPE_MUTE)
(cuser.admin? or \
(article and article.can_create? cuser) or \
(directory_id == Directory::MOVIES and cuser.has_access? Group::MOVIES))
end
def can_update? cuser
cuser and cuser.admin? or (article and article.can_create? cuser)
end
def can_destroy? cuser
cuser and cuser.admin? or (article and article.can_create? cuser)
end
end

102
app/models/directory.rb Normal file
View file

@ -0,0 +1,102 @@
class Directory < ActiveRecord::Base
include Extra
ROOT = 1
DEMOS = 5
DEMOS_DEFAULT = 19
DEMOS_GATHERS = 92
MOVIES = 30
ARTICLES = 39
attr_protected :id, :updated_at, :created_at, :path
belongs_to :parent, :class_name => "Directory"
has_many :subdirs, :class_name => "Directory", :foreign_key => :parent_id
has_many :files, :class_name => "DataFile", :order => "name"
scope :ordered, :order => "name ASC"
scope :filtered, :conditions => {:hidden => false}
scope :of_parent, lambda { |parent| {:conditions => {:parent_id => parent.id}} }
validates_length_of [:name, :path], :in => 1..255
validates_format_of :name, :with => /\A[A-Za-z0-9]{1,20}\z/, :on => :create
validates_length_of :name, :in => 1..25
validates_inclusion_of :hidden, :in => [true, false]
before_validation :init_variables
after_create :make_path
after_save :update_timestamp
before_destroy :remove_files
after_destroy :remove_path
def to_s
name
end
def init_variables
self.path = File.join(parent.path, name.downcase)
self.hidden = false if hidden.nil?
end
def make_path
Dir.mkdir(path) unless File.exists?(path)
end
def update_timestamp
self.created_at = File.mtime(path) if File.exists?(path)
end
def remove_files
files.each do |subdir|
subdir.destroy
end
subdirs.each do |subdir|
subdir.destroy
end
end
def remove_path
Dir.unlink(path) if File.exists?(path)
end
def process_dir
ActiveRecord::Base.transaction do
Dir.glob("#{path}/*").each do |file|
if File.directory?(file)
if dir = Directory.find_by_path(file)
dir.save!
else
dir = Directory.new
dir.name = File.basename(file)
dir.path = file
dir.parent = self
dir.save!
end
dir.process_dir
else
if dbfile = DataFile.find_by_path(file)
dbfile.directory = self
dbfile.save!
elsif (File.mtime(file) + 100).past?
dbfile = DataFile.new
dbfile.path = file
dbfile.directory = self
dbfile.save!
end
end
end
end
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser, params = {}
cuser and cuser.admin? and Verification.contain params, [:description, :hidden]
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

64
app/models/forum.rb Normal file
View file

@ -0,0 +1,64 @@
class Forum < ActiveRecord::Base
include Extra
BANS = 8
TRASH = 12
attr_protected :id, :updated_at, :created_at
scope :available_to,
lambda { |user, level| {
:select => "forums.*, groupers.user_id AS access, COUNT(f2.id) AS acl, g2.user_id",
:joins => "LEFT JOIN forumers ON forumers.forum_id = forums.id AND forumers.access = #{level}
LEFT JOIN forumers AS f2 ON forumers.forum_id = forums.id AND f2.access = #{level}
LEFT JOIN groups ON forumers.group_id = groups.id
LEFT JOIN groupers ON groupers.group_id = groups.id AND groupers.user_id = #{user.id}
LEFT JOIN groupers g2 ON g2.group_id = #{Group::ADMINS} AND g2.user_id = #{user.id}",
:group => "forums.id",
:having => ["access IS NOT NULL OR acl = 0 OR g2.user_id IS NOT NULL", level]} }
scope :public,
:select => "forums.*",
:joins => "LEFT JOIN forumers ON forumers.forum_id = forums.id AND forumers.access = #{Forumer::ACCESS_READ}",
:conditions => "forumers.id IS NULL"
scope :of_forum,
lambda { |forum| {:conditions => {"forums.id" => forum.id}} }
scope :ordered, :order => "position"
has_many :topics
has_many :posts, :through => :topics
has_many :forumers
has_many :groups, :through => :forumers
has_one :forumer
belongs_to :category
after_create :update_position
acts_as_readable
def to_s
self.title
end
def update_position
update_attribute :position, self.id
end
def can_show? cuser
if cuser
Forum.available_to(cuser, Forumer::ACCESS_READ).of_forum(self).first
else
Forum.public.of_forum(self).first
end
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

27
app/models/forumer.rb Normal file
View file

@ -0,0 +1,27 @@
class Forumer < ActiveRecord::Base
ACCESS_READ = 0
ACCESS_REPLY = 1
ACCESS_TOPIC = 2
include Extra
scope :access,
lambda { |level| {:conditions => ["access >= ?", level]} }
validates_uniqueness_of :group_id, :scope => [:forum_id, :access]
validates_presence_of [:group_id, :forum_id]
validates_inclusion_of :access, :in => 0..2
belongs_to :forum
belongs_to :group
before_create :init_variables
def init_variables
self.access ||= ACCESS_READ
end
def accesses
{ACCESS_READ => "Read", ACCESS_REPLY => "Reply", ACCESS_TOPIC => "Post a Topic"}
end
end

176
app/models/gather.rb Normal file
View file

@ -0,0 +1,176 @@
class Gather < ActiveRecord::Base
STATE_RUNNING = 0
STATE_VOTING = 3
STATE_PICKING = 1
STATE_FINISHED = 2
NOTIFY = 6
FULL = 12
SERVERS = [3, 5, 23, 21, 22]
attr_accessor :admin
scope :ordered, :order => "id DESC"
scope :basic, :include => [:captain1, :captain2, :map1, :map2, :server]
scope :active,
:conditions => ["gathers.status IN (?, ?, ?) AND gathers.updated_at > ?",
STATE_VOTING, STATE_PICKING, STATE_RUNNING, 12.hours.ago.utc]
belongs_to :server
belongs_to :captain1, :class_name => "Gatherer"
belongs_to :captain2, :class_name => "Gatherer"
belongs_to :map1, :class_name => "GatherMap"
belongs_to :map2, :class_name => "GatherMap"
belongs_to :category
has_many :gatherers
has_many :users, :through => :gatherers
has_many :gatherer_votes, :through => :gatherers, :source => :real_votes
has_many :map_votes, :through => :gather_maps, :source => :real_votes
has_many :gather_maps, :class_name => "GatherMap"
has_many :maps, :through => :gather_maps
has_many :server_votes, :through => :gather_servers, :source => :real_votes
has_many :gather_servers, :class_name => "GatherServer"
has_many :servers, :through => :gather_servers
has_many :shoutmsgs, :as => "shoutable"
has_many :real_votes, :class_name => "Vote", :as => :votable, :dependent => :destroy
before_create :init_variables
after_create :add_maps_and_server
before_save :check_status
before_save :check_captains
def to_s
"Gather_#{self.id}"
end
def self.find_game(name)
Category.where(name: name, domain: Category::DOMAIN_GAMES).first
end
def self.player_count_for_game(name)
game = self.find_game(name)
if game && players = game.gathers.ordered.first.gatherers
players.size
else
0
end
end
def demo_name
Verification.uncrap("gather-#{self.id}")
end
def states
{STATE_RUNNING => "Running", STATE_PICKING => "Picking", STATE_FINISHED => "Finished"}
end
def votes_needed?
5
end
def first
Gather.where(:category_id => category_id).order("id ASC").first
end
def previous_gather
Gather.first(:conditions => ["id < ? AND category_id = ?", self.id, category_id], :order => "id DESC")
end
def next_gather
Gather.first(:conditions => ["id > ? AND category_id = ?", self.id, category_id], :order => "id ASC")
end
def last
Category.find(category_id).gathers.ordered.first
end
def init_variables
self.status = STATE_RUNNING
end
def add_maps_and_server
category.maps.basic.classic.each do |m|
maps << m
end
(category_id == 44 ? category.servers.hlds.active.ordered : category.servers.active.ordered).each do |s|
servers << s
end
end
def check_status
if status_changed? and status == STATE_PICKING and !self.captain1
g = Gather.new
g.category = self.category
g.save
self.captain1 = self.gatherers.most_voted[1]
self.captain2 = self.gatherers.most_voted[0]
if self.gather_maps.count > 1
self.map1 = self.gather_maps.ordered[0]
self.map2 = self.gather_maps.ordered[1]
elsif self.gather_maps.count > 0
self.map1 = self.gather_maps.ordered[0]
end
if self.gather_servers.count > 0
self.server = self.gather_servers.ordered[0].server
end
end
end
def check_captains
if captain1_id_changed? or captain2_id_changed? or admin
self.turn = 1
self.status = STATE_PICKING
gatherers.each do |gatherer|
if gatherer.id == captain1_id
gatherer.update_attributes(:team => 1, :skip_callbacks => true)
elsif gatherer.id == captain2_id
gatherer.update_attributes(:team => 2, :skip_callbacks => true)
else
gatherer.update_attributes(:team => nil, :skip_callbacks => true)
end
end
end
end
def refresh cuser
if status == STATE_RUNNING
gatherers.idle.destroy_all
elsif status == STATE_VOTING and updated_at < 60.seconds.ago and updated_at > 5.days.ago
if status == STATE_VOTING and updated_at < 60.seconds.ago
self.status = STATE_PICKING
save!
end
elsif status == STATE_PICKING
if turn == 1 and gatherers.team(1).count == 2 and gatherers.team(2).count == 1
update_attribute :turn, 2
elsif turn == 2 and gatherers.team(2).count == 3 and gatherers.team(1).count == 2
update_attribute :turn, 1
elsif turn == 1 and gatherers.team(1).count == 4 and gatherers.team(2).count == 3
update_attribute :turn, 2
elsif turn == 2 and gatherers.team(2).count == 5 and gatherers.team(1).count == 4
update_attribute :turn, 1
elsif turn == 1 and gatherers.team(1).count == 6 and gatherers.team(2).count == 5
gatherers.lobby.first.update_attributes(:team => 2, :skip_callbacks => true)
update_attribute :turn, 2
elsif gatherers.team(1).count == 6 and gatherers.team(2).count == 6
update_attribute :status, STATE_FINISHED
end
end
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def self.last(name = "NS2")
if game = self.find_game(name)
game.gathers.ordered.first
end
end
end

17
app/models/gather_map.rb Normal file
View file

@ -0,0 +1,17 @@
class GatherMap < ActiveRecord::Base
scope :ordered, :order => "votes DESC, id DESC"
belongs_to :gather
belongs_to :map
has_many :real_votes, :class_name => "Vote", :as => :votable
before_create :init_variables
def to_s
self.map.to_s
end
def init_variables
self.votes = 0
end
end

View file

@ -0,0 +1,15 @@
class GatherServer < ActiveRecord::Base
scope :ordered, :order => "votes DESC"
belongs_to :gather
belongs_to :server
has_many :real_votes, :class_name => "Vote", :as => :votable
def to_s
self.server.to_s
end
def before_create
self.votes = 0
end
end

153
app/models/gatherer.rb Normal file
View file

@ -0,0 +1,153 @@
class Gatherer < ActiveRecord::Base
IDLE_TIME = 600
EJECT_VOTES = 4
include Extra
attr_protected :id
attr_accessor :confirm, :username
cattr_accessor :skip_callbacks
scope :team,
lambda { |team| {:conditions => {:team => team}} }
scope :of_user,
lambda { |user| {:conditions => {:user_id => user.id}} }
scope :lobby, :conditions => "team IS NULL"
scope :best,
lambda { |gather| {
:select => "u.id, u.username, (COUNT(*) / (SELECT COUNT(*) FROM gatherers g3 WHERE g3.user_id = u.id)) AS skill, g4.id",
:from => "gathers g1",
:joins => "LEFT JOIN gatherers g2 ON g1.captain1_id = g2.id OR g1.captain2_id = g2.id
LEFT JOIN users u ON g2.user_id = u.id
LEFT JOIN gatherers g4 ON u.id = g4.user_id AND g4.gather_id = #{gather.id}",
:group => "u.id",
:having => "g4.id IS NOT NULL",
:order => "skill DESC",
:limit => 15 } }
scope :with_kpd,
:select => "gatherers.*, SUM(kills)/SUM(deaths) as kpd, COUNT(rounders.id) as rounds",
:joins => "LEFT JOIN rounders ON rounders.user_id = gatherers.user_id",
:group => "rounders.user_id",
:order => "kpd DESC"
scope :lobby_team,
lambda { |team| {
:conditions => ["gatherers.team IS NULL OR gatherers.team = ?", team],
:order => "gatherers.team"} }
scope :most_voted, :order => "votes DESC, created_at DESC"
scope :not_user,
lambda { |user| {:conditions => ["user_id != ?", user.id]} }
scope :eject_order, :order => "votes ASC"
scope :ordered,
:joins => "LEFT JOIN gathers ON captain1_id = gatherers.id OR captain2_id = gatherers.id",
:order => "captain1_id, captain2_id, gatherers.id"
scope :idle,
:joins => "LEFT JOIN users ON users.id = gatherers.user_id",
:conditions => ["lastvisit < ?", 30.minutes.ago.utc]
belongs_to :user
belongs_to :gather
has_many :real_votes, :class_name => "Vote", :as => :votable, :dependent => :destroy
validates_uniqueness_of :user_id, :scope => :gather_id
validates_inclusion_of :team, :in => 1..2, :allow_nil => true
validates :confirm, :acceptance => true, :unless => Proc.new {|gatherer| gatherer.user.gatherers.count >= 5}
validate :validate_username
after_create :start_gather, :if => Proc.new {|gatherer| gatherer.gather.gatherers.count == Gather::FULL}
after_create :notify_gatherers, :if => Proc.new {|gatherer| gatherer.gather.gatherers.count == Gather::NOTIFY}
after_update :change_turn, :unless => Proc.new {|gatherer| gatherer.skip_callbacks == true}
after_destroy :cleanup_votes
def to_s
user.to_s
end
def validate_username
if username
if u = User.first(:conditions => {:username => username})
self.user = u
else
errors.add(:username, t(:gatherer_wrong_username))
end
end
end
def start_gather
gather.update_attribute :status, Gather::STATE_VOTING
end
def notify_gatherers
Profile.all(:include => :user, :conditions => "notify_gather = 1").each do |p|
Notifications.gather p.user, gather if p.user
end
end
def change_turn
if team_changed? and team != nil
new_turn = (team == 1 ? 2 : 1)
if team == 2 and [2, 4].include?(gather.gatherers.team(2).count.to_i)
new_turn = 2
elsif team == 1 and [3, 5].include?(gather.gatherers.team(1).count.to_i)
new_turn = 1
end
gather.update_attribute :turn, new_turn
if gather.gatherers.lobby.count == 1
gather.gatherers.lobby.first.update_attribute :team, (self.team == 1 ? 2 : 1)
end
if gather.gatherers.lobby.count == 0
gather.update_attribute :status, Gather::STATE_FINISHED
end
end
end
def cleanup_votes
gather.map_votes.all(:conditions => {:user_id => user_id}).each { |g| g.destroy }
gather.server_votes.all(:conditions => {:user_id => user_id}).each { |g| g.destroy }
gather.gatherer_votes.all(:conditions => {:user_id => user_id}).each { |g| g.destroy }
end
def votes_needed?
return 5
end
def captain?
gather.captain1 == self or gather.captain2 == self
end
def turn?
(gather.captain1 == self and gather.turn == 1) or (gather.captain2 == self and gather.turn == 2)
end
def can_create? cuser, params = {}
# and check_params(params, [:user_id, :gather_id])
cuser \
and user == cuser \
and !cuser.banned?(Ban::TYPE_GATHER) \
and gather.status == Gather::STATE_RUNNING \
and gather.gatherers.count < Gather::FULL \
and !gather.gatherers.of_user(cuser).first
end
def can_update? cuser, params = {}
return false unless cuser
if params.keys.include? "username"
if cuser.admin?
return true
else
return false
end
end
return false unless team.nil? \
and ((gather.captain1.user == cuser and gather.turn == 1) or (gather.captain2.user == cuser and gather.turn == 2))
return false if gather.turn == 1 and gather.gatherers.team(1).count == 2 and gather.gatherers.team(2).count < 3
return false if gather.turn == 2 and gather.gatherers.team(1).count < 4 and gather.gatherers.team(2).count == 3
return false if gather.turn == 1 and gather.gatherers.team(1).count == 4 and gather.gatherers.team(2).count < 5
return false if gather.turn == 2 and gather.gatherers.team(1).count < 6 and gather.gatherers.team(2).count == 5
return false if gather.turn == 1 and gather.gatherers.team(1).count == 6
true
end
def can_destroy? cuser
cuser and ((user == cuser or cuser.admin?) and gather.status == Gather::STATE_RUNNING)
end
end

77
app/models/group.rb Normal file
View file

@ -0,0 +1,77 @@
class Group < ActiveRecord::Base
include Extra
ADMINS = 1
REFEREES = 2
MOVIES = 3
DONORS = 4
MOVIEMAKERS = 5
SHOUTCASTERS = 6
CHAMPIONS = 7
PREDICTORS = 8
STAFF = 10
attr_protected :id, :updated_at, :created_at, :founder_id
validates_length_of :name, :maximum => 20
has_and_belongs_to_many :users
has_many :groupers
has_many :users, :through => :groupers
belongs_to :founder, :class_name => "User"
def to_s
name
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
def self.staff
staff = []
(find(ADMINS).groupers + find(PREDICTORS).groupers + find(SHOUTCASTERS).groupers + find(STAFF).groupers + find(REFEREES).groupers).each do |g|
staff << g unless staff.include? g
end
staff
end
def self.admins
admins = []
(find(ADMINS).groupers).each do |g|
admins << g unless admins.include? g
end
admins
end
def self.referees
referees = []
(find(REFEREES).groupers).each do |g|
referees << g unless referees.include? g
end
referees
end
def self.extras
extras = []
(find(PREDICTORS).groupers + find(STAFF).groupers).each do |g|
extras << g unless extras.include? g
end
extras
end
def self.shoutcasters
shoutcasters = []
(find(SHOUTCASTERS).groupers).each do |g|
shoutcasters << g unless shoutcasters.include? g
end
shoutcasters
end
end

33
app/models/grouper.rb Normal file
View file

@ -0,0 +1,33 @@
class Grouper < ActiveRecord::Base
attr_protected :id, :created_at, :updated_at
attr_accessor :username
belongs_to :group
belongs_to :user
validates_associated :group, :user
validates :group, :user, :presence => true
validates :task, :length => {:maximum => 25}
before_validation :fetch_user, :if => Proc.new {|grouper| grouper.username and !grouper.username.empty?}
def to_s
user.to_s
end
def fetch_user
self.user = User.find_by_username(username)
end
def can_create? cuser
cuser and cuser.admin?
end
def can_update? cuser
cuser and cuser.admin?
end
def can_destroy? cuser
cuser and cuser.admin?
end
end

Some files were not shown because too many files have changed in this diff Show more