├── keys └── README.txt ├── app.js ├── public ├── no.mp3 ├── yes.mp3 ├── no5s.ogg ├── no5s.wav ├── soon.png ├── images │ ├── close.gif │ ├── error.png │ ├── notice.png │ ├── icn_edit.png │ ├── icn_tags.png │ ├── icn_user.png │ ├── sidebar.png │ ├── success.png │ ├── warning.png │ ├── btn_submit.png │ ├── header_bg.png │ ├── icn_audio.png │ ├── icn_folder.png │ ├── icn_logout.png │ ├── icn_photo.png │ ├── icn_profile.png │ ├── icn_search.png │ ├── icn_trash.png │ ├── icn_video.png │ ├── btn_submit_2.png │ ├── btn_view_site.png │ ├── header_shadow.png │ ├── icn_add_user.png │ ├── icn_jump_back.png │ ├── icn_security.png │ ├── icn_settings.png │ ├── post_message.png │ ├── secondary_bar.png │ ├── icn_alert_error.png │ ├── icn_alert_info.png │ ├── icn_categories.png │ ├── icn_edit_article.png │ ├── icn_new_article.png │ ├── icn_view_users.png │ ├── module_footer_bg.png │ ├── sidebar_divider.png │ ├── sidebar_shadow.png │ ├── breadcrumb_divider.png │ ├── icn_alert_success.png │ ├── icn_alert_warning.png │ ├── secondary_bar_shadow.png │ └── table_sorter_header.png ├── img │ ├── tile_bg.jpg │ ├── 230690_700b.jpg │ ├── page_bg_center.jpg │ ├── cropped-proposta02.jpg │ ├── glyphicons-halflings.png │ ├── glyphicons-halflings-white.png │ └── Consuela_Family_Guy_Pink_by_djluckyremix.png ├── stylesheets │ ├── style.css │ ├── login.css │ ├── jquery.countdown.css │ └── jquery.toastmessage.css ├── js │ ├── jquery.equalHeight.js │ ├── hideshow.js │ └── jquery.tablesorter.min.js ├── css │ └── ie.css └── javascripts │ ├── admin.js │ ├── jquery.countdown.css │ ├── themes │ ├── grid.js │ ├── skies.js │ ├── dark-blue.js │ ├── dark-green.js │ └── gray.js │ ├── jquery.scrollTo-1.4.2-min.js │ ├── bootstrap-alert.js │ ├── index.js │ ├── bootstrap-popover.js │ ├── jquery.countdown.js │ ├── bootstrap-tab.js │ ├── bootstrap-transition.js │ ├── bootstrap-collapse.js │ ├── bootstrap-modal.js │ ├── script.js │ ├── jquery.toastmessage.js │ └── bootstrap-tooltip.js ├── views ├── admin │ ├── dashboard_good.jade │ ├── dashboard.jade │ ├── config │ │ ├── comms.jade │ │ └── options.jade │ ├── insert │ │ ├── addCategory.jade │ │ ├── addChallenge.jade │ │ ├── addTeam.jade │ │ └── addProblem.jade │ ├── edit │ │ ├── editChallenge.jade │ │ ├── editTeam.jade │ │ ├── editCategory.jade │ │ └── editProblem.jade │ ├── list │ │ ├── listCategories.jade │ │ ├── listTeams.jade │ │ ├── listProblems.jade │ │ └── listChallenges.jade │ ├── layout.jade │ └── index.jade ├── session │ └── login.jade ├── layout.jade ├── score.jade └── index.jade ├── config.js ├── BD ├── db.js ├── salts.sql └── tournament.sql ├── package.json ├── routes ├── sessions.js ├── score.js ├── index.js └── administration.js └── README.md /keys/README.txt: -------------------------------------------------------------------------------- 1 | Your https keys go here -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/app.js -------------------------------------------------------------------------------- /public/no.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/no.mp3 -------------------------------------------------------------------------------- /public/yes.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/yes.mp3 -------------------------------------------------------------------------------- /public/no5s.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/no5s.ogg -------------------------------------------------------------------------------- /public/no5s.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/no5s.wav -------------------------------------------------------------------------------- /public/soon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/soon.png -------------------------------------------------------------------------------- /public/images/close.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/close.gif -------------------------------------------------------------------------------- /public/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/error.png -------------------------------------------------------------------------------- /public/images/notice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/notice.png -------------------------------------------------------------------------------- /public/img/tile_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/tile_bg.jpg -------------------------------------------------------------------------------- /public/images/icn_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_edit.png -------------------------------------------------------------------------------- /public/images/icn_tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_tags.png -------------------------------------------------------------------------------- /public/images/icn_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_user.png -------------------------------------------------------------------------------- /public/images/sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/sidebar.png -------------------------------------------------------------------------------- /public/images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/success.png -------------------------------------------------------------------------------- /public/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/warning.png -------------------------------------------------------------------------------- /public/img/230690_700b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/230690_700b.jpg -------------------------------------------------------------------------------- /public/images/btn_submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/btn_submit.png -------------------------------------------------------------------------------- /public/images/header_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/header_bg.png -------------------------------------------------------------------------------- /public/images/icn_audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_audio.png -------------------------------------------------------------------------------- /public/images/icn_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_folder.png -------------------------------------------------------------------------------- /public/images/icn_logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_logout.png -------------------------------------------------------------------------------- /public/images/icn_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_photo.png -------------------------------------------------------------------------------- /public/images/icn_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_profile.png -------------------------------------------------------------------------------- /public/images/icn_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_search.png -------------------------------------------------------------------------------- /public/images/icn_trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_trash.png -------------------------------------------------------------------------------- /public/images/icn_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_video.png -------------------------------------------------------------------------------- /public/img/page_bg_center.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/page_bg_center.jpg -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/stylesheets/style.css -------------------------------------------------------------------------------- /public/images/btn_submit_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/btn_submit_2.png -------------------------------------------------------------------------------- /public/images/btn_view_site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/btn_view_site.png -------------------------------------------------------------------------------- /public/images/header_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/header_shadow.png -------------------------------------------------------------------------------- /public/images/icn_add_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_add_user.png -------------------------------------------------------------------------------- /public/images/icn_jump_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_jump_back.png -------------------------------------------------------------------------------- /public/images/icn_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_security.png -------------------------------------------------------------------------------- /public/images/icn_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_settings.png -------------------------------------------------------------------------------- /public/images/post_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/post_message.png -------------------------------------------------------------------------------- /public/images/secondary_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/secondary_bar.png -------------------------------------------------------------------------------- /views/admin/dashboard_good.jade: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/views/admin/dashboard_good.jade -------------------------------------------------------------------------------- /public/images/icn_alert_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_alert_error.png -------------------------------------------------------------------------------- /public/images/icn_alert_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_alert_info.png -------------------------------------------------------------------------------- /public/images/icn_categories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_categories.png -------------------------------------------------------------------------------- /public/images/icn_edit_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_edit_article.png -------------------------------------------------------------------------------- /public/images/icn_new_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_new_article.png -------------------------------------------------------------------------------- /public/images/icn_view_users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_view_users.png -------------------------------------------------------------------------------- /public/images/module_footer_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/module_footer_bg.png -------------------------------------------------------------------------------- /public/images/sidebar_divider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/sidebar_divider.png -------------------------------------------------------------------------------- /public/images/sidebar_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/sidebar_shadow.png -------------------------------------------------------------------------------- /public/img/cropped-proposta02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/cropped-proposta02.jpg -------------------------------------------------------------------------------- /public/images/breadcrumb_divider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/breadcrumb_divider.png -------------------------------------------------------------------------------- /public/images/icn_alert_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_alert_success.png -------------------------------------------------------------------------------- /public/images/icn_alert_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/icn_alert_warning.png -------------------------------------------------------------------------------- /public/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /public/images/secondary_bar_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/secondary_bar_shadow.png -------------------------------------------------------------------------------- /public/images/table_sorter_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/images/table_sorter_header.png -------------------------------------------------------------------------------- /public/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /public/img/Consuela_Family_Guy_Pink_by_djluckyremix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PTCoreSec/CTF-Scoreboard/HEAD/public/img/Consuela_Family_Guy_Pink_by_djluckyremix.png -------------------------------------------------------------------------------- /views/admin/dashboard.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | header 8 | h3 Welcome to Administration. 9 | .module_content 10 | p You can admin and do stuff.. 11 | // 12 | end of styles article 13 | .spacer 14 | -------------------------------------------------------------------------------- /public/stylesheets/login.css: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 300px; 3 | } 4 | 5 | /* The white background content wrapper */ 6 | .container > .content { 7 | padding: 20px; 8 | margin: 0 -20px; 9 | } 10 | 11 | .login-form { 12 | margin-left: 65px; 13 | } 14 | 15 | legend { 16 | margin-right: -50px; 17 | font-weight: bold; 18 | color: #404040; 19 | } -------------------------------------------------------------------------------- /views/session/login.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block scripts 4 | link(rel='stylesheet', href='/stylesheets/login.css') 5 | 6 | block content 7 | div.container 8 | div.content 9 | div.row 10 | div.login-form 11 | form(action='/login', method='POST') 12 | fieldset 13 | div.clearfix 14 | input.text-input(type='text', name='username', id='username', placeholder='User') 15 | div.clearfix 16 | input.text-input(type='password', name='password', id='password', placeholder='Password') 17 | button.btn.btn-primary(type='submit') Login -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | var config = {}; 2 | 3 | config.db = {}; 4 | config.dbHashes = {}; 5 | 6 | // Complete DB 7 | config.db.host = ''; // <-- Insert host 8 | config.db.user = ''; // <-- Insert user 9 | config.db.password = ''; // <-- Insert password 10 | //Don't Change. 11 | config.db.database = 'torneio'; 12 | 13 | // Password Salt DB 14 | config.dbHashes.host = ''; // <-- Insert host 15 | config.dbHashes.user = ''; // <-- Insert user 16 | config.dbHashes.password = ''; // <-- Insert password 17 | //Don't Change. 18 | config.dbHashes.database = 'passsalts'; 19 | 20 | module.exports = config; 21 | -------------------------------------------------------------------------------- /views/admin/config/comms.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form 8 | header 9 | h3 Communications 10 | .module_content 11 | fieldset 12 | label Global Message 13 | input(id='message', type='text', name='message', value='') 14 | .clear 15 | footer 16 | .submit_link 17 | input.alt_btn(id='sendMessage', type='submit', value='Submit') 18 | // 19 | end of post new article 20 | .spacer -------------------------------------------------------------------------------- /BD/db.js: -------------------------------------------------------------------------------- 1 | //Config 2 | var config = require('../config.js'); 3 | var mysql = require('mysql'); 4 | 5 | var connections = {}; 6 | 7 | connections.connection = mysql.createConnection({ 8 | host : config.db.host, 9 | user : config.db.user, 10 | password : config.db.password, 11 | database : config.db.database, 12 | }); 13 | 14 | connections.connectionHashes = mysql.createConnection({ 15 | host : config.dbHashes.host, 16 | user : config.dbHashes.user, 17 | password : config.dbHashes.password, 18 | database : config.dbHashes.database, 19 | }); 20 | 21 | module.exports = connections; 22 | -------------------------------------------------------------------------------- /public/js/jquery.equalHeight.js: -------------------------------------------------------------------------------- 1 | // make sure the $ is pointing to JQuery and not some other library 2 | (function($){ 3 | // add a new method to JQuery 4 | 5 | $.fn.equalHeight = function() { 6 | // find the tallest height in the collection 7 | // that was passed in (.column) 8 | tallest = 0; 9 | this.each(function(){ 10 | thisHeight = $(this).height(); 11 | if( thisHeight > tallest) 12 | tallest = thisHeight; 13 | }); 14 | 15 | // set each items height to use the tallest value found 16 | this.each(function(){ 17 | $(this).height(tallest); 18 | }); 19 | } 20 | })(jQuery); -------------------------------------------------------------------------------- /views/admin/insert/addCategory.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='insertCategory', method='POST') 8 | header 9 | h3 Create New Category 10 | .module_content 11 | fieldset 12 | label Category Name 13 | input(type='text', name='categoryName', value='') 14 | fieldset 15 | label Category Description 16 | textarea(rows='12', name='description') 17 | .clear 18 | footer 19 | .submit_link 20 | input.alt_btn(type='submit', value='Submit') 21 | input(type='submit', value='Reset') 22 | // 23 | end of post new article 24 | .spacer -------------------------------------------------------------------------------- /views/admin/edit/editChallenge.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='insertChallenge', method='POST') 8 | header 9 | h3 Create Challenge 10 | .module_content 11 | fieldset 12 | label Challenge Name 13 | input(type='text', name='challengeName', value='') 14 | fieldset 15 | label Challenge Description 16 | textarea(rows='12', name='description') 17 | .clear 18 | footer 19 | .submit_link 20 | input.alt_btn(type='submit', value='Submit') 21 | input(type='submit', value='Reset') 22 | // 23 | end of post new article 24 | .spacer -------------------------------------------------------------------------------- /views/admin/insert/addChallenge.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='insertChallenge', method='POST') 8 | header 9 | h3 Create Challenge 10 | .module_content 11 | fieldset 12 | label Challenge Name 13 | input(type='text', name='challengeName', value='') 14 | fieldset 15 | label Challenge Description 16 | textarea(rows='12', name='description') 17 | .clear 18 | footer 19 | .submit_link 20 | input.alt_btn(type='submit', value='Submit') 21 | input(type='submit', value='Reset') 22 | // 23 | end of post new article 24 | .spacer -------------------------------------------------------------------------------- /public/css/ie.css: -------------------------------------------------------------------------------- 1 | .quick_search { 2 | text-align: center; 3 | padding: 14px 0 0px 0; 4 | } 5 | 6 | .quick_search input[type=text] { 7 | text-align: left; 8 | height: 22px; 9 | width: 88%; 10 | color: #ccc; 11 | padding-left: 2%; 12 | padding-top: 5px; 13 | background: #fff url(../images/icn_search.png) no-repeat; 14 | background-position: 10px 6px; 15 | } 16 | 17 | .toggleLink { 18 | display: inline; 19 | float: none; 20 | margin-left: 2% 21 | } 22 | 23 | html ul.tabs li.active, html ul.tabs li.active a:hover { 24 | background: #ccc; 25 | } 26 | 27 | input[type=submit].btn_post_message { 28 | background: url(../images/post_message.png) no-repeat; 29 | } 30 | 31 | fieldset input[type=text] { 32 | margin-left: -10px; 33 | } 34 | 35 | 36 | fieldset select { 37 | margin-left: -10px 38 | } 39 | 40 | fieldset textarea { 41 | margin-left: -10px; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /views/admin/edit/editTeam.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='/editTeam/#{team.idteams}', method='POST') 8 | header 9 | h3 Edit Team 10 | .module_content 11 | fieldset 12 | label Team Name 13 | input(type='text', name='teamName', value='#{team.name}') 14 | fieldset 15 | label Team Description 16 | textarea(rows='12', name='description') #{team.description} 17 | .clear 18 | footer 19 | .submit_link 20 | input.alt_btn(type='submit', value='Submit') 21 | input(type='submit', value='Reset') 22 | // 23 | end of post new article 24 | .spacer -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PTCoreSec-Scoreboard-CTF" 3 | , "version": "0.1" 4 | , "author": { 5 | "name": "PTCoreSec" 6 | , "email": "ptcoresec@ptcoresec.eu" 7 | } 8 | , "contributors": [ 9 | { 10 | "name": "Gank" 11 | , "email": "Gank@ptcoresec.eu" 12 | } 13 | ,{ 14 | "name": "Maluko" 15 | , "email": "Maluko@ptcoresec.eu" 16 | } 17 | ,{ 18 | "name": "Balgan" 19 | , "email": "Balgan@ptcoresec.eu" 20 | } 21 | ] 22 | , "dependencies": { 23 | "express": "2.5.8" 24 | , "jade": "0.26.3" 25 | , "connect-redis": "1.4.0" 26 | , "cookie": "0.0.4" 27 | , "mysql": "2.0.0-alpha3" 28 | , "node_hash": "0.2.0" 29 | , "passport": "0.1.10" 30 | , "passport-local": "0.1.3" 31 | , "randomstring": "1.0.1" 32 | , "redis": "0.7.2" 33 | , "socket.io": "0.9.6" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /views/admin/edit/editCategory.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='/editCategory/#{category.idgrupos_problemas}', method='POST') 8 | header 9 | h3 Edit Category 10 | .module_content 11 | fieldset 12 | label Category Name 13 | input(type='text', name='categoryName', value='#{category.name}') 14 | fieldset 15 | label Category Description 16 | textarea(rows='12', name='description') #{category.desc} 17 | .clear 18 | footer 19 | .submit_link 20 | input.alt_btn(type='submit', value='Submit') 21 | input(type='submit', value='Reset') 22 | // 23 | end of post new article 24 | .spacer -------------------------------------------------------------------------------- /views/admin/list/listCategories.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | header 8 | h3.tabs_involved List Categories 9 | .tab_container 10 | #tab1.tab_content 11 | table.tablesorter(cellspacing='0') 12 | thead 13 | tr 14 | th Name 15 | th Description 16 | th Actions 17 | tbody 18 | - each categorie in categories 19 | tr 20 | td #{categorie.name} 21 | td #{categorie.desc} 22 | td 23 | a(href='editCategory/#{categorie.idgrupos_problemas}') 24 | input(type='image', src='images/icn_edit.png', title='Edit') 25 | a(href='deleteCategory/#{categorie.idgrupos_problemas}') 26 | input(type='image', src='images/icn_trash.png', title='Trash') 27 | // 28 | end of #tab1 29 | // 30 | end of .tab_container 31 | // 32 | end of content manager article 33 | .spacer 34 | -------------------------------------------------------------------------------- /views/admin/list/listTeams.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | header 8 | h3.tabs_involved List teams 9 | .tab_container 10 | #tab1.tab_content 11 | table.tablesorter(cellspacing='0') 12 | thead 13 | tr 14 | // 15 | th ID 16 | th Name 17 | th Description 18 | th Actions 19 | tbody 20 | - each team in teams 21 | tr 22 | // 23 | td #{team.idteams} 24 | td #{team.name} 25 | td #{team.description} 26 | td 27 | a(href='editTeam/#{team.idteams}') 28 | input(type='image', src='images/icn_edit.png', title='Edit') 29 | a(href='deleteTeam/#{team.idteams}') 30 | input(type='image', src='images/icn_trash.png', title='Trash') 31 | // 32 | end of #tab1 33 | // 34 | end of .tab_container 35 | // 36 | end of content manager article 37 | .spacer 38 | -------------------------------------------------------------------------------- /public/javascripts/admin.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | 4 | var socket = io.connect(); 5 | var selectedGroup = -1; 6 | var selectedProblem = -1; 7 | 8 | 9 | 10 | $("#reset").click(function() { 11 | console.log('reset'); 12 | socket.emit('reloadConfig'); 13 | }); 14 | 15 | $("#reloadConfig").click(function() { 16 | console.log('reload config'); 17 | socket.emit('reloadConfig'); 18 | }); 19 | 20 | $("#sendMessage").click(function() { 21 | /* stop form from submitting normally */ 22 | event.preventDefault(); 23 | console.log('send message'); 24 | socket.emit('globalMessage', {message: $('#message').val(), sticky: true}); 25 | }); 26 | 27 | $("#category").change(function() { 28 | selectedGroup = $(this).find("option:selected").attr("idgroup"); 29 | selectedProblem = $(this).find("option:selected").attr("idproblem"); 30 | }); 31 | 32 | $("#adminActivateProblem").click(function() { 33 | console.log('send message to activate '+selectedGroup+' - '+selectedProblem); 34 | socket.emit('adminActivateProblem', {group: selectedGroup, problem: selectedProblem}); 35 | }); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /routes/sessions.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | exports.requiresLogin = function(req, res, next){ 4 | if(req.session.passport.user){ 5 | req.session.teamId = req.user[0].idteams; 6 | req.session.user = req.user[0].name; 7 | req.session.administrationLevel = req.user[0].administrationLevel; 8 | next(); 9 | } else { 10 | res.render('session/login', { title: 'PTCoreSec Login' }); 11 | } 12 | } 13 | 14 | exports.requiresAdminLogin = function(req, res, next){ 15 | if(req.session.passport.user && req.user[0].administrationLevel == 2){ 16 | req.session.teamId = req.user[0].idteams; 17 | req.session.user = req.user[0].name; 18 | req.session.administrationLevel = req.user[0].administrationLevel; 19 | next(); 20 | } else { 21 | res.render('session/login', { title: 'PTCoreSec Login' }); 22 | } 23 | } 24 | 25 | exports.login = function(req, res) { 26 | req.session.path = req.route.path; 27 | res.render('session/login', { title: 'PTCoreSec Login' }); 28 | } 29 | 30 | exports.logout = function(req, res) { 31 | req.logOut(); 32 | req.session.administrationLevel = ''; 33 | req.session.user = ''; 34 | req.session.teamId = ''; 35 | res.cookie('teamid', null); 36 | res.redirect('/'); 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /views/admin/list/listProblems.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | header 8 | h3.tabs_involved List Problems 9 | .tab_container 10 | #tab1.tab_content 11 | table.tablesorter(cellspacing='0') 12 | thead 13 | tr 14 | th Group Name 15 | // 16 | th Problem ID 17 | th Description 18 | th Answer 19 | th Points 20 | th Level 21 | th Actions 22 | tbody 23 | - each problem in problems 24 | tr 25 | td #{problem.name} 26 | // 27 | td #{problem.idproblemas} 28 | td #{problem.description} 29 | td #{problem.resposta} 30 | td #{problem.points} 31 | td #{problem.level} 32 | td 33 | a(href='editProblem/#{problem.idproblemas}') 34 | input(type='image', src='images/icn_edit.png', title='Edit') 35 | a(href='deleteProblem/#{problem.idproblemas}') 36 | input(type='image', src='images/icn_trash.png', title='Trash') 37 | // 38 | end of #tab1 39 | // 40 | end of .tab_container 41 | // 42 | end of content manager article 43 | .spacer 44 | -------------------------------------------------------------------------------- /public/js/hideshow.js: -------------------------------------------------------------------------------- 1 | // Andy Langton's show/hide/mini-accordion @ http://andylangton.co.uk/jquery-show-hide 2 | 3 | // this tells jquery to run the function below once the DOM is ready 4 | $(document).ready(function() { 5 | 6 | // choose text for the show/hide link - can contain HTML (e.g. an image) 7 | var showText='Show'; 8 | var hideText='Hide'; 9 | 10 | // initialise the visibility check 11 | var is_visible = false; 12 | 13 | // append show/hide links to the element directly preceding the element with a class of "toggle" 14 | $('.toggle').prev().append(' '+hideText+''); 15 | 16 | // hide all of the elements with a class of 'toggle' 17 | $('.toggle').show(); 18 | 19 | // capture clicks on the toggle links 20 | $('a.toggleLink').click(function() { 21 | 22 | // switch visibility 23 | is_visible = !is_visible; 24 | 25 | // change the link text depending on whether the element is shown or hidden 26 | if ($(this).text()==showText) { 27 | $(this).text(hideText); 28 | $(this).parent().next('.toggle').slideDown('slow'); 29 | } 30 | else { 31 | $(this).text(showText); 32 | $(this).parent().next('.toggle').slideUp('slow'); 33 | } 34 | 35 | // return false so any link destination is not followed 36 | return false; 37 | 38 | }); 39 | }); -------------------------------------------------------------------------------- /views/admin/insert/addTeam.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='insertTeam', method='POST') 8 | header 9 | h3 Create Team 10 | .module_content 11 | fieldset 12 | label Team Name 13 | input(type='text', name='teamName', value='') 14 | fieldset 15 | label User Type 16 | select(name='type') 17 | option(value='0') Normal 18 | option(value='2') Admin 19 | fieldset 20 | label Password 21 | input(type='password', name='teamPassword', value='') 22 | fieldset 23 | label Confirm Password 24 | input(type='password', name='confirmTeamPassord) 25 | fieldset 26 | label Team Description 27 | textarea(rows='12', name='description') 28 | .clear 29 | footer 30 | .submit_link 31 | input.alt_btn(type='submit', value='Submit') 32 | input(type='submit', value='Reset') 33 | // 34 | end of post new article 35 | .spacer -------------------------------------------------------------------------------- /views/admin/edit/editProblem.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='/editProblem/#{problem.idproblemas}', method='POST') 8 | header 9 | h3 Edit Problem 10 | .module_content 11 | fieldset 12 | label Category 13 | select(name='category') 14 | - each categorie in categories 15 | - if (categorie.idgrupos_problemas==problem.idgrupos_problemas) 16 | option(value='#{categorie.idgrupos_problemas}', selected='selected') #{categorie.name} 17 | - else 18 | option(value='#{categorie.idgrupos_problemas}') #{categorie.name} 19 | fieldset 20 | label Answer 21 | input(type='text', name='answer', value='#{problem.resposta}') 22 | fieldset 23 | label Level 24 | input(type='text', name='level', value='#{problem.level}') 25 | fieldset 26 | label Points 27 | input(type='text', name='points', value='#{problem.points}') 28 | fieldset 29 | label Category Description 30 | textarea(rows='12', name='description') #{problem.description} 31 | .clear 32 | footer 33 | .submit_link 34 | input.alt_btn(type='submit', value='Submit') 35 | input(type='submit', value='Reset') 36 | // 37 | end of post new article 38 | .spacer -------------------------------------------------------------------------------- /public/stylesheets/jquery.countdown.css: -------------------------------------------------------------------------------- 1 | .countdownHolder{ 2 | width:97%; 3 | margin:0 auto; 4 | font: 16px/1.5 'Open Sans Condensed',sans-serif; 5 | text-align:right; 6 | letter-spacing:-3px; 7 | } 8 | 9 | .position{ 10 | display: inline-block; 11 | height: 1.6em; 12 | overflow: hidden; 13 | position: relative; 14 | width: 1.05em; 15 | } 16 | 17 | .digit{ 18 | position:absolute; 19 | display:block; 20 | width:1em; 21 | background-color:#444; 22 | border-radius:0.2em; 23 | text-align:center; 24 | color:#fff; 25 | letter-spacing:-1px; 26 | } 27 | 28 | .digit.static{ 29 | box-shadow:1px 1px 1px rgba(4, 4, 4, 0.35); 30 | 31 | background-image: linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 32 | background-image: -o-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 33 | background-image: -moz-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 34 | background-image: -webkit-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 35 | background-image: -ms-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 36 | 37 | background-image: -webkit-gradient( 38 | linear, 39 | left bottom, 40 | left top, 41 | color-stop(0.5, #3A3A3A), 42 | color-stop(0.5, #444444) 43 | ); 44 | } 45 | 46 | /** 47 | * You can use these classes to hide parts 48 | * of the countdown that you don't need. 49 | */ 50 | 51 | .countDays{ /* display:none !important;*/ } 52 | .countDiv0{ /* display:none !important;*/ } 53 | .countHours{} 54 | .countDiv1{} 55 | .countMinutes{} 56 | .countDiv2{} 57 | .countSeconds{} 58 | 59 | 60 | .countDiv{ 61 | display:inline-block; 62 | width:16px; 63 | height:1.6em; 64 | position:relative; 65 | } 66 | 67 | .countDiv:before, 68 | .countDiv:after{ 69 | position:absolute; 70 | width:5px; 71 | height:5px; 72 | background-color:#444; 73 | border-radius:50%; 74 | left:50%; 75 | margin-left:-3px; 76 | top:0.5em; 77 | box-shadow:1px 1px 1px rgba(4, 4, 4, 0.5); 78 | content:''; 79 | } 80 | 81 | .countDiv:after{ 82 | top:0.9em; 83 | } -------------------------------------------------------------------------------- /public/javascripts/jquery.countdown.css: -------------------------------------------------------------------------------- 1 | .countdownHolder{ 2 | width:450px; 3 | margin:0 auto; 4 | font: 40px/1.5 'Open Sans Condensed',sans-serif; 5 | text-align:center; 6 | letter-spacing:-3px; 7 | } 8 | 9 | .position{ 10 | display: inline-block; 11 | height: 1.6em; 12 | overflow: hidden; 13 | position: relative; 14 | width: 1.05em; 15 | } 16 | 17 | .digit{ 18 | position:absolute; 19 | display:block; 20 | width:1em; 21 | background-color:#444; 22 | border-radius:0.2em; 23 | text-align:center; 24 | color:#fff; 25 | letter-spacing:-1px; 26 | } 27 | 28 | .digit.static{ 29 | box-shadow:1px 1px 1px rgba(4, 4, 4, 0.35); 30 | 31 | background-image: linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 32 | background-image: -o-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 33 | background-image: -moz-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 34 | background-image: -webkit-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 35 | background-image: -ms-linear-gradient(bottom, #3A3A3A 50%, #444444 50%); 36 | 37 | background-image: -webkit-gradient( 38 | linear, 39 | left bottom, 40 | left top, 41 | color-stop(0.5, #3A3A3A), 42 | color-stop(0.5, #444444) 43 | ); 44 | } 45 | 46 | /** 47 | * You can use these classes to hide parts 48 | * of the countdown that you don't need. 49 | */ 50 | 51 | .countDays{ /* display:none !important;*/ } 52 | .countDiv0{ /* display:none !important;*/ } 53 | .countHours{} 54 | .countDiv1{} 55 | .countMinutes{} 56 | .countDiv2{} 57 | .countSeconds{} 58 | 59 | 60 | .countDiv{ 61 | display:inline-block; 62 | width:16px; 63 | height:1.6em; 64 | position:relative; 65 | } 66 | 67 | .countDiv:before, 68 | .countDiv:after{ 69 | position:absolute; 70 | width:5px; 71 | height:5px; 72 | background-color:#444; 73 | border-radius:50%; 74 | left:50%; 75 | margin-left:-3px; 76 | top:0.5em; 77 | box-shadow:1px 1px 1px rgba(4, 4, 4, 0.5); 78 | content:''; 79 | } 80 | 81 | .countDiv:after{ 82 | top:0.9em; 83 | } -------------------------------------------------------------------------------- /views/admin/insert/addProblem.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='insertProblem', method='POST') 8 | header 9 | h3 Create New Problem 10 | .module_content 11 | fieldset 12 | label Category 13 | select(name='category') 14 | - each categorie in categories 15 | option(value='#{categorie.idgrupos_problemas}') #{categorie.name} 16 | fieldset 17 | label Answer 18 | input(type='text', name='answer', value='') 19 | fieldset 20 | label Level 21 | select(name='level') 22 | option(value='1') 1 23 | option(value='2') 2 24 | option(value='3') 3 25 | option(value='4') 4 26 | fieldset 27 | label Points 28 | select(name='points') 29 | option(value='100') 100 30 | option(value='200') 200 31 | option(value='300') 300 32 | option(value='400') 400 33 | option(value='500') 500 34 | option(value='600') 600 35 | option(value='700') 700 36 | option(value='800') 800 37 | option(value='900') 900 38 | option(value='1000') 1000 39 | // 40 | input(type='text', name='points', value='') 41 | fieldset 42 | label Category Description 43 | textarea(rows='12', name='description') 44 | .clear 45 | footer 46 | .submit_link 47 | input.alt_btn(type='submit', value='Submit') 48 | input(type='submit', value='Reset') 49 | // 50 | end of post new article 51 | .spacer -------------------------------------------------------------------------------- /public/javascripts/themes/grid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ['#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'], 8 | chart: { 9 | backgroundColor: { 10 | linearGradient: [0, 0, 500, 500], 11 | stops: [ 12 | [0, 'rgb(255, 255, 255)'], 13 | [1, 'rgb(240, 240, 255)'] 14 | ] 15 | }, 16 | borderWidth: 2, 17 | plotBackgroundColor: 'rgba(255, 255, 255, .9)', 18 | plotShadow: true, 19 | plotBorderWidth: 1 20 | }, 21 | title: { 22 | style: { 23 | color: '#000', 24 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 25 | } 26 | }, 27 | subtitle: { 28 | style: { 29 | color: '#666666', 30 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 31 | } 32 | }, 33 | xAxis: { 34 | gridLineWidth: 1, 35 | lineColor: '#000', 36 | tickColor: '#000', 37 | labels: { 38 | style: { 39 | color: '#000', 40 | font: '11px Trebuchet MS, Verdana, sans-serif' 41 | } 42 | }, 43 | title: { 44 | style: { 45 | color: '#333', 46 | fontWeight: 'bold', 47 | fontSize: '12px', 48 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 49 | 50 | } 51 | } 52 | }, 53 | yAxis: { 54 | minorTickInterval: 'auto', 55 | lineColor: '#000', 56 | lineWidth: 1, 57 | tickWidth: 1, 58 | tickColor: '#000', 59 | labels: { 60 | style: { 61 | color: '#000', 62 | font: '11px Trebuchet MS, Verdana, sans-serif' 63 | } 64 | }, 65 | title: { 66 | style: { 67 | color: '#333', 68 | fontWeight: 'bold', 69 | fontSize: '12px', 70 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 71 | } 72 | } 73 | }, 74 | legend: { 75 | itemStyle: { 76 | font: '9pt Trebuchet MS, Verdana, sans-serif', 77 | color: 'black' 78 | 79 | }, 80 | itemHoverStyle: { 81 | color: '#039' 82 | }, 83 | itemHiddenStyle: { 84 | color: 'gray' 85 | } 86 | }, 87 | labels: { 88 | style: { 89 | color: '#99b' 90 | } 91 | } 92 | }; 93 | 94 | // Apply the theme 95 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 96 | -------------------------------------------------------------------------------- /public/javascripts/themes/skies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Skies theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#514F78", "#42A07B", "#9B5E4A", "#72727F", "#1F949A", "#82914E", "#86777F", "#42A07B"], 8 | chart: { 9 | className: 'skies', 10 | borderWidth: 0, 11 | plotShadow: true, 12 | plotBackgroundImage: '/demo/gfx/skies.jpg', 13 | plotBackgroundColor: { 14 | linearGradient: [0, 0, 250, 500], 15 | stops: [ 16 | [0, 'rgba(255, 255, 255, 1)'], 17 | [1, 'rgba(255, 255, 255, 0)'] 18 | ] 19 | }, 20 | plotBorderWidth: 1 21 | }, 22 | title: { 23 | style: { 24 | color: '#3E576F', 25 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 26 | } 27 | }, 28 | subtitle: { 29 | style: { 30 | color: '#6D869F', 31 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 32 | } 33 | }, 34 | xAxis: { 35 | gridLineWidth: 0, 36 | lineColor: '#C0D0E0', 37 | tickColor: '#C0D0E0', 38 | labels: { 39 | style: { 40 | color: '#666', 41 | fontWeight: 'bold' 42 | } 43 | }, 44 | title: { 45 | style: { 46 | color: '#666', 47 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 48 | } 49 | } 50 | }, 51 | yAxis: { 52 | alternateGridColor: 'rgba(255, 255, 255, .5)', 53 | lineColor: '#C0D0E0', 54 | tickColor: '#C0D0E0', 55 | tickWidth: 1, 56 | labels: { 57 | style: { 58 | color: '#666', 59 | fontWeight: 'bold' 60 | } 61 | }, 62 | title: { 63 | style: { 64 | color: '#666', 65 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 66 | } 67 | } 68 | }, 69 | legend: { 70 | itemStyle: { 71 | font: '9pt Trebuchet MS, Verdana, sans-serif', 72 | color: '#3E576F' 73 | }, 74 | itemHoverStyle: { 75 | color: 'black' 76 | }, 77 | itemHiddenStyle: { 78 | color: 'silver' 79 | } 80 | }, 81 | labels: { 82 | style: { 83 | color: '#3E576F' 84 | } 85 | } 86 | }; 87 | 88 | // Apply the theme 89 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 90 | -------------------------------------------------------------------------------- /public/javascripts/jquery.scrollTo-1.4.2-min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery.ScrollTo - Easy element scrolling using jQuery. 3 | * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com 4 | * Dual licensed under MIT and GPL. 5 | * Date: 5/25/2009 6 | * @author Ariel Flesler 7 | * @version 1.4.2 8 | * 9 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html 10 | */ 11 | ;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery); -------------------------------------------------------------------------------- /views/admin/config/options.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | form(action='editOptions', method='POST') 8 | header 9 | h3 General Options 10 | .module_content 11 | fieldset 12 | label Start Date 13 | input(type='text', name='startDate', value='#{config.start_date}') 14 | fieldset 15 | label End Date 16 | input(type='text', name='endDate', value='#{config.end_date}') 17 | fieldset 18 | label Random Problem Interval 19 | input(type='text', name='random_problem_opening_interval', value='#{config.random_problem_opening_interval}') 20 | .clear 21 | footer 22 | .submit_link 23 | input.alt_btn(type='submit', value='Submit') 24 | input.alt_btn(id='reloadConfig', type='submit', value='Reload Options at Server') 25 | article.module.width_full 26 | form(action='resetTeamlogs', method='POST') 27 | header 28 | h3 Reset Stuff 29 | .module_content 30 | fieldset 31 | p This will only reset team logs for now. 32 | .clear 33 | footer 34 | .submit_link 35 | input.alt_btn(id='reset', type='submit', value='Reset') 36 | article.module.width_full 37 | form 38 | header 39 | h3 Open Problem 40 | .module_content 41 | fieldset 42 | p Select problem to Open. 43 | fieldset 44 | label Category 45 | select(id='category', name='category') 46 | option 47 | - each categorie in categories 48 | option(value='#{categorie.idgrupos_problemas}', idproblem='#{categorie.idproblemas}', idgroup='#{categorie.idgrupos_problemas}') #{categorie.name} - #{categorie.points} 49 | .clear 50 | footer 51 | .submit_link 52 | input.alt_btn(id='adminActivateProblem', type='submit', value='Open') 53 | // 54 | end of post new article 55 | .spacer -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

ptcoresec-scoreboard-ctf

2 | ======================== 3 | 4 | A scoreboard used for CTF jeopardy style events 5 | 6 | This is a scoreboard that can be used for jeopardy style tournaments. It was developed by us to be used in our capture the flag security events. 7 | 8 |

INSTALLATION (Version 0.1)

9 | 10 | You need to have NodeJS, Redis and MySQL installed: 11 | 12 | We have tested the scoreboard with Ubuntu 12.04 64 bits, NodeJS versions 0.6.12 and 0.8.1, Redis version 2.2.12 and 2.4.15. 13 | 14 |
15 | 
16 | sudo apt-get update
17 | sudo apt-get install nodejs redis-server mysql-server
18 | 
19 | 20 | 21 | In the folder DB you will find two SQL scripts to import, tournament.sql (Complete database) and salts.sql (Password salts). 22 |
23 | 
24 | cd BD
25 | mysql -u username -p < tournament.sql 
26 | mysql -u username -p < salts.sql 
27 | 
28 | 29 | 30 | Go back to the main folder and configure the config.js file to use your MySQL database, it will look like this, 31 |
32 | 
33 | var config = {};
34 | 
35 | config.db = {};
36 | config.dbHashes = {};
37 | 
38 | // Complete DB
39 | config.db.host = ''; // <-- Insert host
40 | config.db.user = ''; // <-- Insert user
41 | config.db.password = ''; // <-- Insert password
42 | //Don't Change.
43 | config.db.database = 'torneio';
44 | 
45 | // Password Salt DB
46 | config.dbHashes.host = ''; // <-- Insert host
47 | config.dbHashes.user = ''; // <-- Insert user
48 | config.dbHashes.password = ''; // <-- Insert password
49 | //Don't Change.
50 | config.dbHashes.database = 'passsalts';
51 | 
52 | module.exports = config;
53 | 
54 | 55 | 56 | We will now generate keys to be used for HTTPS. 57 |
58 | You can generate the privatekey.pem and certificate.pem files using the following commands: 59 |
60 | 
61 | cd keys
62 | openssl genrsa -out privatekey.pem 1024 
63 | openssl req -new -key privatekey.pem -out certrequest.csr 
64 | openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
65 | 
66 | 67 | 68 | Now you just need to run node. 69 |
70 | 
71 | cd ptcoresec-scoreboard-ctf
72 | node app.js
73 | 
74 | 75 | 76 | 77 | You can then browse to https://server-address:3000 and login with username Administrator and password 123456 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /public/javascripts/bootstrap-alert.js: -------------------------------------------------------------------------------- 1 | /* ========================================================== 2 | * bootstrap-alert.js v2.0.2 3 | * http://twitter.github.com/bootstrap/javascript.html#alerts 4 | * ========================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* ALERT CLASS DEFINITION 26 | * ====================== */ 27 | 28 | var dismiss = '[data-dismiss="alert"]' 29 | , Alert = function ( el ) { 30 | $(el).on('click', dismiss, this.close) 31 | } 32 | 33 | Alert.prototype = { 34 | 35 | constructor: Alert 36 | 37 | , close: function ( e ) { 38 | var $this = $(this) 39 | , selector = $this.attr('data-target') 40 | , $parent 41 | 42 | if (!selector) { 43 | selector = $this.attr('href') 44 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 45 | } 46 | 47 | $parent = $(selector) 48 | $parent.trigger('close') 49 | 50 | e && e.preventDefault() 51 | 52 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) 53 | 54 | $parent 55 | .trigger('close') 56 | .removeClass('in') 57 | 58 | function removeElement() { 59 | $parent 60 | .trigger('closed') 61 | .remove() 62 | } 63 | 64 | $.support.transition && $parent.hasClass('fade') ? 65 | $parent.on($.support.transition.end, removeElement) : 66 | removeElement() 67 | } 68 | 69 | } 70 | 71 | 72 | /* ALERT PLUGIN DEFINITION 73 | * ======================= */ 74 | 75 | $.fn.alert = function ( option ) { 76 | return this.each(function () { 77 | var $this = $(this) 78 | , data = $this.data('alert') 79 | if (!data) $this.data('alert', (data = new Alert(this))) 80 | if (typeof option == 'string') data[option].call($this) 81 | }) 82 | } 83 | 84 | $.fn.alert.Constructor = Alert 85 | 86 | 87 | /* ALERT DATA-API 88 | * ============== */ 89 | 90 | $(function () { 91 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) 92 | }) 93 | 94 | }( window.jQuery ); -------------------------------------------------------------------------------- /public/javascripts/index.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | var socket = io.connect(); 3 | 4 | socket.on('globalMessage', function (data) { 5 | $().toastmessage('showToast', { 6 | text : data.message, 7 | sticky : data.sticky, 8 | type : 'notice' 9 | }); 10 | }); 11 | 12 | socket.on('start', function (data) { 13 | window.location.reload(true); 14 | }); 15 | 16 | socket.on('reconnect', function (data) { 17 | window.location.reload(true); 18 | }); 19 | 20 | socket.on('activateProblem', function (data) { 21 | $("div#"+data.group+''+data.problem).removeClass("pontuacao_closed"); 22 | $('#'+data.group+''+data.problem).addClass("pontuacao_no_answer"); 23 | $().toastmessage('showToast', { 24 | text : 'le wild problem appeared..', 25 | sticky : false, 26 | type : 'notice' 27 | }); 28 | }); 29 | 30 | socket.on('answers', function (data) { 31 | var teamid = data.teamid; 32 | var teamname = data.teamname; 33 | var group = data.group; 34 | var groupname = data.groupname; 35 | var problema = data.problem; 36 | var correct = data.correct; 37 | var sum_of_points = data.sum_of_points; 38 | //var myDate = new Date(); 39 | var myDate = new Date(data.time); 40 | var timezone_delay = -myDate.getTimezoneOffset()*60*1000; 41 | myDate = new Date(myDate.getTime() + timezone_delay); 42 | var found = false; 43 | 44 | //console.log('Recebi pontos da team '+teamid+ ' - '+teamname+' - pontos '+sum_of_points+' data- '+myDate); 45 | 46 | for(var i = 0; chart.series[i]; i++){ 47 | if(chart.series[i].options.id == teamid){ 48 | if (!sum_of_points){ 49 | sum_of_points = 0; 50 | } 51 | found = true; 52 | //console.log(chart.series[i].legendItem); 53 | var el = $(chart.series[i].legendItem.element); 54 | el.text(teamname+' - '+sum_of_points); 55 | var myCss = function(){el.css("font-size","12px")}; 56 | myCss(); 57 | el.hover(myCss).click(myCss); 58 | chart.series[i].addPoint({name: groupname, x: myDate.getTime(), y:parseInt(sum_of_points)}); 59 | } 60 | } 61 | if(correct){ 62 | $("div#"+group+''+problema).removeClass("pontuacao_no_answer"); 63 | $("div#"+group+''+problema).removeClass("pontuacao_selected"); 64 | $("div#"+group+''+problema).addClass("pontuacao_correct"); 65 | } 66 | }); 67 | 68 | socket.on('leader', function (data) { 69 | var leaderBoard = ""; 70 | for(var i = 0; data.teams[i]; i++){ 71 | var name = data.teams[i].name; 72 | var points = 0; 73 | if(data.teams[i].points){ 74 | points = data.teams[i].points; 75 | } 76 | if(data.teams[i].idteams == $('#teamId').attr("team")){ 77 | leaderBoard +='

'+name+' - '+points+'

'; 78 | } 79 | else{ 80 | leaderBoard +='

'+name+' - '+points+'

'; 81 | } 82 | } 83 | 84 | document.getElementById("scores").innerHTML = leaderBoard; 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /public/stylesheets/jquery.toastmessage.css: -------------------------------------------------------------------------------- 1 | .toast-container { 2 | width: 280px; 3 | z-index: 9999; 4 | } 5 | 6 | 7 | * html .toast-container { 8 | position: absolute; 9 | } 10 | 11 | .toast-item { 12 | height: auto; 13 | background: #333; 14 | opacity: 0.9; 15 | -moz-border-radius: 10px; 16 | -webkit-border-radius: 10px; 17 | color: #eee; 18 | padding-top: 20px; 19 | padding-bottom: 20px; 20 | padding-left: 6px; 21 | padding-right: 6px; 22 | font-family: lucida Grande; 23 | font-size: 14px; 24 | border: 2px solid #999; 25 | display: block; 26 | position: relative; 27 | margin: 0 0 12px 0; 28 | } 29 | 30 | .toast-item p { 31 | text-align: left; 32 | margin-left: 50px; 33 | margin-top: 10px; 34 | } 35 | 36 | .toast-item-close { 37 | background:url(../images/close.gif); 38 | width:22px; 39 | height:22px; 40 | position: absolute; 41 | top:7px; 42 | right:7px; 43 | } 44 | 45 | .toast-item-image { 46 | width:32px; 47 | height: 32px; 48 | margin-left: 10px; 49 | margin-top: 10px; 50 | margin-right: 10px; 51 | float:left; 52 | } 53 | 54 | .toast-item-image-notice { 55 | background:url(../images/notice.png); 56 | } 57 | 58 | .toast-item-image-success { 59 | background:url(../images/success.png); 60 | } 61 | 62 | .toast-item-image-warning { 63 | background:url(../images/warning.png); 64 | } 65 | 66 | .toast-item-image-error { 67 | background:url(../images/error.png); 68 | } 69 | 70 | 71 | /** 72 | * toast types 73 | * 74 | * pattern: toast-type-[value] 75 | * where 'value' is the real value of the plugin option 'type' 76 | * 77 | */ 78 | .toast-type-notice { 79 | color: white; 80 | } 81 | 82 | .toast-type-success { 83 | color: white; 84 | } 85 | 86 | .toast-type-warning { 87 | color: white; 88 | border-color: #FCBD57; 89 | } 90 | 91 | .toast-type-error { 92 | color: white; 93 | border-color: #B32B2B; 94 | } 95 | 96 | /** 97 | * positions 98 | * 99 | * pattern: toast-position-[value] 100 | * where 'value' is the real value of the plugin option 'position' 101 | * 102 | */ 103 | .toast-position-top-left { 104 | position: fixed; 105 | left: 20px; 106 | top: 20px; 107 | } 108 | 109 | .toast-position-top-center { 110 | position: fixed; 111 | top: 20px; 112 | left: 50%; 113 | margin-left: -140px; 114 | } 115 | 116 | .toast-position-top-right { 117 | position: fixed; 118 | top: 20px; 119 | right: 20px; 120 | } 121 | 122 | .toast-position-middle-left { 123 | position: fixed; 124 | left: 20px; 125 | top: 50%; 126 | margin-top: -40px; 127 | } 128 | 129 | .toast-position-middle-center { 130 | position: fixed; 131 | left: 50%; 132 | margin-left: -140px; 133 | margin-top: -40px; 134 | top: 50%; 135 | } 136 | 137 | .toast-position-middle-right { 138 | position: fixed; 139 | right: 20px; 140 | margin-left: -140px; 141 | margin-top: -40px; 142 | top: 50%; 143 | } 144 | -------------------------------------------------------------------------------- /public/javascripts/bootstrap-popover.js: -------------------------------------------------------------------------------- 1 | /* =========================================================== 2 | * bootstrap-popover.js v2.0.0 3 | * http://twitter.github.com/bootstrap/javascript.html#popovers 4 | * =========================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * =========================================================== */ 19 | 20 | 21 | !function( $ ) { 22 | 23 | "use strict" 24 | 25 | var Popover = function ( element, options ) { 26 | this.init('popover', element, options) 27 | } 28 | 29 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js 30 | ========================================== */ 31 | 32 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, { 33 | 34 | constructor: Popover 35 | 36 | , setContent: function () { 37 | var $tip = this.tip() 38 | , title = this.getTitle() 39 | , content = this.getContent() 40 | 41 | $tip.find('.popover-title')[ $.type(title) == 'object' ? 'append' : 'html' ](title) 42 | $tip.find('.popover-content > *')[ $.type(content) == 'object' ? 'append' : 'html' ](content) 43 | 44 | $tip.removeClass('fade top bottom left right in') 45 | } 46 | 47 | , hasContent: function () { 48 | return this.getTitle() || this.getContent() 49 | } 50 | 51 | , getContent: function () { 52 | var content 53 | , $e = this.$element 54 | , o = this.options 55 | 56 | content = $e.attr('data-content') 57 | || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) 58 | 59 | content = content.toString().replace(/(^\s*|\s*$)/, "") 60 | 61 | return content 62 | } 63 | 64 | , tip: function() { 65 | if (!this.$tip) { 66 | this.$tip = $(this.options.template) 67 | } 68 | return this.$tip 69 | } 70 | 71 | }) 72 | 73 | 74 | /* POPOVER PLUGIN DEFINITION 75 | * ======================= */ 76 | 77 | $.fn.popover = function ( option ) { 78 | return this.each(function () { 79 | var $this = $(this) 80 | , data = $this.data('popover') 81 | , options = typeof option == 'object' && option 82 | if (!data) $this.data('popover', (data = new Popover(this, options))) 83 | if (typeof option == 'string') data[option]() 84 | }) 85 | } 86 | 87 | $.fn.popover.Constructor = Popover 88 | 89 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, { 90 | placement: 'right' 91 | , content: '' 92 | , template: '

' 93 | }) 94 | 95 | }( window.jQuery ) 96 | -------------------------------------------------------------------------------- /views/admin/layout.jade: -------------------------------------------------------------------------------- 1 | !!! 5 2 | html(lang='en') 3 | head 4 | meta(charset='utf-8') 5 | title PTCoreSec Admin Panel 6 | link(rel='stylesheet', href='/css/layout.css', type='text/css', media='screen') 7 | //if lt IE 9 8 | link(rel='stylesheet', href='/css/ie.css', type='text/css', media='screen') 9 | script(src='http://html5shim.googlecode.com/svn/trunk/html5.js') 10 | script(src='/javascripts/jquery.min.js') 11 | script(src='/javascripts/admin.js') 12 | script(src='/js/hideshow.js', type='text/javascript') 13 | script(src='/js/jquery.tablesorter.min.js', type='text/javascript') 14 | script(type='text/javascript', src='/js/jquery.equalHeight.js') 15 | script(type='text/javascript') 16 | $(document).ready(function() 17 | { 18 | $(".tablesorter").tablesorter(); 19 | } 20 | ); 21 | $(document).ready(function() { 22 | //When page loads... 23 | $(".tab_content").hide(); //Hide all content 24 | $("ul.tabs li:first").addClass("active").show(); //Activate first tab 25 | $(".tab_content:first").show(); //Show first tab content 26 | //On Click Event 27 | $("ul.tabs li").click(function() { 28 | $("ul.tabs li").removeClass("active"); //Remove any "active" class 29 | $(this).addClass("active"); //Add "active" class to selected tab 30 | $(".tab_content").hide(); //Hide all tab content 31 | var activeTab = $(this).find("a").attr("href"); //Find the href attribute value to identify the active tab + content 32 | $(activeTab).fadeIn(); //Fade in the active ID content 33 | return false; 34 | }); 35 | }); 36 | script(type='text/javascript') 37 | $(function(){ 38 | $('.column').equalHeight(); 39 | }); 40 | body 41 | header#header 42 | hgroup 43 | h1.site_title 44 | a(href='/dashboard') PTCoreSec Admin 45 | // 46 | h2.section_title Dashboard 47 | // 48 | end of header bar 49 | section#secondary_bar 50 | .user 51 | p #{session.user} 52 | // 53 | Logout 54 | aside#sidebar.column 55 | h3 Manage Teams 56 | ul.toggle 57 | li.icn_add_user 58 | a(href='/addTeam') Add New Team 59 | li.icn_view_users 60 | a(href='/listTeams') List Teams 61 | // 62 | h3 Manage Challenges 63 | ul.toggle 64 | li.icn_new_article 65 | a(href='/addChallenge') Add New Challenge 66 | li.icn_categories 67 | a(href='/listChallenges') List Challenges 68 | h3 Manage Problems 69 | ul.toggle 70 | li.icn_new_article 71 | a(href='/addCategory') Add New Category 72 | li.icn_categories 73 | a(href='/listCategories') List Categories 74 | li.icn_new_article 75 | a(href='/addProblem') Add New Problem 76 | li.icn_categories 77 | a(href='/listProblems') List Problems 78 | h3 Scoreboard 79 | ul.toggle 80 | li.icn_settings 81 | a(href='/') Go back to Scoreboard 82 | h3 Admin 83 | ul.toggle 84 | li.icn_settings 85 | a(href='/options') Options 86 | li.icn_settings 87 | a(href='/comms') Communications 88 | li.icn_jump_back 89 | a(href='/logout') Logout 90 | //end of sidebar 91 | block content 92 | 93 | footer 94 | script(src='/socket.io/socket.io.js') 95 | block footer -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | !!! 5 2 | html(lang='pt-PT') 3 | head 4 | title PTCoreSec 5 | link(rel='stylesheet', href='/stylesheets/bootstrap.css') 6 | link(rel='stylesheet', href='/stylesheets/style.css') 7 | link(rel='stylesheet', href='/stylesheets/jquery.countdown.css') 8 | link(rel='stylesheet', href='/stylesheets/jquery.toastmessage.css') 9 | script(src='../javascripts/jquery.min.js') 10 | script(src='/socket.io/socket.io.js') 11 | script(src='../javascripts/jquery.countdown.js') 12 | script(src='../javascripts/bootstrap.min.js') 13 | block scripts 14 | body 15 | #main 16 | div.navbar 17 | div.navbar-inner 18 | div.container(style='height:40px;') 19 | a(href='http://www.ptcoresec.eu/').brand PTCoreSec 20 | div.nav-collapse 21 | ul.nav 22 | if(session.path == '/') 23 | li.active 24 | a(href='/') Public 25 | else 26 | li 27 | a(href='/') Public 28 | - if (session.administrationLevel == 2) 29 | ul.nav 30 | if(session.path == '/dashboard') 31 | li.active 32 | a(href='/dashboard') Administration 33 | else 34 | li 35 | a(href='/dashboard') Administration 36 | - else 37 | - if (session.passport.user) 38 | ul.nav 39 | if(session.path == '/score') 40 | li.active 41 | a(href='/score') My Scoreboard 42 | else 43 | li 44 | a(href='/score') My Scoreboard 45 | 46 | 47 | ul.nav.pull-right 48 | - if (session.passport.user) 49 | ul.nav 50 | li 51 | p 52 | div(id='countdown') 53 | p(id='note') 54 | - var userType = '' 55 | - if (session.administrationLevel == 2) 56 | userType = 'Admin ' 57 | - else 58 | userType = 'Team ' 59 | li 60 | p.navbar-text #{userType} 61 | a(href='/', id='teamId', team='#{session.passport.user}') #{session.user} 62 | li.divider-vertical 63 | li 64 | p.navbar-text 65 | a(href='/logout') logout 66 | - else 67 | ul.nav 68 | li 69 | p 70 | div(id='countdown') 71 | p(id='note') 72 | ul.nav.nav-tabs.pull-right.signin-menu 73 | li.dropdown(id='menu1') 74 | a.dropdown-toggle(data-toggle='dropdown', href='#menu1') Login 75 | b.caret 76 | div.dropdown-menu 77 | form(style="margin: 0px;", action='/login', method='POST') 78 | fieldset.textbox(style="padding:10px;") 79 | div.clearfix 80 | input(style="margin-top: 8px", type='text', name='username', id='username', placeholder='Username') 81 | div.clearfix 82 | input(style="margin-top: 8px", type='password', name='password', id='password', placeholder='Password') 83 | button.btn.primary(type='submit') Login 84 | block content 85 | 86 | footer 87 | script(src='../javascripts/jquery.toastmessage.js') 88 | script(src='../javascripts/jquery-ui.min.js') 89 | script(src='../javascripts/bootstrap-collapse.js') 90 | script(src='../javascripts/bootstrap-popover.js') 91 | script(src='../javascripts/bootstrap-tooltip.js') 92 | script(src='../javascripts/bootstrap-modal.js') 93 | script(src='../javascripts/bootstrap-alert.js') 94 | script(src='../javascripts/bootstrap-tab.js') 95 | script(src='../javascripts/bootstrap-transition.js') 96 | block footer -------------------------------------------------------------------------------- /public/javascripts/jquery.countdown.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name jQuery Countdown Plugin 3 | * @author Martin Angelov 4 | * @version 1.0 5 | * @url http://tutorialzine.com/2011/12/countdown-jquery/ 6 | * @license MIT License 7 | */ 8 | 9 | (function($){ 10 | 11 | // Number of seconds in every time division 12 | var days = 24*60*60, 13 | hours = 60*60, 14 | minutes = 60; 15 | 16 | // Creating the plugin 17 | $.fn.countdown = function(prop){ 18 | 19 | var options = $.extend({ 20 | callback : function(){}, 21 | timestamp : 0 22 | },prop); 23 | 24 | var left, d, h, m, s, positions; 25 | 26 | // Initialize the plugin 27 | init(this, options); 28 | 29 | positions = this.find('.position'); 30 | 31 | (function tick(){ 32 | 33 | // Time left 34 | left = Math.floor((options.timestamp - (new Date())) / 1000); 35 | 36 | if(left < 0){ 37 | left = 0; 38 | } 39 | 40 | // Number of days left 41 | d = Math.floor(left / days); 42 | updateDuo(0, 1, d); 43 | left -= d*days; 44 | 45 | // Number of hours left 46 | h = Math.floor(left / hours); 47 | updateDuo(2, 3, h); 48 | left -= h*hours; 49 | 50 | // Number of minutes left 51 | m = Math.floor(left / minutes); 52 | updateDuo(4, 5, m); 53 | left -= m*minutes; 54 | 55 | // Number of seconds left 56 | s = left; 57 | updateDuo(6, 7, s); 58 | 59 | // Calling an optional user supplied callback 60 | options.callback(d, h, m, s); 61 | 62 | // Scheduling another call of this function in 1s 63 | setTimeout(tick, 1000); 64 | })(); 65 | 66 | // This function updates two digit positions at once 67 | function updateDuo(minor,major,value){ 68 | switchDigit(positions.eq(minor),Math.floor(value/10)%10); 69 | switchDigit(positions.eq(major),value%10); 70 | } 71 | 72 | return this; 73 | }; 74 | 75 | 76 | function init(elem, options){ 77 | elem.addClass('countdownHolder'); 78 | 79 | // Creating the markup inside the container 80 | $.each(['Days','Hours','Minutes','Seconds'],function(i){ 81 | $('').html( 82 | '\ 83 | 0\ 84 | \ 85 | \ 86 | 0\ 87 | ' 88 | ).appendTo(elem); 89 | 90 | if(this!="Seconds"){ 91 | elem.append(''); 92 | } 93 | }); 94 | 95 | } 96 | 97 | // Creates an animated transition between the two numbers 98 | function switchDigit(position,number){ 99 | 100 | var digit = position.find('.digit') 101 | 102 | if(digit.is(':animated')){ 103 | return false; 104 | } 105 | 106 | if(position.data('digit') == number){ 107 | // We are already showing this number 108 | return false; 109 | } 110 | 111 | position.data('digit', number); 112 | 113 | var replacement = $('',{ 114 | 'class':'digit', 115 | css:{ 116 | top:'-2.1em', 117 | opacity:0 118 | }, 119 | html:number 120 | }); 121 | 122 | // The .static class is added when the animation 123 | // completes. This makes it run smoother. 124 | 125 | digit 126 | .before(replacement) 127 | .removeClass('static') 128 | .animate({top:'2.5em',opacity:0},'fast',function(){ 129 | digit.remove(); 130 | }) 131 | 132 | replacement 133 | .delay(100) 134 | .animate({top:0,opacity:1},'fast',function(){ 135 | replacement.addClass('static'); 136 | }); 137 | } 138 | })(jQuery); -------------------------------------------------------------------------------- /BD/salts.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS `torneio` /*!40100 DEFAULT CHARACTER SET latin1 */; 2 | USE `torneio`; 3 | -- MySQL dump 10.13 Distrib 5.5.16, for Win32 (x86) 4 | -- 5 | -- Host: zeus.gank.eu Database: torneio 6 | -- ------------------------------------------------------ 7 | -- Server version 5.1.63-0ubuntu0.11.04.1 8 | 9 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 10 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 11 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 12 | /*!40101 SET NAMES utf8 */; 13 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 14 | /*!40103 SET TIME_ZONE='+00:00' */; 15 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 16 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 17 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 18 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 19 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 20 | 21 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 22 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 23 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 24 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 25 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 26 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 27 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 28 | 29 | -- Dump completed on 2012-07-14 19:18:42 30 | CREATE DATABASE IF NOT EXISTS `passsalts` /*!40100 DEFAULT CHARACTER SET latin1 */; 31 | USE `passsalts`; 32 | -- MySQL dump 10.13 Distrib 5.5.16, for Win32 (x86) 33 | -- 34 | -- Host: zeus.gank.eu Database: torneioHashes 35 | -- ------------------------------------------------------ 36 | -- Server version 5.1.63-0ubuntu0.11.04.1 37 | 38 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 39 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 40 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 41 | /*!40101 SET NAMES utf8 */; 42 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 43 | /*!40103 SET TIME_ZONE='+00:00' */; 44 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 45 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 46 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 47 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 48 | 49 | -- 50 | -- Table structure for table `userHashes` 51 | -- 52 | 53 | DROP TABLE IF EXISTS `userHashes`; 54 | /*!40101 SET @saved_cs_client = @@character_set_client */; 55 | /*!40101 SET character_set_client = utf8 */; 56 | CREATE TABLE `userHashes` ( 57 | `idteams` int(11) NOT NULL, 58 | `salt` varchar(100) DEFAULT NULL, 59 | PRIMARY KEY (`idteams`) 60 | ) ENGINE=MyISAM DEFAULT CHARSET=latin1; 61 | /*!40101 SET character_set_client = @saved_cs_client */; 62 | 63 | -- 64 | -- Dumping data for table `userHashes` 65 | -- 66 | 67 | LOCK TABLES `userHashes` WRITE; 68 | /*!40000 ALTER TABLE `userHashes` DISABLE KEYS */; 69 | INSERT INTO `userHashes` VALUES (31,'KMq8MCrVe0lPl01qyv8a'); 70 | /*!40000 ALTER TABLE `userHashes` ENABLE KEYS */; 71 | UNLOCK TABLES; 72 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 73 | 74 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 75 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 76 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 77 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 78 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 79 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 80 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 81 | 82 | -- Dump completed on 2012-07-14 19:18:43 83 | -------------------------------------------------------------------------------- /public/javascripts/bootstrap-tab.js: -------------------------------------------------------------------------------- 1 | /* ======================================================== 2 | * bootstrap-tab.js v2.0.3 3 | * http://twitter.github.com/bootstrap/javascript.html#tabs 4 | * ======================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ======================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | "use strict"; // jshint ;_; 24 | 25 | 26 | /* TAB CLASS DEFINITION 27 | * ==================== */ 28 | 29 | var Tab = function ( element ) { 30 | this.element = $(element) 31 | } 32 | 33 | Tab.prototype = { 34 | 35 | constructor: Tab 36 | 37 | , show: function () { 38 | var $this = this.element 39 | , $ul = $this.closest('ul:not(.dropdown-menu)') 40 | , selector = $this.attr('data-target') 41 | , previous 42 | , $target 43 | , e 44 | 45 | if (!selector) { 46 | selector = $this.attr('href') 47 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 48 | } 49 | 50 | if ( $this.parent('li').hasClass('active') ) return 51 | 52 | previous = $ul.find('.active a').last()[0] 53 | 54 | e = $.Event('show', { 55 | relatedTarget: previous 56 | }) 57 | 58 | $this.trigger(e) 59 | 60 | if (e.isDefaultPrevented()) return 61 | 62 | $target = $(selector) 63 | 64 | this.activate($this.parent('li'), $ul) 65 | this.activate($target, $target.parent(), function () { 66 | $this.trigger({ 67 | type: 'shown' 68 | , relatedTarget: previous 69 | }) 70 | }) 71 | } 72 | 73 | , activate: function ( element, container, callback) { 74 | var $active = container.find('> .active') 75 | , transition = callback 76 | && $.support.transition 77 | && $active.hasClass('fade') 78 | 79 | function next() { 80 | $active 81 | .removeClass('active') 82 | .find('> .dropdown-menu > .active') 83 | .removeClass('active') 84 | 85 | element.addClass('active') 86 | 87 | if (transition) { 88 | element[0].offsetWidth // reflow for transition 89 | element.addClass('in') 90 | } else { 91 | element.removeClass('fade') 92 | } 93 | 94 | if ( element.parent('.dropdown-menu') ) { 95 | element.closest('li.dropdown').addClass('active') 96 | } 97 | 98 | callback && callback() 99 | } 100 | 101 | transition ? 102 | $active.one($.support.transition.end, next) : 103 | next() 104 | 105 | $active.removeClass('in') 106 | } 107 | } 108 | 109 | 110 | /* TAB PLUGIN DEFINITION 111 | * ===================== */ 112 | 113 | $.fn.tab = function ( option ) { 114 | return this.each(function () { 115 | var $this = $(this) 116 | , data = $this.data('tab') 117 | if (!data) $this.data('tab', (data = new Tab(this))) 118 | if (typeof option == 'string') data[option]() 119 | }) 120 | } 121 | 122 | $.fn.tab.Constructor = Tab 123 | 124 | 125 | /* TAB DATA-API 126 | * ============ */ 127 | 128 | $(function () { 129 | $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 130 | e.preventDefault() 131 | $(this).tab('show') 132 | }) 133 | }) 134 | 135 | }(window.jQuery); -------------------------------------------------------------------------------- /public/javascripts/bootstrap-transition.js: -------------------------------------------------------------------------------- 1 | /* =================================================== 2 | * bootstrap-transition.js v2.0.4 3 | * http://twitter.github.com/bootstrap/javascript.html#transitions 4 | * =================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | $(function () { 24 | 25 | "use strict"; // jshint ;_; 26 | 27 | 28 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) 29 | * ======================================================= */ 30 | 31 | $.support.transition = (function () { 32 | 33 | var transitionEnd = (function () { 34 | 35 | var el = document.createElement('bootstrap') 36 | , transEndEventNames = { 37 | 'WebkitTransition' : 'webkitTransitionEnd' 38 | , 'MozTransition' : 'transitionend' 39 | , 'OTransition' : 'oTransitionEnd' 40 | , 'msTransition' : 'MSTransitionEnd' 41 | , 'transition' : 'transitionend' 42 | } 43 | , name 44 | 45 | for (name in transEndEventNames){ 46 | if (el.style[name] !== undefined) { 47 | return transEndEventNames[name] 48 | } 49 | } 50 | 51 | }()) 52 | 53 | return transitionEnd && { 54 | end: transitionEnd 55 | } 56 | 57 | })() 58 | 59 | }) 60 | 61 | }(window.jQuery);/* =================================================== 62 | * bootstrap-transition.js v2.0.4 63 | * http://twitter.github.com/bootstrap/javascript.html#transitions 64 | * =================================================== 65 | * Copyright 2012 Twitter, Inc. 66 | * 67 | * Licensed under the Apache License, Version 2.0 (the "License"); 68 | * you may not use this file except in compliance with the License. 69 | * You may obtain a copy of the License at 70 | * 71 | * http://www.apache.org/licenses/LICENSE-2.0 72 | * 73 | * Unless required by applicable law or agreed to in writing, software 74 | * distributed under the License is distributed on an "AS IS" BASIS, 75 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 76 | * See the License for the specific language governing permissions and 77 | * limitations under the License. 78 | * ========================================================== */ 79 | 80 | 81 | !function ($) { 82 | 83 | $(function () { 84 | 85 | "use strict"; // jshint ;_; 86 | 87 | 88 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) 89 | * ======================================================= */ 90 | 91 | $.support.transition = (function () { 92 | 93 | var transitionEnd = (function () { 94 | 95 | var el = document.createElement('bootstrap') 96 | , transEndEventNames = { 97 | 'WebkitTransition' : 'webkitTransitionEnd' 98 | , 'MozTransition' : 'transitionend' 99 | , 'OTransition' : 'oTransitionEnd' 100 | , 'msTransition' : 'MSTransitionEnd' 101 | , 'transition' : 'transitionend' 102 | } 103 | , name 104 | 105 | for (name in transEndEventNames){ 106 | if (el.style[name] !== undefined) { 107 | return transEndEventNames[name] 108 | } 109 | } 110 | 111 | }()) 112 | 113 | return transitionEnd && { 114 | end: transitionEnd 115 | } 116 | 117 | })() 118 | 119 | }) 120 | 121 | }(window.jQuery); -------------------------------------------------------------------------------- /routes/score.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * GET home page. 4 | */ 5 | 6 | var mysql = require('mysql'); 7 | var util = require('util'); 8 | var connections = require('../BD/db.js'); 9 | 10 | 11 | connections.connection.on('close', function(err) { 12 | if (err) { 13 | // We did not expect this connection to terminate 14 | util.log('ligacao caiu mas vou restabelecer'); 15 | connections.connection = mysql.createConnection(connections.connection.config); 16 | } else { 17 | // We expected this to happen, end() was called. 18 | } 19 | }); 20 | 21 | connections.connection.on('error', function(err) { 22 | util.log(err.code); // 'ER_BAD_DB_ERROR' 23 | util.log('ligacao caiu mas vou restabelecer'); 24 | connections.connection = mysql.createConnection(connections.connection.config); 25 | }); 26 | 27 | exports.answer= function(req, res){ 28 | console.log('Recebi uma answer'); 29 | console.log(req.body); 30 | 31 | } 32 | 33 | 34 | 35 | 36 | exports.score = function(req, res){ 37 | var sqlGrupos = 'SELECT * FROM torneio.grupos_problemas'; 38 | var problems = new Array; 39 | var groups = new Array; 40 | connections.connection.query(sqlGrupos, function(errGroups, rowsGroups, fieldsGroups) { 41 | if(errGroups){ 42 | console.log('err - '+errGroups); 43 | } 44 | if(rowsGroups.length == 0){ 45 | console.log('Nao encontrei nada'); 46 | callbackRender(req, res, {}, {}); 47 | } 48 | else{ 49 | groups = rowsGroups; 50 | var totalGroups = 0; 51 | for(var i = 0; rowsGroups[i];i++){ 52 | var sqlProblemas = 'SELECT p.*, SUM(t.correct) as correct FROM problemas as p LEFT JOIN teams_log as t ' 53 | +' on p.idgrupos_problemas = t.idgrupos_problemas and p.idproblemas = t.idproblemas ' 54 | +' and t.idteams = '+req.session.teamId+' ' 55 | + 'where p.idgrupos_problemas = '+rowsGroups[i].idgrupos_problemas+' ' 56 | +' group by p.idproblemas ORDER by points'; 57 | connections.connection.query(sqlProblemas, function(err, rows, fields) { 58 | if(err){ 59 | console.log('err - '+err); 60 | totalGroups++; 61 | } 62 | else{ 63 | problems[totalGroups] = rows; 64 | totalGroups++; 65 | if(totalGroups == rowsGroups.length){ 66 | callbackRender(req, res, groups, problems) 67 | } 68 | } 69 | }); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | 76 | function callbackRender(req, res, groups, problems){ 77 | var teams = new Array; 78 | var sqlConfig = 'SELECT * from config'; 79 | var sqlTeams = 'SELECT * FROM teams where administrationLevel = 0'; 80 | 81 | var sqlTeamsPoints = 'SELECT t.idteams, name, sum(p.points) as points, (SELECT data from teams_log where teams_log.idteams = t.idteams order by data desc limit 1) as data ' 82 | + ', problems_to_open_level_1, problems_to_open_level_2, problems_to_open_level_3, problems_to_open_level_4 ' 83 | +'FROM teams ' 84 | +'LEFT JOIN teams_log as t on t.idteams = teams.idteams ' 85 | +'LEFT JOIN problemas as p ON t.idgrupos_problemas = p.idgrupos_problemas AND t.idproblemas = p.idproblemas ' 86 | +'where administrationLevel = 0 and (t.correct = 1 OR t.correct IS NULL) ' 87 | +'group by teams.idteams order by points desc, data asc ' 88 | connections.connection.query(sqlTeamsPoints, function(errTeams, rowsTeams, fieldsTeams) { 89 | if(errTeams){ 90 | console.log('errTeams - '+errTeams); 91 | } 92 | connections.connection.query(sqlConfig, function(errConfig, rowsConfig, fieldsConfig) { 93 | req.session.user = req.user[0].name; 94 | res.cookie('teamid', req.session.teamId); 95 | res.cookie('teamname', req.user[0].name); 96 | req.session.path = req.route.path; 97 | req.session.administrationLevel = req.user[0].administrationLevel; 98 | var open; 99 | var now = new Date(); 100 | if(now < rowsConfig[0].start_date){ 101 | open = false; 102 | } 103 | else{ 104 | open = true; 105 | } 106 | var level1 = 0; 107 | var level2 = 0; 108 | var level3 = 0; 109 | for(var i = 0; rowsTeams[i];i++){ 110 | if(rowsTeams[i].idteams == req.session.teamId){ 111 | level1 = rowsTeams[i].problems_to_open_level_1; 112 | level2 = rowsTeams[i].problems_to_open_level_2; 113 | level3 = rowsTeams[i].problems_to_open_level_3; 114 | } 115 | } 116 | res.render('score', { title: 'PTCoreSec Scoreboard', thisteam: req.session.teamId, level1: level1, level2: level2, level3: level3, open: open, config: rowsConfig, groups: groups, problems: problems, teams: rowsTeams}) 117 | }); 118 | }); 119 | } -------------------------------------------------------------------------------- /public/javascripts/bootstrap-collapse.js: -------------------------------------------------------------------------------- 1 | /* ============================================================= 2 | * bootstrap-collapse.js v2.0.0 3 | * http://twitter.github.com/bootstrap/javascript.html#collapse 4 | * ============================================================= 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | !function( $ ){ 21 | 22 | "use strict" 23 | 24 | var Collapse = function ( element, options ) { 25 | this.$element = $(element) 26 | this.options = $.extend({}, $.fn.collapse.defaults, options) 27 | 28 | if (this.options["parent"]) { 29 | this.$parent = $(this.options["parent"]) 30 | } 31 | 32 | this.options.toggle && this.toggle() 33 | } 34 | 35 | Collapse.prototype = { 36 | 37 | constructor: Collapse 38 | 39 | , dimension: function () { 40 | var hasWidth = this.$element.hasClass('width') 41 | return hasWidth ? 'width' : 'height' 42 | } 43 | 44 | , show: function () { 45 | var dimension = this.dimension() 46 | , scroll = $.camelCase(['scroll', dimension].join('-')) 47 | , actives = this.$parent && this.$parent.find('.in') 48 | , hasData 49 | 50 | if (actives && actives.length) { 51 | hasData = actives.data('collapse') 52 | actives.collapse('hide') 53 | hasData || actives.data('collapse', null) 54 | } 55 | 56 | this.$element[dimension](0) 57 | this.transition('addClass', 'show', 'shown') 58 | this.$element[dimension](this.$element[0][scroll]) 59 | 60 | } 61 | 62 | , hide: function () { 63 | var dimension = this.dimension() 64 | this.reset(this.$element[dimension]()) 65 | this.transition('removeClass', 'hide', 'hidden') 66 | this.$element[dimension](0) 67 | } 68 | 69 | , reset: function ( size ) { 70 | var dimension = this.dimension() 71 | 72 | this.$element 73 | .removeClass('collapse') 74 | [dimension](size || 'auto') 75 | [0].offsetWidth 76 | 77 | this.$element.addClass('collapse') 78 | } 79 | 80 | , transition: function ( method, startEvent, completeEvent ) { 81 | var that = this 82 | , complete = function () { 83 | if (startEvent == 'show') that.reset() 84 | that.$element.trigger(completeEvent) 85 | } 86 | 87 | this.$element 88 | .trigger(startEvent) 89 | [method]('in') 90 | 91 | $.support.transition && this.$element.hasClass('collapse') ? 92 | this.$element.one($.support.transition.end, complete) : 93 | complete() 94 | } 95 | 96 | , toggle: function () { 97 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 98 | } 99 | 100 | } 101 | 102 | /* COLLAPSIBLE PLUGIN DEFINITION 103 | * ============================== */ 104 | 105 | $.fn.collapse = function ( option ) { 106 | return this.each(function () { 107 | var $this = $(this) 108 | , data = $this.data('collapse') 109 | , options = typeof option == 'object' && option 110 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) 111 | if (typeof option == 'string') data[option]() 112 | }) 113 | } 114 | 115 | $.fn.collapse.defaults = { 116 | toggle: true 117 | } 118 | 119 | $.fn.collapse.Constructor = Collapse 120 | 121 | 122 | /* COLLAPSIBLE DATA-API 123 | * ==================== */ 124 | 125 | $(function () { 126 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { 127 | var $this = $(this), href 128 | , target = $this.attr('data-target') 129 | || e.preventDefault() 130 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 131 | , option = $(target).data('collapse') ? 'toggle' : $this.data() 132 | $(target).collapse(option) 133 | }) 134 | }) 135 | 136 | }( window.jQuery ) 137 | -------------------------------------------------------------------------------- /views/admin/list/listChallenges.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | section#main.column 5 | .clear 6 | article.module.width_full 7 | header 8 | h3.tabs_involved Content Manager 9 | ul.tabs 10 | li 11 | a(href='#tab1') Posts 12 | li 13 | a(href='#tab2') Comments 14 | .tab_container 15 | #tab1.tab_content 16 | table.tablesorter(cellspacing='0') 17 | thead 18 | tr 19 | th 20 | th Entry Name 21 | th Category 22 | th Created On 23 | th Actions 24 | tbody 25 | tr 26 | td 27 | input(type='checkbox') 28 | td Lorem Ipsum Dolor Sit Amet 29 | td Articles 30 | td 5th April 2011 31 | td 32 | input(type='image', src='images/icn_edit.png', title='Edit') 33 | input(type='image', src='images/icn_trash.png', title='Trash') 34 | tr 35 | td 36 | input(type='checkbox') 37 | td Ipsum Lorem Dolor Sit Amet 38 | td Freebies 39 | td 6th April 2011 40 | td 41 | input(type='image', src='images/icn_edit.png', title='Edit') 42 | input(type='image', src='images/icn_trash.png', title='Trash') 43 | tr 44 | td 45 | input(type='checkbox') 46 | td Sit Amet Dolor Ipsum 47 | td Tutorials 48 | td 10th April 2011 49 | td 50 | input(type='image', src='images/icn_edit.png', title='Edit') 51 | input(type='image', src='images/icn_trash.png', title='Trash') 52 | tr 53 | td 54 | input(type='checkbox') 55 | td Dolor Lorem Amet 56 | td Articles 57 | td 16th April 2011 58 | td 59 | input(type='image', src='images/icn_edit.png', title='Edit') 60 | input(type='image', src='images/icn_trash.png', title='Trash') 61 | tr 62 | td 63 | input(type='checkbox') 64 | td Dolor Lorem Amet 65 | td Articles 66 | td 16th April 2011 67 | td 68 | input(type='image', src='images/icn_edit.png', title='Edit') 69 | input(type='image', src='images/icn_trash.png', title='Trash') 70 | // 71 | end of #tab1 72 | #tab2.tab_content 73 | table.tablesorter(cellspacing='0') 74 | thead 75 | tr 76 | th 77 | th Comment 78 | th Posted by 79 | th Posted On 80 | th Actions 81 | tbody 82 | tr 83 | td 84 | input(type='checkbox') 85 | td Lorem Ipsum Dolor Sit Amet 86 | td Mark Corrigan 87 | td 5th April 2011 88 | td 89 | input(type='image', src='images/icn_edit.png', title='Edit') 90 | input(type='image', src='images/icn_trash.png', title='Trash') 91 | tr 92 | td 93 | input(type='checkbox') 94 | td Ipsum Lorem Dolor Sit Amet 95 | td Jeremy Usbourne 96 | td 6th April 2011 97 | td 98 | input(type='image', src='images/icn_edit.png', title='Edit') 99 | input(type='image', src='images/icn_trash.png', title='Trash') 100 | tr 101 | td 102 | input(type='checkbox') 103 | td Sit Amet Dolor Ipsum 104 | td Super Hans 105 | td 10th April 2011 106 | td 107 | input(type='image', src='images/icn_edit.png', title='Edit') 108 | input(type='image', src='images/icn_trash.png', title='Trash') 109 | tr 110 | td 111 | input(type='checkbox') 112 | td Dolor Lorem Amet 113 | td Alan Johnson 114 | td 16th April 2011 115 | td 116 | input(type='image', src='images/icn_edit.png', title='Edit') 117 | input(type='image', src='images/icn_trash.png', title='Trash') 118 | tr 119 | td 120 | input(type='checkbox') 121 | td Dolor Lorem Amet 122 | td Dobby 123 | td 16th April 2011 124 | td 125 | input(type='image', src='images/icn_edit.png', title='Edit') 126 | input(type='image', src='images/icn_trash.png', title='Trash') 127 | // 128 | end of #tab2 129 | // 130 | end of .tab_container 131 | // 132 | end of content manager article 133 | .spacer 134 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * GET home page. 4 | */ 5 | 6 | var mysql = require('mysql'); 7 | var util = require('util'); 8 | var connections = require('../BD/db.js'); 9 | 10 | 11 | connections.connection.on('close', function(err) { 12 | if (err) { 13 | // We did not expect this connection to terminate 14 | util.log('ligacao caiu mas vou restabelecer'); 15 | connections.connection = mysql.createConnection(connections.connection.config); 16 | } else { 17 | // We expected this to happen, end() was called. 18 | } 19 | }); 20 | 21 | connections.connection.on('error', function(err) { 22 | util.log(err.code); // 'ER_BAD_DB_ERROR' 23 | util.log('ligacao caiu mas vou restabelecer'); 24 | connections.connection = mysql.createConnection(connections.connection.config); 25 | }); 26 | 27 | 28 | exports.index = function(req, res){ 29 | var sqlGrupos = 'SELECT * FROM torneio.grupos_problemas'; 30 | var problems = new Array; 31 | var groups = new Array; 32 | connections.connection.query(sqlGrupos, function(errGroups, rowsGroups, fieldsGroups) { 33 | if(errGroups){ 34 | console.log('err - '+errGroups); 35 | } 36 | if(rowsGroups.length == 0){ 37 | callbackRender(req, res, {}, {}) 38 | } 39 | else{ 40 | groups = rowsGroups; 41 | var totalGroups = 0; 42 | for(var i = 0; rowsGroups[i];i++){ 43 | var sqlProblemas = 'SELECT p.*, SUM(t.correct) as correct FROM problemas as p LEFT JOIN teams_log as t ' 44 | +' on p.idgrupos_problemas = t.idgrupos_problemas and p.idproblemas = t.idproblemas ' 45 | + 'where p.idgrupos_problemas = '+rowsGroups[i].idgrupos_problemas+' ' 46 | +' group by p.idproblemas ORDER by points'; 47 | connections.connection.query(sqlProblemas, function(err, rows, fields) { 48 | if(err){ 49 | console.log('err - '+err); 50 | totalGroups++; 51 | } 52 | else{ 53 | problems[totalGroups] = rows; 54 | totalGroups++; 55 | if(totalGroups == rowsGroups.length){ 56 | callbackRender(req, res, groups, problems) 57 | } 58 | } 59 | }); 60 | } 61 | } 62 | }); 63 | }; 64 | 65 | function callbackRender(req, res, groups, problems){ 66 | var teams = new Array; 67 | var sqlTeams = 'SELECT * FROM teams where administrationLevel = 0'; 68 | var sqlConfig = 'SELECT * from config'; 69 | var sqlTeamsPoints = 'SELECT t.idteams, name, sum(p.points) as points, (SELECT data from teams_log where teams_log.idteams = t.idteams order by data desc limit 1) as data ' 70 | + ', problems_to_open_level_1, problems_to_open_level_2, problems_to_open_level_3, problems_to_open_level_4 ' 71 | +'FROM teams ' 72 | +'LEFT JOIN teams_log as t on t.idteams = teams.idteams ' 73 | +'LEFT JOIN problemas as p ON t.idgrupos_problemas = p.idgrupos_problemas AND t.idproblemas = p.idproblemas ' 74 | +'where administrationLevel = 0 and (t.correct = 1 OR t.correct IS NULL) ' 75 | +'group by teams.idteams order by points desc, data asc ' 76 | var sqlTeamsPointsLogs = 'SELECT t.idteams, DATE_FORMAT(t.data, \'%Y-%m-%d %H:%i:%s\') as data, t.sum_of_points, gp.name from teams_log as t, teams, grupos_problemas as gp where t.idteams = teams.idteams and t.idgrupos_problemas = gp.idgrupos_problemas order by data'; 77 | connections.connection.query(sqlTeamsPoints, function(errTeams, rowsTeams, fieldsTeams) { 78 | connections.connection.query(sqlTeamsPointsLogs, function(err, rowsLogs, fieldsLogs) { 79 | if(req.user){ 80 | if(req.user[0]){ 81 | req.session.user = req.user[0].name; 82 | res.cookie('teamid', req.session.teamId); 83 | req.session.administrationLevel = req.user[0].administrationLevel; 84 | } 85 | } 86 | req.session.path = req.route.path; 87 | var processLogs = []; 88 | var teamsDataAll = []; 89 | for(var i = 0; rowsLogs[i];i++){ 90 | if(teamsDataAll[rowsLogs[i].idteams]){ 91 | if(rowsLogs[i].sum_of_points){ 92 | var myDate = new Date(rowsLogs[i].data); 93 | var timezone_delay = -myDate.getTimezoneOffset()*60*1000; 94 | myDate = new Date(myDate.getTime() + timezone_delay); 95 | teamsDataAll[rowsLogs[i].idteams].push({name: rowsLogs[i].name, x:(myDate).getTime(), y:rowsLogs[i].sum_of_points}); 96 | } 97 | } 98 | else{ 99 | teamsDataAll[rowsLogs[i].idteams] = new Array(); 100 | var myDate = new Date(rowsLogs[i].data); 101 | var timezone_delay = -myDate.getTimezoneOffset()*60*1000; 102 | myDate = new Date(myDate.getTime() + timezone_delay); 103 | 104 | teamsDataAll[rowsLogs[i].idteams].push({name: rowsLogs[i].name, x: (myDate).getTime(), y:rowsLogs[i].sum_of_points}); 105 | } 106 | } 107 | 108 | 109 | connections.connection.query(sqlTeams, function(errTeams, rows, fields) { 110 | 111 | for(var i = 0; rows[i];i++){ 112 | var teamid = rows[i].idteams; 113 | if(teamsDataAll[rows[i].idteams]){ 114 | processLogs.push({name: rows[i].name, id: teamid, data: teamsDataAll[rows[i].idteams]}); 115 | } 116 | else { 117 | if(rows[i].administrationLevel == 0){ 118 | processLogs.push({name: rows[i].name, id: teamid, data: []}); 119 | } 120 | } 121 | } 122 | 123 | connections.connection.query(sqlConfig, function(errConfig, rowsConfig, fieldsConfig) { 124 | res.render('index', { title: 'PTCoreSec Scoreboard', config: rowsConfig, groups: groups, problems: problems, teams: rowsTeams, logs: processLogs}); 125 | }); 126 | }); 127 | 128 | }); 129 | }); 130 | } -------------------------------------------------------------------------------- /views/score.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block scripts 4 | script(src='../javascripts/jquery.scrollTo-1.4.2-min.js') 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | 7 | script(type='text/javascript') 8 | $(document).ready(function() { 9 | var level1 = #{level1}; 10 | var level2 = #{level2}; 11 | var level3 = #{level3}; 12 | 13 | 14 | $('div.exampleborderradiusa').each(function(index) { 15 | var level = jQuery(this).attr("level"); 16 | if((level == 2 && level1>0) || (level == 3 && level2>0) || (level3>0 && level == 4)){ 17 | if(jQuery(this).hasClass('pontuacao_closed')){ 18 | jQuery(this).removeClass("pontuacao_closed"); 19 | jQuery(this).addClass("pontuacao_can_open"); 20 | } 21 | } 22 | }); 23 | 24 | 25 | 26 | var start = new Date('#{config[0].start_date}'); 27 | var end = new Date('#{config[0].end_date}'); 28 | var note = $('#note'); 29 | ts = start; 30 | newYear = true; 31 | if(note){ 32 | if((new Date()) > ts){ 33 | // The new year is here! Count towards something else. 34 | // Notice the *1000 at the end - time must be in milliseconds 35 | ts = end; 36 | newYear = false; 37 | } 38 | 39 | $('#countdown').countdown({ 40 | timestamp : ts, 41 | callback : function(days, hours, minutes, seconds){ 42 | var message = ""; 43 | note.html(message); 44 | } 45 | }); 46 | } 47 | }); 48 | script(src='../javascripts/script.js') 49 | block content 50 | div(id='page') 51 | - if(!open) 52 | div(style='margin:0 auto;text-align:center;') 53 | // 54 | h3 Soon.. 55 | img(src='soon.png', alt='Soon, height='400', width='400') 56 | - else 57 | div(id='conteudoGeral') 58 | div(id='conteudo') 59 | table 60 | tr 61 | td 62 | div(id='left') 63 | - var largura = groups.length*173 64 | - var numProblems = 0 65 | - each problemsFromGroup in problems 66 | -if(problemsFromGroup.length>numProblems) 67 | - numProblems = problemsFromGroup.length 68 | - var altura = (numProblems+1)*80 69 | div.main_pontuacao(id='main_pontuacao', style='width: #{largura}px;height: #{altura}px;') 70 | - each group, i in groups 71 | div.group 72 | div.exampleborderradiusatop.pontuacao_header 73 | span.exampleborderradiusatop(style='font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;') #{group.name} 74 | - var problemsFromGroup = problems[i] 75 | - each problem in problemsFromGroup 76 | - if(problem.correct > 0) 77 | div.exampleborderradiusa.pontuacao_correct(group=problem.idgrupos_problemas, problem=problem.idproblemas, id=problem.idgrupos_problemas+''+problem.idproblemas, level=problem.level) 78 | span.exampleborderradiusa #{problem.points} 79 | - else 80 | - if(problem.open) 81 | div.exampleborderradiusa.pontuacao_no_answer(group=problem.idgrupos_problemas, problem=problem.idproblemas, id=problem.idgrupos_problemas+''+problem.idproblemas, level=problem.level) 82 | span.exampleborderradiusa #{problem.points} 83 | - else 84 | div.exampleborderradiusa.pontuacao_closed(group=problem.idgrupos_problemas, problem=problem.idproblemas, id=problem.idgrupos_problemas+''+problem.idproblemas, level=problem.level) 85 | span.exampleborderradiusa #{problem.points} 86 | div(id='legenda') 87 | div.legenda.pontuacao_correct 88 | div.legenda_text Answered 89 | div.legenda.pontuacao_no_answer 90 | div.legenda_text Open 91 | div.legenda.pontuacao_closed 92 | div.legenda_text Closed 93 | div.legenda.pontuacao_can_open 94 | div.legenda_text You can open me 95 | // 96 | div.legenda_text(style='text-align:right;width:460px;color:red;') U can open X problems 97 | td 98 | div(id='right') 99 | div(id='answer') 100 | h3(style='font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;margin-left:5px;') Problem 101 | div(style='height:240px;') 102 | label(id='problem_description', style='color:black;') 103 | div(style='height:30px;') 104 | form.form-inline 105 | input.span2(id='answerInput', text='text', style='display: none;') 106 | input.button(id='submitAnswer', type='submit', value='Answer', sytle='width:50px;display: none;').btn.btn-primary 107 | span.help-inline(id='feedback') 108 | div(id='leaderboard') 109 | h3(style='font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;margin-left:5px;') Leaderboard 110 | div(id='scores') 111 | table 112 | -each team in teams 113 | -if(team) 114 | -var points = 0 115 | -if(team.points) 116 | - points = team.points 117 | -if(team.idteams == session.passport.user) 118 | tr 119 | td 120 | p(style='color: white;') #{team.name} 121 | td 122 | p(style='color: white;') - 123 | td(style='text-align:right;') 124 | p(style='color: white;') #{points} 125 | -else 126 | tr 127 | td 128 | p #{team.name} 129 | td 130 | p - 131 | td(style='text-align:right;') 132 | p #{points} 133 | -------------------------------------------------------------------------------- /public/javascripts/themes/dark-blue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark blue theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: [0, 0, 250, 500], 12 | stops: [ 13 | [0, 'rgb(48, 48, 96)'], 14 | [1, 'rgb(0, 0, 0)'] 15 | ] 16 | }, 17 | borderColor: '#000000', 18 | borderWidth: 2, 19 | className: 'dark-container', 20 | plotBackgroundColor: 'rgba(255, 255, 255, .1)', 21 | plotBorderColor: '#CCCCCC', 22 | plotBorderWidth: 1 23 | }, 24 | title: { 25 | style: { 26 | color: '#C0C0C0', 27 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 28 | } 29 | }, 30 | subtitle: { 31 | style: { 32 | color: '#666666', 33 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 34 | } 35 | }, 36 | xAxis: { 37 | gridLineColor: '#333333', 38 | gridLineWidth: 1, 39 | labels: { 40 | style: { 41 | color: '#A0A0A0' 42 | } 43 | }, 44 | lineColor: '#A0A0A0', 45 | tickColor: '#A0A0A0', 46 | title: { 47 | style: { 48 | color: '#CCC', 49 | fontWeight: 'bold', 50 | fontSize: '12px', 51 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 52 | 53 | } 54 | } 55 | }, 56 | yAxis: { 57 | gridLineColor: '#333333', 58 | labels: { 59 | style: { 60 | color: '#A0A0A0' 61 | } 62 | }, 63 | lineColor: '#A0A0A0', 64 | minorTickInterval: null, 65 | tickColor: '#A0A0A0', 66 | tickWidth: 1, 67 | title: { 68 | style: { 69 | color: '#CCC', 70 | fontWeight: 'bold', 71 | fontSize: '12px', 72 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.75)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | toolbar: { 83 | itemStyle: { 84 | color: 'silver' 85 | } 86 | }, 87 | plotOptions: { 88 | line: { 89 | dataLabels: { 90 | color: '#CCC' 91 | }, 92 | marker: { 93 | lineColor: '#333' 94 | } 95 | }, 96 | spline: { 97 | marker: { 98 | lineColor: '#333' 99 | } 100 | }, 101 | scatter: { 102 | marker: { 103 | lineColor: '#333' 104 | } 105 | }, 106 | candlestick: { 107 | lineColor: 'white' 108 | } 109 | }, 110 | legend: { 111 | itemStyle: { 112 | font: '9pt Trebuchet MS, Verdana, sans-serif', 113 | color: '#A0A0A0' 114 | }, 115 | itemHoverStyle: { 116 | color: '#FFF' 117 | }, 118 | itemHiddenStyle: { 119 | color: '#444' 120 | } 121 | }, 122 | credits: { 123 | style: { 124 | color: '#666' 125 | } 126 | }, 127 | labels: { 128 | style: { 129 | color: '#CCC' 130 | } 131 | }, 132 | 133 | navigation: { 134 | buttonOptions: { 135 | backgroundColor: { 136 | linearGradient: [0, 0, 0, 20], 137 | stops: [ 138 | [0.4, '#606060'], 139 | [0.6, '#333333'] 140 | ] 141 | }, 142 | borderColor: '#000000', 143 | symbolStroke: '#C0C0C0', 144 | hoverSymbolStroke: '#FFFFFF' 145 | } 146 | }, 147 | 148 | exporting: { 149 | buttons: { 150 | exportButton: { 151 | symbolFill: '#55BE3B' 152 | }, 153 | printButton: { 154 | symbolFill: '#7797BE' 155 | } 156 | } 157 | }, 158 | 159 | // scroll charts 160 | rangeSelector: { 161 | buttonTheme: { 162 | fill: { 163 | linearGradient: [0, 0, 0, 20], 164 | stops: [ 165 | [0.4, '#888'], 166 | [0.6, '#555'] 167 | ] 168 | }, 169 | stroke: '#000000', 170 | style: { 171 | color: '#CCC', 172 | fontWeight: 'bold' 173 | }, 174 | states: { 175 | hover: { 176 | fill: { 177 | linearGradient: [0, 0, 0, 20], 178 | stops: [ 179 | [0.4, '#BBB'], 180 | [0.6, '#888'] 181 | ] 182 | }, 183 | stroke: '#000000', 184 | style: { 185 | color: 'white' 186 | } 187 | }, 188 | select: { 189 | fill: { 190 | linearGradient: [0, 0, 0, 20], 191 | stops: [ 192 | [0.1, '#000'], 193 | [0.3, '#333'] 194 | ] 195 | }, 196 | stroke: '#000000', 197 | style: { 198 | color: 'yellow' 199 | } 200 | } 201 | } 202 | }, 203 | inputStyle: { 204 | backgroundColor: '#333', 205 | color: 'silver' 206 | }, 207 | labelStyle: { 208 | color: 'silver' 209 | } 210 | }, 211 | 212 | navigator: { 213 | handles: { 214 | backgroundColor: '#666', 215 | borderColor: '#AAA' 216 | }, 217 | outlineColor: '#CCC', 218 | maskFill: 'rgba(16, 16, 16, 0.5)', 219 | series: { 220 | color: '#7798BF', 221 | lineColor: '#A6C7ED' 222 | } 223 | }, 224 | 225 | scrollbar: { 226 | barBackgroundColor: { 227 | linearGradient: [0, 0, 0, 20], 228 | stops: [ 229 | [0.4, '#888'], 230 | [0.6, '#555'] 231 | ] 232 | }, 233 | barBorderColor: '#CCC', 234 | buttonArrowColor: '#CCC', 235 | buttonBackgroundColor: { 236 | linearGradient: [0, 0, 0, 20], 237 | stops: [ 238 | [0.4, '#888'], 239 | [0.6, '#555'] 240 | ] 241 | }, 242 | buttonBorderColor: '#CCC', 243 | rifleColor: '#FFF', 244 | trackBackgroundColor: { 245 | linearGradient: [0, 0, 0, 10], 246 | stops: [ 247 | [0, '#000'], 248 | [1, '#333'] 249 | ] 250 | }, 251 | trackBorderColor: '#666' 252 | }, 253 | 254 | // special colors for some of the 255 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 256 | legendBackgroundColorSolid: 'rgb(35, 35, 70)', 257 | dataLabelsColor: '#444', 258 | textColor: '#C0C0C0', 259 | maskColor: 'rgba(255,255,255,0.3)' 260 | }; 261 | 262 | // Apply the theme 263 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 264 | -------------------------------------------------------------------------------- /public/javascripts/themes/dark-green.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark blue theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: [0, 0, 250, 500], 12 | stops: [ 13 | [0, 'rgb(48, 96, 48)'], 14 | [1, 'rgb(0, 0, 0)'] 15 | ] 16 | }, 17 | borderColor: '#000000', 18 | borderWidth: 2, 19 | className: 'dark-container', 20 | plotBackgroundColor: 'rgba(255, 255, 255, .1)', 21 | plotBorderColor: '#CCCCCC', 22 | plotBorderWidth: 1 23 | }, 24 | title: { 25 | style: { 26 | color: '#C0C0C0', 27 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 28 | } 29 | }, 30 | subtitle: { 31 | style: { 32 | color: '#666666', 33 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 34 | } 35 | }, 36 | xAxis: { 37 | gridLineColor: '#333333', 38 | gridLineWidth: 1, 39 | labels: { 40 | style: { 41 | color: '#A0A0A0' 42 | } 43 | }, 44 | lineColor: '#A0A0A0', 45 | tickColor: '#A0A0A0', 46 | title: { 47 | style: { 48 | color: '#CCC', 49 | fontWeight: 'bold', 50 | fontSize: '12px', 51 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 52 | 53 | } 54 | } 55 | }, 56 | yAxis: { 57 | gridLineColor: '#333333', 58 | labels: { 59 | style: { 60 | color: '#A0A0A0' 61 | } 62 | }, 63 | lineColor: '#A0A0A0', 64 | minorTickInterval: null, 65 | tickColor: '#A0A0A0', 66 | tickWidth: 1, 67 | title: { 68 | style: { 69 | color: '#CCC', 70 | fontWeight: 'bold', 71 | fontSize: '12px', 72 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.75)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | toolbar: { 83 | itemStyle: { 84 | color: 'silver' 85 | } 86 | }, 87 | plotOptions: { 88 | line: { 89 | dataLabels: { 90 | color: '#CCC' 91 | }, 92 | marker: { 93 | lineColor: '#333' 94 | } 95 | }, 96 | spline: { 97 | marker: { 98 | lineColor: '#333' 99 | } 100 | }, 101 | scatter: { 102 | marker: { 103 | lineColor: '#333' 104 | } 105 | }, 106 | candlestick: { 107 | lineColor: 'white' 108 | } 109 | }, 110 | legend: { 111 | itemStyle: { 112 | font: '9pt Trebuchet MS, Verdana, sans-serif', 113 | color: '#A0A0A0' 114 | }, 115 | itemHoverStyle: { 116 | color: '#FFF' 117 | }, 118 | itemHiddenStyle: { 119 | color: '#444' 120 | } 121 | }, 122 | credits: { 123 | style: { 124 | color: '#666' 125 | } 126 | }, 127 | labels: { 128 | style: { 129 | color: '#CCC' 130 | } 131 | }, 132 | 133 | navigation: { 134 | buttonOptions: { 135 | backgroundColor: { 136 | linearGradient: [0, 0, 0, 20], 137 | stops: [ 138 | [0.4, '#606060'], 139 | [0.6, '#333333'] 140 | ] 141 | }, 142 | borderColor: '#000000', 143 | symbolStroke: '#C0C0C0', 144 | hoverSymbolStroke: '#FFFFFF' 145 | } 146 | }, 147 | 148 | exporting: { 149 | buttons: { 150 | exportButton: { 151 | symbolFill: '#55BE3B' 152 | }, 153 | printButton: { 154 | symbolFill: '#7797BE' 155 | } 156 | } 157 | }, 158 | 159 | // scroll charts 160 | rangeSelector: { 161 | buttonTheme: { 162 | fill: { 163 | linearGradient: [0, 0, 0, 20], 164 | stops: [ 165 | [0.4, '#888'], 166 | [0.6, '#555'] 167 | ] 168 | }, 169 | stroke: '#000000', 170 | style: { 171 | color: '#CCC', 172 | fontWeight: 'bold' 173 | }, 174 | states: { 175 | hover: { 176 | fill: { 177 | linearGradient: [0, 0, 0, 20], 178 | stops: [ 179 | [0.4, '#BBB'], 180 | [0.6, '#888'] 181 | ] 182 | }, 183 | stroke: '#000000', 184 | style: { 185 | color: 'white' 186 | } 187 | }, 188 | select: { 189 | fill: { 190 | linearGradient: [0, 0, 0, 20], 191 | stops: [ 192 | [0.1, '#000'], 193 | [0.3, '#333'] 194 | ] 195 | }, 196 | stroke: '#000000', 197 | style: { 198 | color: 'yellow' 199 | } 200 | } 201 | } 202 | }, 203 | inputStyle: { 204 | backgroundColor: '#333', 205 | color: 'silver' 206 | }, 207 | labelStyle: { 208 | color: 'silver' 209 | } 210 | }, 211 | 212 | navigator: { 213 | handles: { 214 | backgroundColor: '#666', 215 | borderColor: '#AAA' 216 | }, 217 | outlineColor: '#CCC', 218 | maskFill: 'rgba(16, 16, 16, 0.5)', 219 | series: { 220 | color: '#7798BF', 221 | lineColor: '#A6C7ED' 222 | } 223 | }, 224 | 225 | scrollbar: { 226 | barBackgroundColor: { 227 | linearGradient: [0, 0, 0, 20], 228 | stops: [ 229 | [0.4, '#888'], 230 | [0.6, '#555'] 231 | ] 232 | }, 233 | barBorderColor: '#CCC', 234 | buttonArrowColor: '#CCC', 235 | buttonBackgroundColor: { 236 | linearGradient: [0, 0, 0, 20], 237 | stops: [ 238 | [0.4, '#888'], 239 | [0.6, '#555'] 240 | ] 241 | }, 242 | buttonBorderColor: '#CCC', 243 | rifleColor: '#FFF', 244 | trackBackgroundColor: { 245 | linearGradient: [0, 0, 0, 10], 246 | stops: [ 247 | [0, '#000'], 248 | [1, '#333'] 249 | ] 250 | }, 251 | trackBorderColor: '#666' 252 | }, 253 | 254 | // special colors for some of the 255 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 256 | legendBackgroundColorSolid: 'rgb(35, 35, 70)', 257 | dataLabelsColor: '#444', 258 | textColor: '#C0C0C0', 259 | maskColor: 'rgba(255,255,255,0.3)' 260 | }; 261 | 262 | // Apply the theme 263 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 264 | -------------------------------------------------------------------------------- /public/javascripts/themes/gray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gray theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: [0, 0, 0, 400], 12 | stops: [ 13 | [0, 'rgb(96, 96, 96)'], 14 | [1, 'rgb(16, 16, 16)'] 15 | ] 16 | }, 17 | borderWidth: 0, 18 | borderRadius: 15, 19 | plotBackgroundColor: null, 20 | plotShadow: false, 21 | plotBorderWidth: 0 22 | }, 23 | title: { 24 | style: { 25 | color: '#FFF', 26 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 27 | } 28 | }, 29 | subtitle: { 30 | style: { 31 | color: '#DDD', 32 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 33 | } 34 | }, 35 | xAxis: { 36 | gridLineWidth: 0, 37 | lineColor: '#999', 38 | tickColor: '#999', 39 | labels: { 40 | style: { 41 | color: '#999', 42 | fontWeight: 'bold' 43 | } 44 | }, 45 | title: { 46 | style: { 47 | color: '#AAA', 48 | font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 49 | } 50 | } 51 | }, 52 | yAxis: { 53 | alternateGridColor: null, 54 | minorTickInterval: null, 55 | gridLineColor: 'rgba(255, 255, 255, .1)', 56 | lineWidth: 0, 57 | tickWidth: 0, 58 | labels: { 59 | style: { 60 | color: '#999', 61 | fontWeight: 'bold' 62 | } 63 | }, 64 | title: { 65 | style: { 66 | color: '#AAA', 67 | font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 68 | } 69 | } 70 | }, 71 | legend: { 72 | itemStyle: { 73 | color: '#CCC' 74 | }, 75 | itemHoverStyle: { 76 | color: '#FFF' 77 | }, 78 | itemHiddenStyle: { 79 | color: '#333' 80 | } 81 | }, 82 | labels: { 83 | style: { 84 | color: '#CCC' 85 | } 86 | }, 87 | tooltip: { 88 | backgroundColor: { 89 | linearGradient: [0, 0, 0, 50], 90 | stops: [ 91 | [0, 'rgba(96, 96, 96, .8)'], 92 | [1, 'rgba(16, 16, 16, .8)'] 93 | ] 94 | }, 95 | borderWidth: 0, 96 | style: { 97 | color: '#FFF' 98 | } 99 | }, 100 | 101 | 102 | plotOptions: { 103 | line: { 104 | dataLabels: { 105 | color: '#CCC' 106 | }, 107 | marker: { 108 | lineColor: '#333' 109 | } 110 | }, 111 | spline: { 112 | marker: { 113 | lineColor: '#333' 114 | } 115 | }, 116 | scatter: { 117 | marker: { 118 | lineColor: '#333' 119 | } 120 | }, 121 | candlestick: { 122 | lineColor: 'white' 123 | } 124 | }, 125 | 126 | toolbar: { 127 | itemStyle: { 128 | color: '#CCC' 129 | } 130 | }, 131 | 132 | navigation: { 133 | buttonOptions: { 134 | backgroundColor: { 135 | linearGradient: [0, 0, 0, 20], 136 | stops: [ 137 | [0.4, '#606060'], 138 | [0.6, '#333333'] 139 | ] 140 | }, 141 | borderColor: '#000000', 142 | symbolStroke: '#C0C0C0', 143 | hoverSymbolStroke: '#FFFFFF' 144 | } 145 | }, 146 | 147 | exporting: { 148 | buttons: { 149 | exportButton: { 150 | symbolFill: '#55BE3B' 151 | }, 152 | printButton: { 153 | symbolFill: '#7797BE' 154 | } 155 | } 156 | }, 157 | 158 | // scroll charts 159 | rangeSelector: { 160 | buttonTheme: { 161 | fill: { 162 | linearGradient: [0, 0, 0, 20], 163 | stops: [ 164 | [0.4, '#888'], 165 | [0.6, '#555'] 166 | ] 167 | }, 168 | stroke: '#000000', 169 | style: { 170 | color: '#CCC', 171 | fontWeight: 'bold' 172 | }, 173 | states: { 174 | hover: { 175 | fill: { 176 | linearGradient: [0, 0, 0, 20], 177 | stops: [ 178 | [0.4, '#BBB'], 179 | [0.6, '#888'] 180 | ] 181 | }, 182 | stroke: '#000000', 183 | style: { 184 | color: 'white' 185 | } 186 | }, 187 | select: { 188 | fill: { 189 | linearGradient: [0, 0, 0, 20], 190 | stops: [ 191 | [0.1, '#000'], 192 | [0.3, '#333'] 193 | ] 194 | }, 195 | stroke: '#000000', 196 | style: { 197 | color: 'yellow' 198 | } 199 | } 200 | } 201 | }, 202 | inputStyle: { 203 | backgroundColor: '#333', 204 | color: 'silver' 205 | }, 206 | labelStyle: { 207 | color: 'silver' 208 | } 209 | }, 210 | 211 | navigator: { 212 | handles: { 213 | backgroundColor: '#666', 214 | borderColor: '#AAA' 215 | }, 216 | outlineColor: '#CCC', 217 | maskFill: 'rgba(16, 16, 16, 0.5)', 218 | series: { 219 | color: '#7798BF', 220 | lineColor: '#A6C7ED' 221 | } 222 | }, 223 | 224 | scrollbar: { 225 | barBackgroundColor: { 226 | linearGradient: [0, 0, 0, 20], 227 | stops: [ 228 | [0.4, '#888'], 229 | [0.6, '#555'] 230 | ] 231 | }, 232 | barBorderColor: '#CCC', 233 | buttonArrowColor: '#CCC', 234 | buttonBackgroundColor: { 235 | linearGradient: [0, 0, 0, 20], 236 | stops: [ 237 | [0.4, '#888'], 238 | [0.6, '#555'] 239 | ] 240 | }, 241 | buttonBorderColor: '#CCC', 242 | rifleColor: '#FFF', 243 | trackBackgroundColor: { 244 | linearGradient: [0, 0, 0, 10], 245 | stops: [ 246 | [0, '#000'], 247 | [1, '#333'] 248 | ] 249 | }, 250 | trackBorderColor: '#666' 251 | }, 252 | 253 | // special colors for some of the demo examples 254 | legendBackgroundColor: 'rgba(48, 48, 48, 0.8)', 255 | legendBackgroundColorSolid: 'rgb(70, 70, 70)', 256 | dataLabelsColor: '#444', 257 | textColor: '#E0E0E0', 258 | maskColor: 'rgba(255,255,255,0.3)' 259 | }; 260 | 261 | // Apply the theme 262 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 263 | -------------------------------------------------------------------------------- /public/javascripts/bootstrap-modal.js: -------------------------------------------------------------------------------- 1 | /* ========================================================= 2 | * bootstrap-modal.js v2.0.2 3 | * http://twitter.github.com/bootstrap/javascript.html#modals 4 | * ========================================================= 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================= */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* MODAL CLASS DEFINITION 26 | * ====================== */ 27 | 28 | var Modal = function ( content, options ) { 29 | this.options = options 30 | this.$element = $(content) 31 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) 32 | } 33 | 34 | Modal.prototype = { 35 | 36 | constructor: Modal 37 | 38 | , toggle: function () { 39 | return this[!this.isShown ? 'show' : 'hide']() 40 | } 41 | 42 | , show: function () { 43 | var that = this 44 | 45 | if (this.isShown) return 46 | 47 | $('body').addClass('modal-open') 48 | 49 | this.isShown = true 50 | this.$element.trigger('show') 51 | 52 | escape.call(this) 53 | backdrop.call(this, function () { 54 | var transition = $.support.transition && that.$element.hasClass('fade') 55 | 56 | !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position 57 | 58 | that.$element 59 | .show() 60 | 61 | if (transition) { 62 | that.$element[0].offsetWidth // force reflow 63 | } 64 | 65 | that.$element.addClass('in') 66 | 67 | transition ? 68 | that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : 69 | that.$element.trigger('shown') 70 | 71 | }) 72 | } 73 | 74 | , hide: function ( e ) { 75 | e && e.preventDefault() 76 | 77 | if (!this.isShown) return 78 | 79 | var that = this 80 | this.isShown = false 81 | 82 | $('body').removeClass('modal-open') 83 | 84 | escape.call(this) 85 | 86 | this.$element 87 | .trigger('hide') 88 | .removeClass('in') 89 | 90 | $.support.transition && this.$element.hasClass('fade') ? 91 | hideWithTransition.call(this) : 92 | hideModal.call(this) 93 | } 94 | 95 | } 96 | 97 | 98 | /* MODAL PRIVATE METHODS 99 | * ===================== */ 100 | 101 | function hideWithTransition() { 102 | var that = this 103 | , timeout = setTimeout(function () { 104 | that.$element.off($.support.transition.end) 105 | hideModal.call(that) 106 | }, 500) 107 | 108 | this.$element.one($.support.transition.end, function () { 109 | clearTimeout(timeout) 110 | hideModal.call(that) 111 | }) 112 | } 113 | 114 | function hideModal( that ) { 115 | this.$element 116 | .hide() 117 | .trigger('hidden') 118 | 119 | backdrop.call(this) 120 | } 121 | 122 | function backdrop( callback ) { 123 | var that = this 124 | , animate = this.$element.hasClass('fade') ? 'fade' : '' 125 | 126 | if (this.isShown && this.options.backdrop) { 127 | var doAnimate = $.support.transition && animate 128 | 129 | this.$backdrop = $('