From 998d011cd308d2d959ccab1e5b8ea92cc732616f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Wed, 9 Oct 2013 15:40:23 +0200 Subject: [PATCH 0001/2585] Initial commit --- db/fic2014.sql | 100 + htdocs/.onyx | 1 + htdocs/index.php | 174 + onyx/ban.list | 0 onyx/cache/templates/cache/cache | 0 onyx/cache/templates/compile/compile | 0 onyx/config/sample.root.xml | 60 + onyx/db/sample.profile.php | 10 + onyx/include/common.php | 28 + onyx/include/functions.php | 96 + onyx/lang/en.xml | 5 + onyx/lang/fr/contact.json | 1 + onyx/lang/fr/erreurs.json | 1 + onyx/lang/fr/global.json | 1 + onyx/lang/fr/publication.json | 1 + onyx/lang/fr/register.json | 1 + onyx/lang/fr/tickets.json | 1 + onyx/lang/fr/userinfos.json | 1 + onyx/load.php | 167 + onyx/log/php.log | 0 onyx/modules/bbcode/main.php | 60 + onyx/modules/captcha/fonts/0.ttfdd | Bin 0 -> 24216 bytes onyx/modules/captcha/fonts/1.ttf | Bin 0 -> 69380 bytes onyx/modules/captcha/main.php | 121 + onyx/modules/captcha/mots.list | 3834 +++++++++++++++++ onyx/modules/chconfig/__config.class.php | 28 + onyx/modules/chconfig/chconfig.class.php | 110 + onyx/modules/chconfig/chmodules.class.php | 57 + onyx/modules/chconfig/main.php | 65 + onyx/modules/db/main.php | 28 + onyx/modules/db/mysql.class.php | 171 + onyx/modules/db/postgresql.class.php | 169 + onyx/modules/lang/main.php | 96 + onyx/modules/mail/class.phpmailer.php | 2320 ++++++++++ onyx/modules/mail/class.pop3.php | 407 ++ onyx/modules/mail/class.smtp.php | 814 ++++ .../mail/language/phpmailer.lang-ar.php | 26 + .../mail/language/phpmailer.lang-br.php | 23 + .../mail/language/phpmailer.lang-ca.php | 24 + .../mail/language/phpmailer.lang-ch.php | 24 + .../mail/language/phpmailer.lang-cz.php | 23 + .../mail/language/phpmailer.lang-de.php | 24 + .../mail/language/phpmailer.lang-dk.php | 23 + .../mail/language/phpmailer.lang-en.php | 23 + .../mail/language/phpmailer.lang-es.php | 23 + .../mail/language/phpmailer.lang-et.php | 24 + .../mail/language/phpmailer.lang-fi.php | 24 + .../mail/language/phpmailer.lang-fo.php | 25 + .../mail/language/phpmailer.lang-fr.php | 23 + .../mail/language/phpmailer.lang-hu.php | 23 + .../mail/language/phpmailer.lang-it.php | 26 + .../mail/language/phpmailer.lang-ja.php | 24 + .../mail/language/phpmailer.lang-nl.php | 23 + .../mail/language/phpmailer.lang-no.php | 23 + .../mail/language/phpmailer.lang-pl.php | 23 + .../mail/language/phpmailer.lang-ro.php | 24 + .../mail/language/phpmailer.lang-ru.php | 23 + .../mail/language/phpmailer.lang-se.php | 23 + .../mail/language/phpmailer.lang-tr.php | 24 + .../mail/language/phpmailer.lang-zh.php | 23 + .../mail/language/phpmailer.lang-zh_cn.php | 24 + onyx/modules/mail/main.php | 38 + onyx/modules/modules.xml | 93 + onyx/modules/pistage/main.php | 34 + onyx/modules/session/main.php | 20 + onyx/modules/session/mysql.class.php | 161 + onyx/modules/session/postgresql.class.php | 153 + onyx/modules/templates/config/config | 0 onyx/modules/templates/main.php | 29 + .../modules/templates/smarty/Smarty.class.php | 1520 +++++++ .../templates/smarty/SmartyBC.class.php | 460 ++ onyx/modules/templates/smarty/debug.tpl | 133 + .../templates/smarty/plugins/block.php.php | 27 + .../smarty/plugins/block.textformat.php | 113 + .../smarty/plugins/function.counter.php | 78 + .../smarty/plugins/function.cycle.php | 106 + .../smarty/plugins/function.fetch.php | 214 + .../plugins/function.html_checkboxes.php | 216 + .../smarty/plugins/function.html_image.php | 159 + .../smarty/plugins/function.html_options.php | 176 + .../smarty/plugins/function.html_radios.php | 200 + .../plugins/function.html_select_date.php | 394 ++ .../plugins/function.html_select_time.php | 366 ++ .../smarty/plugins/function.html_table.php | 177 + .../smarty/plugins/function.mailto.php | 152 + .../smarty/plugins/function.math.php | 87 + .../smarty/plugins/function.popup.php | 118 + .../smarty/plugins/function.popup_init.php | 38 + .../smarty/plugins/function.text.php | 33 + .../smarty/plugins/modifier.capitalize.php | 65 + .../templates/smarty/plugins/modifier.cat.php | 31 + .../plugins/modifier.count_characters.php | 29 + .../plugins/modifier.count_paragraphs.php | 26 + .../plugins/modifier.count_sentences.php | 27 + .../smarty/plugins/modifier.count_words.php | 25 + .../smarty/plugins/modifier.countdown.php | 33 + .../smarty/plugins/modifier.date_format.php | 65 + .../plugins/modifier.debug_print_var.php | 105 + .../smarty/plugins/modifier.default.php | 29 + .../smarty/plugins/modifier.download.php | 26 + .../smarty/plugins/modifier.ereg.php | 30 + .../smarty/plugins/modifier.escape.php | 188 + .../smarty/plugins/modifier.exploderes.php | 32 + .../smarty/plugins/modifier.gravatar.php | 29 + .../smarty/plugins/modifier.indent.php | 28 + .../smarty/plugins/modifier.lower.php | 30 + .../smarty/plugins/modifier.nl2br.php | 35 + .../templates/smarty/plugins/modifier.nom.php | 30 + .../smarty/plugins/modifier.noprint.php | 24 + .../smarty/plugins/modifier.regex_replace.php | 55 + .../smarty/plugins/modifier.replace.php | 33 + .../smarty/plugins/modifier.separenombre.php | 29 + .../plugins/modifier.separerNombres.php | 28 + .../plugins/modifier.separernombres.php | 28 + .../smarty/plugins/modifier.spacify.php | 27 + .../smarty/plugins/modifier.splitwords.php | 38 + .../smarty/plugins/modifier.sprintf.php | 43 + .../smarty/plugins/modifier.status.php | 106 + .../smarty/plugins/modifier.string_format.php | 27 + .../smarty/plugins/modifier.strip.php | 31 + .../smarty/plugins/modifier.strip_tags.php | 31 + .../smarty/plugins/modifier.temps.php | 45 + .../smarty/plugins/modifier.translatedate.php | 19 + .../smarty/plugins/modifier.truncate.php | 59 + .../smarty/plugins/modifier.txtcateg.php | 26 + .../smarty/plugins/modifier.ucfirst.php | 27 + .../smarty/plugins/modifier.upper.php | 30 + .../templates/smarty/plugins/modifier.url.php | 48 + .../smarty/plugins/modifier.wordwrap.php | 29 + .../smarty/plugins/modifiercompiler.cat.php | 30 + .../modifiercompiler.count_characters.php | 33 + .../modifiercompiler.count_paragraphs.php | 28 + .../modifiercompiler.count_sentences.php | 28 + .../plugins/modifiercompiler.count_words.php | 32 + .../plugins/modifiercompiler.default.php | 35 + .../plugins/modifiercompiler.escape.php | 125 + .../plugins/modifiercompiler.from_charset.php | 34 + .../plugins/modifiercompiler.indent.php | 32 + .../smarty/plugins/modifiercompiler.lower.php | 31 + .../plugins/modifiercompiler.noprint.php | 25 + .../modifiercompiler.string_format.php | 26 + .../smarty/plugins/modifiercompiler.strip.php | 33 + .../plugins/modifiercompiler.strip_tags.php | 33 + .../plugins/modifiercompiler.to_charset.php | 34 + .../plugins/modifiercompiler.unescape.php | 51 + .../smarty/plugins/modifiercompiler.upper.php | 30 + .../plugins/modifiercompiler.wordwrap.php | 46 + .../plugins/outputfilter.trimwhitespace.php | 94 + .../plugins/shared.escape_special_chars.php | 51 + .../plugins/shared.literal_compiler_param.php | 33 + .../smarty/plugins/shared.make_timestamp.php | 42 + .../smarty/plugins/shared.mb_str_replace.php | 55 + .../smarty/plugins/shared.mb_unicode.php | 48 + .../smarty/plugins/shared.mb_wordwrap.php | 83 + .../variablefilter.htmlspecialchars.php | 21 + .../sysplugins/smarty_cacheresource.php | 381 ++ .../smarty_cacheresource_custom.php | 237 + .../smarty_cacheresource_keyvaluestore.php | 463 ++ .../sysplugins/smarty_config_source.php | 95 + .../smarty_internal_cacheresource_file.php | 266 ++ .../smarty_internal_compile_append.php | 53 + .../smarty_internal_compile_assign.php | 88 + .../smarty_internal_compile_block.php | 277 ++ .../smarty_internal_compile_break.php | 77 + .../smarty_internal_compile_call.php | 130 + .../smarty_internal_compile_capture.php | 98 + .../smarty_internal_compile_config_load.php | 85 + .../smarty_internal_compile_continue.php | 78 + .../smarty_internal_compile_debug.php | 43 + .../smarty_internal_compile_eval.php | 73 + .../smarty_internal_compile_extends.php | 133 + .../smarty_internal_compile_for.php | 151 + .../smarty_internal_compile_foreach.php | 231 + .../smarty_internal_compile_function.php | 165 + .../sysplugins/smarty_internal_compile_if.php | 207 + .../smarty_internal_compile_include.php | 215 + .../smarty_internal_compile_include_php.php | 108 + .../smarty_internal_compile_insert.php | 142 + .../smarty_internal_compile_ldelim.php | 41 + .../smarty_internal_compile_nocache.php | 73 + ..._internal_compile_private_block_plugin.php | 87 + ...ternal_compile_private_function_plugin.php | 73 + ...arty_internal_compile_private_modifier.php | 140 + ..._compile_private_object_block_function.php | 88 + ...ternal_compile_private_object_function.php | 79 + ...ernal_compile_private_print_expression.php | 156 + ...ernal_compile_private_registered_block.php | 113 + ...al_compile_private_registered_function.php | 81 + ...ernal_compile_private_special_variable.php | 111 + .../smarty_internal_compile_rdelim.php | 41 + .../smarty_internal_compile_section.php | 203 + .../smarty_internal_compile_setfilter.php | 72 + .../smarty_internal_compile_while.php | 94 + .../smarty_internal_compilebase.php | 176 + .../sysplugins/smarty_internal_config.php | 302 ++ .../smarty_internal_config_file_compiler.php | 144 + .../smarty_internal_configfilelexer.php | 622 +++ .../smarty_internal_configfileparser.php | 921 ++++ .../sysplugins/smarty_internal_data.php | 551 +++ .../sysplugins/smarty_internal_debug.php | 206 + .../sysplugins/smarty_internal_filter.php | 89 + .../smarty_internal_filter_handler.php | 70 + .../smarty_internal_function_call_handler.php | 55 + .../smarty_internal_get_include_path.php | 48 + .../smarty_internal_nocache_insert.php | 53 + .../sysplugins/smarty_internal_parsetree.php | 395 ++ .../sysplugins/smarty_internal_register.php | 156 + .../smarty_internal_resource_eval.php | 94 + .../smarty_internal_resource_extends.php | 162 + .../smarty_internal_resource_file.php | 90 + .../smarty_internal_resource_php.php | 114 + .../smarty_internal_resource_registered.php | 95 + .../smarty_internal_resource_stream.php | 76 + .../smarty_internal_resource_string.php | 96 + ...smarty_internal_smartytemplatecompiler.php | 127 + .../sysplugins/smarty_internal_template.php | 692 +++ .../smarty_internal_templatebase.php | 811 ++++ .../smarty_internal_templatecompilerbase.php | 662 +++ .../smarty_internal_templatelexer.php | 1203 ++++++ .../smarty_internal_templateparser.php | 3254 ++++++++++++++ .../sysplugins/smarty_internal_utility.php | 830 ++++ .../sysplugins/smarty_internal_wrapper.php | 131 + .../sysplugins/smarty_internal_write_file.php | 88 + .../smarty/sysplugins/smarty_resource.php | 857 ++++ .../sysplugins/smarty_resource_custom.php | 96 + .../sysplugins/smarty_resource_recompiled.php | 36 + .../sysplugins/smarty_resource_uncompiled.php | 44 + .../smarty/sysplugins/smarty_security.php | 459 ++ onyx/require/cache.php | 35 + onyx/require/env.php | 49 + onyx/require/parse.php | 73 + onyx/require/str.php | 109 + onyx/tpl/bootstrap/bootstrap | 0 233 files changed, 36893 insertions(+) create mode 100644 db/fic2014.sql create mode 100644 htdocs/.onyx create mode 100644 htdocs/index.php create mode 100644 onyx/ban.list create mode 100644 onyx/cache/templates/cache/cache create mode 100644 onyx/cache/templates/compile/compile create mode 100644 onyx/config/sample.root.xml create mode 100644 onyx/db/sample.profile.php create mode 100644 onyx/include/common.php create mode 100644 onyx/include/functions.php create mode 100644 onyx/lang/en.xml create mode 100644 onyx/lang/fr/contact.json create mode 100644 onyx/lang/fr/erreurs.json create mode 100644 onyx/lang/fr/global.json create mode 100644 onyx/lang/fr/publication.json create mode 100644 onyx/lang/fr/register.json create mode 100644 onyx/lang/fr/tickets.json create mode 100644 onyx/lang/fr/userinfos.json create mode 100644 onyx/load.php create mode 100644 onyx/log/php.log create mode 100644 onyx/modules/bbcode/main.php create mode 100644 onyx/modules/captcha/fonts/0.ttfdd create mode 100644 onyx/modules/captcha/fonts/1.ttf create mode 100644 onyx/modules/captcha/main.php create mode 100755 onyx/modules/captcha/mots.list create mode 100644 onyx/modules/chconfig/__config.class.php create mode 100644 onyx/modules/chconfig/chconfig.class.php create mode 100644 onyx/modules/chconfig/chmodules.class.php create mode 100644 onyx/modules/chconfig/main.php create mode 100644 onyx/modules/db/main.php create mode 100644 onyx/modules/db/mysql.class.php create mode 100644 onyx/modules/db/postgresql.class.php create mode 100644 onyx/modules/lang/main.php create mode 100644 onyx/modules/mail/class.phpmailer.php create mode 100644 onyx/modules/mail/class.pop3.php create mode 100644 onyx/modules/mail/class.smtp.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-ar.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-br.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-ca.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-ch.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-cz.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-de.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-dk.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-en.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-es.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-et.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-fi.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-fo.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-fr.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-hu.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-it.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-ja.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-nl.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-no.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-pl.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-ro.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-ru.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-se.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-tr.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-zh.php create mode 100644 onyx/modules/mail/language/phpmailer.lang-zh_cn.php create mode 100644 onyx/modules/mail/main.php create mode 100644 onyx/modules/modules.xml create mode 100644 onyx/modules/pistage/main.php create mode 100644 onyx/modules/session/main.php create mode 100644 onyx/modules/session/mysql.class.php create mode 100644 onyx/modules/session/postgresql.class.php create mode 100644 onyx/modules/templates/config/config create mode 100644 onyx/modules/templates/main.php create mode 100644 onyx/modules/templates/smarty/Smarty.class.php create mode 100644 onyx/modules/templates/smarty/SmartyBC.class.php create mode 100644 onyx/modules/templates/smarty/debug.tpl create mode 100644 onyx/modules/templates/smarty/plugins/block.php.php create mode 100644 onyx/modules/templates/smarty/plugins/block.textformat.php create mode 100644 onyx/modules/templates/smarty/plugins/function.counter.php create mode 100644 onyx/modules/templates/smarty/plugins/function.cycle.php create mode 100644 onyx/modules/templates/smarty/plugins/function.fetch.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_checkboxes.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_image.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_options.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_radios.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_select_date.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_select_time.php create mode 100644 onyx/modules/templates/smarty/plugins/function.html_table.php create mode 100644 onyx/modules/templates/smarty/plugins/function.mailto.php create mode 100644 onyx/modules/templates/smarty/plugins/function.math.php create mode 100644 onyx/modules/templates/smarty/plugins/function.popup.php create mode 100644 onyx/modules/templates/smarty/plugins/function.popup_init.php create mode 100644 onyx/modules/templates/smarty/plugins/function.text.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.capitalize.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.cat.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.count_characters.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.count_paragraphs.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.count_sentences.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.count_words.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.countdown.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.date_format.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.debug_print_var.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.default.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.download.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.ereg.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.escape.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.exploderes.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.gravatar.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.indent.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.lower.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.nl2br.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.nom.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.noprint.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.regex_replace.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.replace.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.separenombre.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.separerNombres.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.separernombres.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.spacify.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.splitwords.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.sprintf.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.status.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.string_format.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.strip.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.strip_tags.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.temps.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.translatedate.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.truncate.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.txtcateg.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.ucfirst.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.upper.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.url.php create mode 100644 onyx/modules/templates/smarty/plugins/modifier.wordwrap.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.cat.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.count_characters.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.count_paragraphs.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.count_sentences.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.count_words.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.default.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.escape.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.from_charset.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.indent.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.lower.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.noprint.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.string_format.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.strip.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.strip_tags.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.to_charset.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.unescape.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.upper.php create mode 100644 onyx/modules/templates/smarty/plugins/modifiercompiler.wordwrap.php create mode 100644 onyx/modules/templates/smarty/plugins/outputfilter.trimwhitespace.php create mode 100644 onyx/modules/templates/smarty/plugins/shared.escape_special_chars.php create mode 100644 onyx/modules/templates/smarty/plugins/shared.literal_compiler_param.php create mode 100644 onyx/modules/templates/smarty/plugins/shared.make_timestamp.php create mode 100644 onyx/modules/templates/smarty/plugins/shared.mb_str_replace.php create mode 100644 onyx/modules/templates/smarty/plugins/shared.mb_unicode.php create mode 100644 onyx/modules/templates/smarty/plugins/shared.mb_wordwrap.php create mode 100644 onyx/modules/templates/smarty/plugins/variablefilter.htmlspecialchars.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_cacheresource.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_cacheresource_custom.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_cacheresource_keyvaluestore.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_config_source.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_cacheresource_file.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_append.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_assign.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_block.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_break.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_call.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_capture.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_config_load.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_continue.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_debug.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_eval.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_extends.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_for.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_foreach.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_function.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_if.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_include.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_include_php.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_insert.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_ldelim.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_nocache.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_block_plugin.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_function_plugin.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_modifier.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_object_block_function.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_object_function.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_print_expression.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_registered_block.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_registered_function.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_private_special_variable.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_rdelim.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_section.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_setfilter.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compile_while.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_compilebase.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_config.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_config_file_compiler.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_configfilelexer.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_configfileparser.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_data.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_debug.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_filter.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_filter_handler.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_function_call_handler.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_get_include_path.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_nocache_insert.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_parsetree.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_register.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_eval.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_extends.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_file.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_php.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_registered.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_stream.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_resource_string.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_smartytemplatecompiler.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_template.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_templatebase.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_templatecompilerbase.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_templatelexer.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_templateparser.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_utility.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_wrapper.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_internal_write_file.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_resource.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_resource_custom.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_resource_recompiled.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_resource_uncompiled.php create mode 100644 onyx/modules/templates/smarty/sysplugins/smarty_security.php create mode 100644 onyx/require/cache.php create mode 100644 onyx/require/env.php create mode 100644 onyx/require/parse.php create mode 100644 onyx/require/str.php create mode 100644 onyx/tpl/bootstrap/bootstrap diff --git a/db/fic2014.sql b/db/fic2014.sql new file mode 100644 index 00000000..38d9e326 --- /dev/null +++ b/db/fic2014.sql @@ -0,0 +1,100 @@ +-- phpMyAdmin SQL Dump +-- version 3.5.1 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Generation Time: Oct 09, 2013 at 03:38 PM +-- Server version: 5.5.32-log +-- PHP Version: 5.4.9--pl0-gentoo + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + +-- +-- Database: `fic2014` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `exercices` +-- + +CREATE TABLE IF NOT EXISTS `exercices` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_theme` int(10) unsigned NOT NULL, + `name` varchar(255) COLLATE utf16_unicode_ci NOT NULL, + `difficulty` tinyint(3) unsigned NOT NULL, + `points` smallint(6) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `exercice_dependancies` +-- + +CREATE TABLE IF NOT EXISTS `exercice_dependancies` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_exercice` int(10) unsigned NOT NULL, + `id_dependence` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sessions` +-- + +CREATE TABLE IF NOT EXISTS `sessions` ( + `session` binary(32) NOT NULL, + `uid` binary(16) NOT NULL, + `time` int(11) NOT NULL, + `ip` varbinary(16) NOT NULL, + `var` varchar(9999) COLLATE utf8_unicode_ci NOT NULL, + `level` tinyint(2) NOT NULL, + `active` enum('1','0') COLLATE utf8_unicode_ci NOT NULL, + PRIMARY KEY (`session`) +) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `solved` +-- + +CREATE TABLE IF NOT EXISTS `solved` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_user` int(10) unsigned NOT NULL, + `id_exercice` int(10) unsigned NOT NULL, + `time` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `themes` +-- + +CREATE TABLE IF NOT EXISTS `themes` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) COLLATE utf16_unicode_ci NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE IF NOT EXISTS `users` ( + `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(255) COLLATE utf16_unicode_ci NOT NULL, + `password` binary(64) NOT NULL, + `auth_level` tinyint(1) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=1 ; diff --git a/htdocs/.onyx b/htdocs/.onyx new file mode 100644 index 00000000..9e6e10a7 --- /dev/null +++ b/htdocs/.onyx @@ -0,0 +1 @@ +../onyx/load.php diff --git a/htdocs/index.php b/htdocs/index.php new file mode 100644 index 00000000..ebe38cc3 --- /dev/null +++ b/htdocs/index.php @@ -0,0 +1,174 @@ +level > 0) +{ + if ($SESS->level&1) + { + switch($p) + { + case "adm_users": + include("admin/users.php"); + break; + } + } + + if ($SESS->level&2) + { + switch($p) + { + case "articles": + include("articles/articles.php"); + break; + + case "articles_prod": + include("articles/production.php"); + break; + } + } + + if ($SESS->level&4) + { + switch($p) + { + case "palettes": + include("articles/palettes.php"); + break; + + case "palettes_besoins": + include("articles/needs.php"); + break; + + case "prod_couts": + include("production/costs.php"); + break; + + case "stocks_besoins": + include("materials/needs.php"); + break; + + case "stocks_etat": + include("materials/etat.php"); + break; + + case "transport": + include("materials/transport.php"); + break; + } + } + + if ($SESS->level&16) + { + switch($p) + { + case "commandes": + include("materials/commandes.php"); + break; + + case "stocks_besoins": + include("materials/needs.php"); + break; + + case "transport": + include("materials/transport.php"); + break; + } + } + + if ($SESS->level&8) + { + switch($p) + { + case "prod_resume": + include("articles/needs.php"); + break; + + case "prod_entry": + include("production/entry.php"); + break; + } + } + + switch($p) + { + case "": + $_GET["p"] = ""; + case "accueil": + include("users/accueil.php"); + break; + + case "disconnect": + include("public/login.php"); + break; + } +} + +if (empty($page)) // Public pages +{ + switch($p) + { + case "": + $_GET["p"] = ""; + case "login": + include("public/login.php"); + break; + + case "forgotpasswd": + include("public/forgotpasswd.php"); + break; + + case "403": + $template->assign("err", 403); + $page = "404"; + break; + case "404": + $template->assign("err", 404); + $page = "404"; + break; + case "5mail": + include("mail.php"); + exit; + case "500": + $template->assign("err", 500); + $page = "404"; + break; + } +} + +if (empty($page)) +{ + $template->assign("err", 404); + $template->display("404.tpl"); +} +else +{ + $ALERTS = array(); + $nbAlert = @count($SESS->values["alerts"]); + if ($nbAlert > 0) + { + for ($i = 0; $i < $nbAlert; $i++) + { + if ($SESS->values["alerts"][$i]->page == $page) + { + $ALERTS[] = $SESS->values["alerts"][$i]; + unset($SESS->values["alerts"][$i]); + $i--; $nbAlert--; + $SESS->values["alerts"] = array_values($SESS->values["alerts"]); + } + } + $SESS->put(); + } + $template->assign("ALERTS", $ALERTS); + + $template->display($page.".tpl"); +} diff --git a/onyx/ban.list b/onyx/ban.list new file mode 100644 index 00000000..e69de29b diff --git a/onyx/cache/templates/cache/cache b/onyx/cache/templates/cache/cache new file mode 100644 index 00000000..e69de29b diff --git a/onyx/cache/templates/compile/compile b/onyx/cache/templates/compile/compile new file mode 100644 index 00000000..e69de29b diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml new file mode 100644 index 00000000..61d79f2e --- /dev/null +++ b/onyx/config/sample.root.xml @@ -0,0 +1,60 @@ + + + + ]]> + + + 0 + 1 + 6143 + Europe/Paris + + text/html;charset=utf-8 + + + 0 + 0 + 1 + 1 + 0 + 0 + 64M + 1 + + 1 + + fr_FR.UTF8 + fr.UTF8 + fr_FR.UTF-8 + fr.UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/onyx/db/sample.profile.php b/onyx/db/sample.profile.php new file mode 100644 index 00000000..1ad73643 --- /dev/null +++ b/onyx/db/sample.profile.php @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/onyx/include/common.php b/onyx/include/common.php new file mode 100644 index 00000000..05d87757 --- /dev/null +++ b/onyx/include/common.php @@ -0,0 +1,28 @@ +values["connected"]) && !defined("xCSRF")) + define("xCSRF", true); + +require_once("functions.php"); //Inclusion des principales fonctions + +//On charge la session +$SESS = new Session(); + +$template = new Template(); + +$template->assign("ERRmessage", false); +$template->assign("auth_lvl", $SESS->level); +$template->assign("SESS", $SESS->values); + +if (!empty($LANG)) + $template->assign("LANG", $LANG); + +//Evite les attaques CSRF +if ($SESS->level > 2 && !empty($_SERVER["HTTP_REFERER"]) && !(preg_match('#^http://'.$_SERVER['HTTP_HOST'].'#', $_SERVER["HTTP_REFERER"]) && defined("xCSRF"))) +{ + elog("Possibilité d'attaque CSRF\n".var_export($_REQUEST, TRUE), 2); + unset($_POST, $_GET); + $_GET = $_POST = array(); +} +?> \ No newline at end of file diff --git a/onyx/include/functions.php b/onyx/include/functions.php new file mode 100644 index 00000000..dfdd80f4 --- /dev/null +++ b/onyx/include/functions.php @@ -0,0 +1,96 @@ +AddAddress($to); + $mail->Subject = $subject; + $mail->Body = $body; + + return $mail->Send(); +} + +function erreur($message, $color = "error") +{ + global $template; + + $template->assign('ERRmessage', $message); + $template->assign('ERRcolor', $color); +} + +function format_url($string) +{ + $string = trim($string); + + if ( ctype_digit($string) ) + { + return $string; + } + else + { + // replace accented chars + $accents = '/&([A-Za-z]{1,2})(grave|acute|circ|cedil|uml|lig);/'; + $string_encoded = htmlentities($string,ENT_NOQUOTES,'UTF-8'); + + $string = preg_replace($accents,'$1',$string_encoded); + + // clean out the rest + $replace = array('([\40\'/])','([^a-zA-Z0-9-])','(-{2,})'); + $with = array('-','','-'); + $string = preg_replace($replace,$with,$string); + } + + return strtolower($string); +} + +function pagination($nbPages, $page, $link = "documents-recents-") +{ + $nbPages++; + $cntPages = array(); + if ($nbPages < 10) + { + for ($i = 1 ; $i <= $nbPages ; $i++) + $cntPages[] = $i; + } + else + { + for ($i = 1 ; $i <= 4 ; $i++) + $cntPages[] = $i; + if (6 != max(6, $page)) + $cntPages[] = "..."; + for ($i = max(6, $page) - 1 ; $i < min(max(6, $page) + 3, $nbPages - 2) ; $i++) + $cntPages[] = $i; + if ($nbPages - 2 != max(6, $page) + 3 && $nbPages - 2 != $i) + $cntPages[] = "..."; + for ($i = $nbPages - 2 ; $i <= $nbPages ; $i++) + $cntPages[] = $i; + } + + $out = ""; + foreach($cntPages as $p) + { + if ($p == "...") + $out .= " ... "; + else + $out .= ' '.$p.' '; + } + + return '<<'.$out.'>>'; +} + +function eregmenu($pattern, $string) +{ + return preg_match("#".$pattern."#ui", $string); +} + +?> \ No newline at end of file diff --git a/onyx/lang/en.xml b/onyx/lang/en.xml new file mode 100644 index 00000000..6f95bc53 --- /dev/null +++ b/onyx/lang/en.xml @@ -0,0 +1,5 @@ + + + Hello + Good bye + \ No newline at end of file diff --git a/onyx/lang/fr/contact.json b/onyx/lang/fr/contact.json new file mode 100644 index 00000000..6ee3fe78 --- /dev/null +++ b/onyx/lang/fr/contact.json @@ -0,0 +1 @@ +{"title":"Nous contacter","1":{"reponses":{"2":"Je suis acheteur","3":"Je suis vendeur","4":"Je suis annonceur","5":"Je souhaite signaler une faute d'orthographe ou un bug pr\u00e9sent sur le site"}},"2":{"intitule":"Raison de votre contact","reponses":{"2.1":"Je n'ai pas b\u00e9n\u00e9fici\u00e9 de mon document gratuit apr\u00e8s cinq achats","2.2":"Je n'ai pas re\u00e7u mon document apr\u00e8s paiement","2.3":"Je ne parviens pas \u00e0 me connecter \u00e0 mon compte","form2.4":"Je me suis fais voler mon compte","2.5":"Je n'arrive pas \u00e0 lire le document que j'ai achet\u00e9","2.6":"Autre"}},"2.1":{"intitule":"Si vous avez achet\u00e9 cinq documents sur Discis, nous vous offrons un document d'une valeur de 1,80 euros. Seuls les documents de cette valeur vous seront accessibles gratuitements apr\u00e8s l'achat de cinq documents.
\nPour b\u00e9n\u00e9ficier de cette offre, connectez-vous \u00e0 votre compte puis allez sur la page du document que vous souhaitez acqu\u00e9rir, celui-ci sera disponible gratuitement !\nNous ne faisons pas de remise sur les documents sup\u00e9rieurs \u00e0 1,80euros.","reponses":{"0":"Retourner \u00e0 l'accueil","2.1.1":"Apr\u00e8s avoir effectu\u00e9 les manipulations d\u00e9crites ci-dessus, je n'ai toujours pas obtenu mon document gratuit"}},"2.1.1":{"intitule":"Pour comptabiliser vos diff\u00e9rents achats, il est n\u00e9cessaire que vous poss\u00e9diez un compte et que vous y soyez connect\u00e9s lors de l'achat des documents.
Nous ne pouvons rien faire dans le cas contraire.
Si vous ne poss\u00e8dez pas de compte, vous ne pouvez malheuresement pas b\u00e9n\u00e9ficier de notre programme de fid\u00e9lit\u00e9.","reponses":{"0":"Retourner \u00e0 l'acceuil","form2.1.1.1":"Je poss\u00e8de un compte Discis et j'\u00e9tais connect\u00e9 lors de l'achat de mes documents"}},"2.3":{"intitule":"Si vous ne parvenez pas \u00e0 vous connecter \u00e0 votre compte, v\u00e9rifiez tout d'abord que ce probl\u00e8me n'est pas d'ordre g\u00e9n\u00e9ral en consultant notre blog des d\u00e9veloppeurs dans la rubrique probl\u00e8mes techniques.","reponses":{"0":"Retourner \u00e0 l'accueil","2.3.1":"Aucun probl\u00e8me n'est signal\u00e9 concernant les connections aux comptes utilisateurs sur le blog des d\u00e9veloppeurs"}},"2.3.1":{"intitule":"Vous pouvez r\u00e9cup\u00e9rer votre mot de pass en cliquant sur le lien \"mot de pass oubli\u00e9\" en dessous du formulaire de connection du compte. Un mail vous sera alors envoy\u00e9 sur l'adresse que vous nous avez fourni lors de votre inscription.","reponses":{"0":"Retourner \u00e0 l'accueil","2.5.1":"Je n'arrive pas \u00e0 utiliser 7-zip","form2.5.2":"Le fichier est illisibe et semble corrompu"}},"form2.4":["test","test2"],"3":{"intitule":"Raison de votre contacte","reponses":{"3.1":"Un de mes documents a \u00e9t\u00e9 plagi\u00e9","3.2":"Mes documents ne sont toujours pas publi\u00e9s","3.3":"Je n'ai toujours pas re\u00e7u mon paiement","3.4":"Je souhaite supprimer un document","3.5":"Je ne parviens pas \u00e0 me connecter \u00e0 mon compte","3.6":"Autre"}},"3.1":{"intitule":"Si vous vous \u00eates rendu compte que certains de vos documents ont \u00e9t\u00e9 plagi\u00e9s sur un site internet tiers, vous pouvez en g\u00e9n\u00e9ral contacter les webmasters du dit site via un formulaire de contact.\n Voici un mod\u00e8le de lettre que vous pouvez soumettre pour faire valoir vos droits :

\n

\nBonjour,

\nJe vous informe que le document [ins\u00e9rez le titre du document] disponible sur votre site internet \u00e0 cette adresse [ins\u00e9rez l'adresse du plagiat] est un document dont je suis l'auteur que j'ai publi\u00e9 sur le site internet discis.fr le [ins\u00e9rer la date de publication de votre document] \u00e0 l'adresse suivante : [ins\u00e9rer l'adresse discis de votre document]. Je vous demande de bien vouloir supprimer ce document plagi\u00e9 de votre base de donn\u00e9e.

\nCordialement<\/p>\nSi vous ne recevez aucune r\u00e9ponse d'ici deux semaines, cliquez sur le bouton ci-dessous.","reponses":{"0":"Retourner \u00e0 l'accueil","form3.1.1":"Le site internet du document plagi\u00e9 n'a pas r\u00e9pondu \u00e0 mon mail"}},"3.2":{"intitule":"Le temps de traitement de vos documents d\u00e9pend du nombre de documents que nous recevons. De plus, afin de garantir la vente de documents de qualit\u00e9s, nous prenons un certain temps \u00e0 lire un \u00e0 un chaque document re\u00e7u et \u00e0 le soumettre \u00e0 notre logiciel anti-plagiat.
Tout ceci prend beaucoup de temps et nous nous excusons par avance pour les d\u00e9lais qui peuvent \u00eatre longs dans certains cas.
Cependant, si votre document a \u00e9t\u00e9 envoy\u00e9 il y a plus d'un mois, il a sans doute \u00e9t\u00e9 \"oubli\u00e9\" par notre comit\u00e9 de lecture.","reponses":{"0":"Retourner \u00e0 l'accueil","form3.2.1":"Aucun probl\u00e8me n'est signal\u00e9 convernant des retards de paiement ce mois-ci sur le blog des d\u00e9veloppeurs"}}} \ No newline at end of file diff --git a/onyx/lang/fr/erreurs.json b/onyx/lang/fr/erreurs.json new file mode 100644 index 00000000..b975bbc0 --- /dev/null +++ b/onyx/lang/fr/erreurs.json @@ -0,0 +1 @@ +{"403":{"title":"Erreur 403","subtitle":"Accès réglementé","content":"Vous n'\u00eates pas autoris\u00e9 \u00e0 acc\u00e9der \u00e0 cette page."},"404":{"title":"Erreur 404","subtitle":"Page introuvable","content":"La page à laquelle vous tentez d'accéder n'existe pas ou l'adresse que vous avez tapée est incorrecte."},"500":{"title":"Erreur 500","subtitle":"Serveur indisponible","content":"Le serveur est actuellement dans l'incapacit\u00e9 de repondre \u00e0 votre requ\u00eate.

Veuillez recommencer plus tard."}} diff --git a/onyx/lang/fr/global.json b/onyx/lang/fr/global.json new file mode 100644 index 00000000..c8a47985 --- /dev/null +++ b/onyx/lang/fr/global.json @@ -0,0 +1 @@ +{"date":"d\/m\/Y \u00e0 H:i","rssfeed":"Flux Atom des nouvelles","forgotpsw":"Mot de passe oubli\u00e9 ...","continue":"Continuer","send":"Envoyer","login":{"connect":"Ok","disconnect":"D\u00e9connexion"},"menu":{"0":{"accueil":"Accueil","publier":"Publier","inscription":"S'inscrire","contact":"Contact"},"1":{"conditions-generales":"Conditions g\u00e9n\u00e9rales"},"2":{"accueil":"Accueil","mon-compte":"Mon compte","statistiques":"Statistiques","":"


","publier":"Publier","mes-documents-publies":"Mes documents publi\u00e9s","mes-documents-en-attente":"Mes documents en attente %s"," ":"
","contact":"Contact"},"4":{"kor-docs-en-correction":"Documents en correction %s","kor-docs-en-attente":"Documents en attente %s"},"6":{"adm-controldocs":"Documents \u00e0 controler %s","kor-docs-en-correction":"Documents en correction %s","kor-docs-en-attente":"Documents en attente %s","":"
","adm-prise-de-controle":"Prendre le controle d'un compte","adm-pubs":"Modifier les publicit\u00e9s","adm-news":"Modifier les news"," ":"
","tickets":"Tickets %s"}},"footer":{"annonceurs":"Annonceurs","conditions-generales":"Conditions g\u00e9n\u00e9rales","plan":"Plan du site"}} \ No newline at end of file diff --git a/onyx/lang/fr/publication.json b/onyx/lang/fr/publication.json new file mode 100644 index 00000000..7251a212 --- /dev/null +++ b/onyx/lang/fr/publication.json @@ -0,0 +1 @@ +{"titre0":"Publication de documents","mails":{"pubOk":{"subject":"[Discis] Publication de votre document","body":"Bonjour,\n\nNous avons le plaisir de vous informer que votre document %s, soumis \u00e0 notre \u00e9quipe le %s, vient d\u2019\u00eatre publi\u00e9 sur Discis.\nVotre document est propos\u00e9 \u00e0 la vente pour %s ; il est disponible \u00e0 cette adresse : http:\/\/www.discis.fr\/document-%s. Si vous d\u00e9sirez apporter des modifications \u00e0 votre document, connectez-vous dans votre espace personnel dans la rubrique \"Mes documents publi\u00e9s\" (http:\/\/www.discis.fr\/mes-documents-publies).\n\nCordialement,"},"pubMod":{"subject":"[Discis] Publication de votre document","body":"Bonjour,\n\nVotre document %s soumis le %s a retenu notre intention. Cependant, nous ne l\u2019avons pas encore publi\u00e9 pour la raison suivante\u00a0:\n\n%s\n\nPour effectuer les modifications n\u00e9cessaires, connectez-vous \u00e0 votre compte \u00e0 la rubrique \"Mes documents en attente\" (http:\/\/www.discis.fr\/mes-documents-en-attente).\n\nCordialement,"},"pubNo":{"subject":"[Discis] Publication de votre document","body":"Bonjour,\n\nNous sommes d\u00e9sol\u00e9 de vous informer que votre document %s soumis le %s ne sera pas publi\u00e9 sur Discis. Le motif est le suivant\u00a0: %s.\n\nNous vous encourageons \u00e0 modifier ce document pour le soumettre \u00e0 nouveau \u00e0 notre \u00e9quipe.\n\nCordialement,"}}} \ No newline at end of file diff --git a/onyx/lang/fr/register.json b/onyx/lang/fr/register.json new file mode 100644 index 00000000..bfa03627 --- /dev/null +++ b/onyx/lang/fr/register.json @@ -0,0 +1 @@ +{"title":"Inscription","helpCaptcha":"Si vous ne parvennez pas \u00e0 voir cette image, contactez un administrateur.","msgOk":"Votre inscription a \u00e9t\u00e9 r\u00e9alis\u00e9e avec succ\u00e8s.
Bienvenue sur Discis !","chPswd":"Votre mot de passe a \u00e9t\u00e9 r\u00e9initialis\u00e9 avec succ\u00e8s.","button":"S'inscrire","err0":"Le nom d'utilisateur comporte des catact\u00e8res invalides ou est trop court ou trop long !","err1":"Veuillez compl\u00e9ter tous les champs","err2":"Le texte que vous avez recopi\u00e9 ne correspond pas au contenu de l'image !","err3":"Le mot de passe et sa conformation sont diff\u00e9rents !","err4":"Le mot de passe est trop court ! Il doit contenir au moins 8 caract\u00e8res.","err5":"L'adresse \u00e9lectronique indiqu\u00e9e ne semble pas valide.","err6":"Le nom d'utilisateur que vous avez choisit existe d\u00e9j\u00e0 ou votre adresse \u00e9lectronique est d\u00e9j\u00e0 associ\u00e9e avec un autre compte.","mail":{"subject":"[Discis] Validation de votre inscription","body":"Soyez le bienvenu sur Discis !\n\nNous vous souhaitons beaucoup de succ\u00e8s avec la vente de vos documents ou la gestion de vos achats. Nous tenons \u00e0 vous informer que nous sommes \u00e0 disposition si vous avez besoin d'aide. Ainsi, vous pouvez nous contacter \u00e0 tout moment via la page contact du site.\n\nMerci de vous \u00eatre enregistr\u00e9,"},"tip":[{"title":"Bienvenue sur Discis !","content":"Votre compte Discis vous permettra de :\n @@ -31,5 +35,8 @@ {$ERRmessage} {/if} + +
{block name=content}{/block} +
{/block} diff --git a/onyx/tpl/bootstrap/public/score.tpl b/onyx/tpl/bootstrap/public/score.tpl index 8c6ef25c..2fea7aee 100644 --- a/onyx/tpl/bootstrap/public/score.tpl +++ b/onyx/tpl/bootstrap/public/score.tpl @@ -1,11 +1,22 @@ {extends file="layout.tpl"} {block name=head} - + {/block} {block name=content} +
+
+
    +
  • 00
  • +
  • :
  • +
  • 00
  • +
  • :
  • +
  • 00
  • +
+
+

TOP #10

@@ -56,7 +67,7 @@

Example

-

This is a example

+

This is a example

This is a example

This is a example

This is a example

@@ -103,8 +114,21 @@ {block name=end} + {/block} From bed471d75a086c7b621a11175286b510e537c7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Tue, 22 Oct 2013 08:16:02 +0200 Subject: [PATCH 0038/2585] New router and associated pages --- htdocs/index.php | 145 +++++++++--------- nginx.conf | 2 +- onyx/config/sample.root.xml | 12 -- onyx/include/common.php | 15 +- .../common/{User.class.php => Team.class.php} | 0 onyx/include/public/home.php | 17 +- onyx/include/public/team.php | 16 ++ onyx/include/team/change.php | 6 + onyx/include/team/exercice.php | 6 + onyx/include/team/home.php | 8 + onyx/include/team/summary.php | 6 + onyx/include/team/team.php | 16 ++ 12 files changed, 134 insertions(+), 115 deletions(-) rename onyx/include/common/{User.class.php => Team.class.php} (100%) create mode 100644 onyx/include/public/team.php create mode 100644 onyx/include/team/change.php create mode 100644 onyx/include/team/exercice.php create mode 100644 onyx/include/team/home.php create mode 100644 onyx/include/team/summary.php create mode 100644 onyx/include/team/team.php diff --git a/htdocs/index.php b/htdocs/index.php index ad2248b4..fcd65efe 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -2,112 +2,107 @@ //Inclusion de l'API Onyx require_once(trim(file_get_contents('./.onyx'))); +define("SALT_USER", "connected"); +define("SALT_ADMIN", "admin"); + //On active le débogage si l'on est sur le domaine de debug if ($_SERVER["SERVER_NAME"] == "localhost" || $_SERVER["SERVER_NAME"] == "fic" || $_SERVER["SERVER_NAME"] == "atlantis.chen.li") define("DEBUG", true); //Chargement de tout le nécessaire pour le site -require_once("common.php"); +//require_once("common.php"); -$p = strtolower(gpc("p")); +$n = preg_match_all("#[^/]+#", strtolower(gpc("p")), $out); +$p = $out[0]; -if (empty($page) && $SESS->level > 0) +// Admin part +if ($p[0] == SALT_ADMIN) { - if ($SESS->level > 1) + if ($n <= 1) + $page = require("admin/home.php"); + else { - switch($p) + switch($p[1]) { - case "exercices/import/": - case "exercices/import": - include("admin/import_exercices.php"); + case "exercices/import/": + case "exercices/import": + $page = require("admin/import_exercices.php"); break; - case "users": - case "users/": - include("admin/list_users.php"); + case "users": + case "users/": + $page = require("admin/list_users.php"); break; - case "users/import": - case "users/import/": - include("admin/import_users.php"); + case "users/import": + case "users/import/": + $page = require("admin/import_users.php"); break; } } - - switch($p) - { - case "": - $_GET["p"] = ""; - case "accueil": - include("users/accueil.php"); - break; - - case "disconnect": - include("public/login.php"); - break; - } } -if (empty($page)) // Public pages +// Known users +else if ($p[0] == SALT_USER) { - switch($p) + $connected = true; + + if ($n <= 1) + $page = require("team/home.php"); + else { - case "": - $_GET["p"] = ""; - case "home": - include("public/home.php"); - break; + $TEAM = $p[1]; - case "login": - include("public/login.php"); - break; + if ($n <= 2) + $page = require("team/team.php"); + else + { + switch($p[2]) + { + case "change/": + case "change": + $page = require("team/change.php"); + break; - case "score": - include("public/score.php"); - break; + case "summary": + case "summary/": + $page = require("team/summary.php"); + break; + } - case "403": - $template->assign("err", 403); - $page = "404"; - break; - case "404": - $template->assign("err", 404); - $page = "404"; - break; - case "5mail": - include("mail.php"); - exit; - case "500": - $template->assign("err", 500); - $page = "404"; - break; + // SALT/$team/$theme + if (empty($page)) + { + $THEME = $p[2]; + + if ($n == 4) + { + $EXERCICE = $p[3]; + $page = require("team/exercice.php"); + } + } + } } } +// Public part +else +{ + if ($n == 0) + $page = require("public/home.php"); + else if ($n == 1) + { + $TEAM = $p[0]; + + $page = require("public/team.php"); + } +} + +// No page here...? if (empty($page)) { $template->assign("err", 404); $template->display("404.tpl"); } else -{ - $ALERTS = array(); - $nbAlert = @count($SESS->values["alerts"]); - if ($nbAlert > 0) - { - for ($i = 0; $i < $nbAlert; $i++) - { - if ($SESS->values["alerts"][$i]->page == $page) - { - $ALERTS[] = $SESS->values["alerts"][$i]; - unset($SESS->values["alerts"][$i]); - $i--; $nbAlert--; - $SESS->values["alerts"] = array_values($SESS->values["alerts"]); - } - } - $SESS->put(); - } - $template->assign("ALERTS", $ALERTS); - $template->display($page.".tpl"); -} diff --git a/nginx.conf b/nginx.conf index e85f1569..02cc969c 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,6 +1,6 @@ server { listen 80; - listen [::]:80; + listen [::]:80 ipv6only=on; server_name fic fic.p0m.fr fic.nemunai.re; access_log /var/log/nginx/fic.access_log; diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index 5f3a4696..e6291018 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -38,16 +38,6 @@ - - - - - - - - - @@ -55,7 +45,5 @@ - - diff --git a/onyx/include/common.php b/onyx/include/common.php index b1397253..6754e327 100644 --- a/onyx/include/common.php +++ b/onyx/include/common.php @@ -7,26 +7,13 @@ if (empty($sess->values["connected"]) && !defined("xCSRF")) require_once("functions.php"); //Inclusion des principales fonctions require_once("common/Exercice.class.php"); +require_once("common/Team.class.php"); require_once("common/Theme.class.php"); -require_once("common/User.class.php"); - -//On charge la session -$SESS = new Session(); $template = new Template(); $template->assign("ERRmessage", false); -$template->assign("auth_lvl", $SESS->level); -$template->assign("SESS", $SESS->values); $template->assign("END", $VAR['end_challenge'] - time()); if (!empty($LANG)) $template->assign("LANG", $LANG); - -//Evite les attaques CSRF -if ($SESS->level > 2 && !empty($_SERVER["HTTP_REFERER"]) && !(preg_match('#^http://'.$_SERVER['HTTP_HOST'].'#', $_SERVER["HTTP_REFERER"]) && defined("xCSRF"))) -{ - elog("Possibilité d'attaque CSRF\n".var_export($_REQUEST, TRUE), 2); - unset($_POST, $_GET); - $_GET = $_POST = array(); -} diff --git a/onyx/include/common/User.class.php b/onyx/include/common/Team.class.php similarity index 100% rename from onyx/include/common/User.class.php rename to onyx/include/common/Team.class.php diff --git a/onyx/include/public/home.php b/onyx/include/public/home.php index 3e8231ad..a1542da3 100644 --- a/onyx/include/public/home.php +++ b/onyx/include/public/home.php @@ -2,16 +2,7 @@ if(!defined('ONYX')) exit; -$t = Team::get_teams(); -foreach ($t as $tt){ - var_dump ($tt->get_username()); -} - -if ($SESS->level < 1) -{ - $page = "public/home"; -} -else -{ - $page = "users/home"; -} +$template->assign("teams", Team::get_teams()); +$template->assign("top", Team::get_top()); + +return "public/home"; diff --git a/onyx/include/public/team.php b/onyx/include/public/team.php new file mode 100644 index 00000000..dfd91661 --- /dev/null +++ b/onyx/include/public/team.php @@ -0,0 +1,16 @@ +assign("team", $team); + + return "public/team"; +} +catch($e) +{ + return "404"; +} diff --git a/onyx/include/team/change.php b/onyx/include/team/change.php new file mode 100644 index 00000000..8a234331 --- /dev/null +++ b/onyx/include/team/change.php @@ -0,0 +1,6 @@ +assign("teams", Team::get_teams()); +$template->assign("top", Team::get_top()); + +return "users/home"; diff --git a/onyx/include/team/summary.php b/onyx/include/team/summary.php new file mode 100644 index 00000000..3ab8aeca --- /dev/null +++ b/onyx/include/team/summary.php @@ -0,0 +1,6 @@ +assign("team", $team); + + return "team/team"; +} +catch($e) +{ + return "404"; +} From 39d5e64ee286c815375754db206eb7f89869d9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Tue, 22 Oct 2013 08:19:51 +0200 Subject: [PATCH 0039/2585] Hotfix: notice in router --- htdocs/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/index.php b/htdocs/index.php index fcd65efe..57e1f8f3 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -10,13 +10,13 @@ if ($_SERVER["SERVER_NAME"] == "localhost" || $_SERVER["SERVER_NAME"] == "fic" | define("DEBUG", true); //Chargement de tout le nécessaire pour le site -//require_once("common.php"); +require_once("common.php"); $n = preg_match_all("#[^/]+#", strtolower(gpc("p")), $out); $p = $out[0]; // Admin part -if ($p[0] == SALT_ADMIN) +if ($n && $p[0] == SALT_ADMIN) { if ($n <= 1) $page = require("admin/home.php"); @@ -43,7 +43,7 @@ if ($p[0] == SALT_ADMIN) } // Known users -else if ($p[0] == SALT_USER) +else if ($n && $p[0] == SALT_USER) { $connected = true; From 0035b984ff7f4cba56aa7b002704fcc86838c3ce Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Tue, 22 Oct 2013 08:31:12 +0200 Subject: [PATCH 0040/2585] Modify feedfortests.sql to match with new DB --- db/feedfortests.sql | 289 +++++++++++++++++--------------------------- 1 file changed, 112 insertions(+), 177 deletions(-) diff --git a/db/feedfortests.sql b/db/feedfortests.sql index d3d24598..36fbafe2 100644 --- a/db/feedfortests.sql +++ b/db/feedfortests.sql @@ -1,4 +1,69 @@ -INSERT INTO `fic2014`.`themes` ( +INSERT INTO `fic`.`users` ( +`id` , +`username` , +`password` , +`auth_level` , +`firstname` , +`lastname` , +`company` +) +VALUES ( +'1', 'Alpha', '2134s65df423sdf132sdg431dsg', '1', 'Alph', 'A', 'Epitra' +), ( +'2', 'Beta', '2134s65df423sef132sdg431dsg', '1', 'Bet', 'A', 'Epitra' +), ( +'3', 'Charli', '2134s45df423sdf132sdg431dsg', '1', 'Charl', 'I', 'Epitra' +), ( +'4', 'Delta', '2134s65df423sdf131sdg431dsg', '1', 'Delt', 'A', 'Epitra' +), ( +'5', 'Echo', '2134s65df423sdf132sdg431dfg', '1', 'Ech', 'O', 'Epitra' +), ( +'6', 'Foxtrot', '2134s65df423shf132sdg431dsg', '1', 'Fox', 'Trot', 'Epitra' +), ( +'7', 'Golf', '2134s65df423sdf1f2sdg431dsg', '1', 'Gol', 'F', 'Epitra' +), ( +'8', 'Hotel', '2134s65df423sdf13zsdg431dsg', '1', 'Hot', 'El', 'Epitra' +), ( +'9', 'India', '2134s65df423sdf13csdg431dsg', '1', 'Ind', 'Ia', 'Epitra' +), ( +'10', 'Juliet', '2134s65df4q3sdf132sdg431dsg', '1', 'Jule', 'Yer', 'Epitra' +), ( +'11', 'Kevlar', '2134s65df423sdf132s2g431dsg', '1', 'Krev', 'Lard', 'Epitra' +), ( +'12', 'Lambda', '2134s65df423sdf132sdg401dsg', '1', 'Lamb', 'Ada', 'Epitra' +), ( +'13' , 'Mike', '2134s65df423sdf132sdg401dsg', '1', 'Mi', 'Ke', 'Epitra' +), ( +'14' , 'November', '2134s65df423sdf132sdg401dsg', '1', 'Nov', 'Ember', 'Epitra' +), ( +'15' , 'Oscar', '2134s65df423sdf132sdg401dsg', '1', 'Os', 'Car', 'Epitra' +), ( +'16' , 'Papa', '2134s65df423sdf132sdg401dsg', '1', 'Pa', 'Pa', 'Epitra' +), ( +'17' , 'Quebec', '2134s65df423sdf132sdg401dsg', '1', 'Que', 'Bec', 'Epitra' +), ( +'18' , 'Romeo', '2134s65df423sdf132sdg401dsg', '1', 'Rom', 'Eo', 'Epitra' +), ( +'19' , 'Sierra', '2134s65df423sdf132sdg401dsg', '1', 'Sier', 'Ra', 'Epitra' +), ( +'20' , 'Tango', '2134s65df423sdf132sdg401dsg', '1', 'Tan', 'Go', 'Epitra' +), ( +'21' , 'Uniform', '2134s65df423sdf132sdg401dsg', '1', 'Uni', 'Form', 'Epitra' +), ( +'22' , 'Victor', '2134s65df423sdf132sdg401dsg', '1', 'Vic', 'Tor', 'Epitra' +), ( +'23' , 'Whiskey', '2134s65df423sdf132sdg401dsg', '1', 'Whis', 'Key', 'Epitra' +), ( +'24' , 'X-ray', '2134s65df423sdf132sdg401dsg', '1', 'X', 'Rey', 'Epitra' +), ( +'25' , 'Yankee', '2134s65df423sdf132sdg401dsg', '1', 'Yan', 'Kee', 'Epitra' +), ( +'26' , 'Zulu', '2134s65df423sdf132sdg401dsg', '1', 'Zul', 'Lu', 'Epitra' +), ( +'27' , 'Zero', '2134s65df423sdf132sdg401dsg', '1', 'Ze', 'Ro', 'Epitra' +); + +INSERT INTO `fic`.`themes` ( `id` , `filename` ) @@ -20,187 +85,57 @@ VALUES ( '8' , 'pcap.xml' ); -INSERT INTO `fic2014`.`users` ( -`id` , -`username` , -`password` , -`auth_level` -) -VALUES ( -'1' , 'Alpha', UNHEX( '' ) , '1' -), ( -'2' , 'Bravo', UNHEX( '' ) , '1' -), ( -'3' , 'Charlie', UNHEX( '' ) , '1' -), ( -'4' , 'Delta', UNHEX( '' ) , '1' -), ( -'5' , 'Echo', UNHEX( '' ) , '1' -), ( -'6' , 'Foxtrot', UNHEX( '' ) , '1' -), ( -'7' , 'Golf', UNHEX( '' ) , '1' -), ( -'8' , 'Hotel', UNHEX( '' ) , '1' -), ( -'9' , 'India', UNHEX( '' ) , '1' -), ( -'10' , 'Juliet', UNHEX( '' ) , '1' -), ( -'11' , 'Kilo', UNHEX( '' ) , '1' -), ( -'12' , 'Lima', UNHEX( '' ) , '1' -), ( -'13' , 'Mike', UNHEX( '' ) , '1' -), ( -'14' , 'November', UNHEX( '' ) , '1' -), ( -'15' , 'Oscar', UNHEX( '' ) , '1' -), ( -'16' , 'Papa', UNHEX( '' ) , '1' -), ( -'17' , 'Quebec', UNHEX( '' ) , '1' -), ( -'18' , 'Romeo', UNHEX( '' ) , '1' -), ( -'19' , 'Sierra', UNHEX( '' ) , '1' -), ( -'20' , 'Tango', UNHEX( '' ) , '1' -), ( -'21' , 'Uniform', UNHEX( '' ) , '1' -), ( -'22' , 'Victor', UNHEX( '' ) , '1' -), ( -'23' , 'Whiskey', UNHEX( '' ) , '1' -), ( -'24' , 'X-ray', UNHEX( '' ) , '1' -), ( -'25' , 'Yankee', UNHEX( '' ) , '1' -), ( -'26' , 'Zulu', UNHEX( '' ) , '1' -), ( -'27' , 'Zero', UNHEX( '' ) , '1' -); - -INSERT INTO `fic2014`.`exercices` ( +INSERT INTO `fic`.`exercices` ( `id` , `id_theme` , -`points` +`require` , +`level` , +`points` , +`statement` ) VALUES -('1', '1', '1'), -('2', '1', '5'), -('3', '1', '10'), -('4', '1', '20'), -('5', '1', '40'), -('6', '2', '1'), -('7', '2', '5'), -('8', '2', '10'), -('9', '2', '20'), -('10', '2', '40'), -('11', '3', '1'), -('12', '3', '5'), -('13', '3', '10'), -('14', '3', '20'), -('15', '3', '40'), -('16', '4', '1'), -('17', '4', '5'), -('18', '4', '10'), -('19', '4', '20'), -('20', '4', '40'), -('21', '5', '1'), -('22', '5', '5'), -('23', '5', '10'), -('24', '5', '20'), -('25', '5', '40'), -('26', '6', '1'), -('27', '6', '5'), -('28', '6', '10'), -('29', '6', '20'), -('30', '6', '40'), -('31', '7', '1'), -('32', '7', '5'), -('33', '7', '10'), -('34', '7', '20'), -('35', '7', '40'), -('36', '8', '1'), -('37', '8', '5'), -('38', '8', '10'), -('39', '8', '20'), -('40', '8', '40'); +('1', '1', '', '1', '1', 'Description 1'), +('2', '1', '1', '2', '5', 'Description 2'), +('3', '1', '2', '3', '10', 'Description 3'), +('4', '1', '3', '4', '20', 'Description 4'), +('5', '1', '4', '5', '40', 'Description 5'), +('6', '2', '', '1', '1', 'Description 6'), +('7', '2', '6', '2', '5', 'Description 7'), +('8', '2', '7', '3', '10', 'Description 8'), +('9', '2', '8', '4', '20', 'Description 9'), +('10', '2', '9', '5', '40', 'Description 10'), +('11', '3', '', '1', '1', 'Description 11'), +('12', '3', '11', '2', '5', 'Description 12'), +('13', '3', '12', '3', '10', 'Description 13'), +('14', '3', '13', '4', '20', 'Description 14'), +('15', '3', '14', '5', '40', 'Description 15'), +('16', '4', '', '1', '1', 'Description 16'), +('17', '4', '16', '2', '5', 'Description 17'), +('18', '4', '17', '3', '10', 'Description 18'), +('19', '4', '18', '4', '20', 'Description 19'), +('20', '4', '19', '5', '40', 'Description 20'), +('21', '5', '', '1', '1', 'Description 21'), +('22', '5', '21', '2', '5', 'Description 22'), +('23', '5', '22', '3', '10', 'Description 23'), +('24', '5', '23', '4', '20', 'Description 24'), +('25', '5', '24', '5', '40', 'Description 25'), +('26', '6', '', '1', '1', 'Description 26'), +('27', '6', '26', '2', '5', 'Description 27'), +('28', '6', '27', '3', '10', 'Description 28'), +('29', '6', '28', '4', '20', 'Description 29'), +('30', '6', '29', '5', '40', 'Description 30'), +('31', '7', '', '1', '1', 'Description 31'), +('32', '7', '30', '2', '5', 'Description 32'), +('33', '7', '31', '3', '10', 'Description 33'), +('34', '7', '32', '4', '20', 'Description 34'), +('35', '7', '33', '5', '40', 'Description 35'), +('36', '8', '', '1', '1', 'Description 36'), +('37', '8', '35', '2', '5', 'Description 37'), +('38', '8', '36', '3', '10', 'Description 38'), +('39', '8', '37', '4', '20', 'Description 39'), +('40', '8', '38', '5', '40', 'Description 40'); -INSERT INTO `fic2014`.`exercice_dependancies` ( -`id` , -`id_exercice` , -`id_dependence` -) -VALUES ( -'1', '2', '1' -), ( -'2', '3', '2' -), ( -'3', '4', '3' -), ( -'4', '5', '4' -), ( -'5', '7', '6' -), ( -'6', '8', '7' -), ( -'7', '9', '8' -), ( -'8', '10', '9' -), ( -'9', '12', '11' -), ( -'10', '13', '12' -), ( -'11', '14', '13' -), ( -'12', '15', '14' -), ( -'13', '17', '16' -), ( -'14', '18', '17' -), ( -'15', '19', '18' -), ( -'16', '20', '19' -), ( -'17', '22', '21' -), ( -'18', '23', '22' -), ( -'19', '24', '23' -), ( -'20', '25', '24' -), ( -'21', '27', '26' -), ( -'22', '28', '27' -), ( -'23', '29', '28' -), ( -'24', '30', '29' -), ( -'25', '32', '31' -), ( -'26', '33', '32' -), ( -'27', '34', '33' -), ( -'28', '35', '34' -), ( -'29', '37', '36' -), ( -'30', '38', '37' -), ( -'31', '39', '38' -), ( -'32', '40', '39' -); - -INSERT INTO `fic2014`.`solved` ( +INSERT INTO `fic`.`solved` ( `id` , `id_user` , `id_exercice` , From a767c4d900b1d5366d29ed05b7b921990e68a5e1 Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Tue, 22 Oct 2013 08:56:38 +0200 Subject: [PATCH 0041/2585] Correct some bugs in Team class. --- onyx/include/common/Team.class.php | 34 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 8ad7e448..1bf78e85 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -2,6 +2,16 @@ if(!defined('ONYX')) exit; +function cmp_team_pts($i1, $i2) +{ + if ($i1->get_pts() == $i2->get_pts()){ + return 0; + } + else{ + return ($i1->get_pts() < $i2->get_pts()) ? 1 : -1; + } +} + class Team { var $id = null; @@ -24,6 +34,7 @@ class Team if (!empty($res)) { + $this->id = $res['id']; $this->firstname = $res['firstname']; $this->lastname = $res['lastname']; $this->username = $res['username']; @@ -94,15 +105,16 @@ class Team function get_pts() { - if(isset($this->points)) + if(!isset($this->points)) { $db = new BDD(); - $res = $db->query("SELECT e.id, s.id_user, SUM(e.points) as sum_points + $res = $db->unique_query("SELECT e.id, s.id_user, SUM(e.points) as sum_points FROM exercices e LEFT OUTER JOIN solved s ON e.id = s.id_exercice - WHERE s.id_user = " . intval($this->id) . " + WHERE s.id_user = " . $this->id . " GROUP BY s.id_user"); + $db->deconnexion(); if (!empty($res)) @@ -110,6 +122,8 @@ class Team $this->points = $res['sum_points']; } } + + return $this->points; } function get_groupIds() @@ -145,19 +159,9 @@ class Team // TODO: Not tested, need feeding BDD public static function get_top() { - function cmp($i1, $i2) - { - if ($i1->get_pts() == $i2->get_pts()){ - return 0; - } - else{ - return ($i1->get_pts() < $i2->get_pts) ? -1 : 1; - } - } - - $teams = $this->get_teams(); + $teams = Team::get_teams(); - usort($teams, "cmp"); + usort($teams, "cmp_team_pts"); return $teams; } From 9c3173c6823786183de31027c3c495df837ea1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Wed, 23 Oct 2013 21:32:17 +0200 Subject: [PATCH 0042/2585] Fix User -> Team --- onyx/include/common/Team.class.php | 67 +++++++++++++++--------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 1bf78e85..4debbf23 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -15,13 +15,11 @@ function cmp_team_pts($i1, $i2) class Team { var $id = null; - var $firstname; - var $lastname; - var $username; - var $company; + var $key_hash; var $auth_level; + var $company; + var $members = null; var $points = null; - var $nb_themes = null; // Constructor function Team ($id=null) @@ -29,15 +27,13 @@ class Team if (!empty($id)) { $db = new BDD(); - $res = $db->unique_query("SELECT id, firstname, lastname, username, company, auth_level - FROM users WHERE id=" . intval($id)); + $res = $db->unique_query("SELECT id, key_hash, company, auth_level + FROM teams WHERE id=" . intval($id)) or die($db->erreur()); if (!empty($res)) { $this->id = $res['id']; - $this->firstname = $res['firstname']; - $this->lastname = $res['lastname']; - $this->username = $res['username']; + $this->key_hash = $res['key_hash']; $this->company = $res['company']; $this->auth_level = $res['auth_level']; } @@ -48,29 +44,25 @@ class Team // Class methods function update() { - $username = $this->username; + $key_hash = $this->key_hash; $auth_level = intval($this->auth_level); - $firstname = $this->firstname; - $lastname = $this->lastname; $company = $this->company; $db = new BDD(); - $db->escape($username); - $db->escape($firstname); - $db->escape($lastname); + $db->escape($key_hash); $db->escape($company); if (empty($this->id)) { - $db->query("INSERT INTO users - VALUES (NULL, '".$username."', 0x0, ".$auth_level.", '".$firstname."', '".$lastname."', '".$company."')"); + $db->query("INSERT INTO teams + VALUES (NULL, '".$key_hash."', ".$auth_level.", '".$company."')"); $this->id = $db->insert_id(); $aff = ($this->id > 0); } else { $db->query("UPDATE users - SET username = '".$username."', auth_level = '".$auth_level."', firstname = '".$firstname."', lastname = '".$lastname."', company = '".$company."' + SET auth_level = ".$auth_level.", key_hash = '".$key_hash."', company = '".$company."' WHERE id = ".intval($this->id)); $aff = $db->affected(); } @@ -83,18 +75,6 @@ class Team return $this->id; } - function get_firstname() { - return $this->firstname; - } - - function get_lastname() { - return $this->lastname; - } - - function get_username() { - return $this->username; - } - function get_company() { return $this->company; } @@ -103,6 +83,25 @@ class Team return $this->auth_level; } + function get_members() + { + if(!isset($this->members)) + { + $db = new BDD(); + + $res = $db->query("SELECT id, firstname, lastname, nickname + FROM team_members + WHERE id_team = " . intval($this->id)); + + $db->deconnexion(); + + if (!empty($res)) + $this->members = $res; + } + + return $this->members; + } + function get_pts() { if(!isset($this->points)) @@ -145,7 +144,7 @@ class Team public static function get_teams() { $db = new BDD(); - $ids = $db->query("SELECT `id` FROM `users`"); + $ids = $db->query("SELECT `id` FROM `teams`"); $db->deconnexion(); $array = array(); @@ -160,9 +159,9 @@ class Team public static function get_top() { $teams = Team::get_teams(); - + usort($teams, "cmp_team_pts"); return $teams; } -} \ No newline at end of file +} From 8a39c734fb11af87469355d333f9b7124613f055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Wed, 23 Oct 2013 21:36:06 +0200 Subject: [PATCH 0043/2585] New db schema --- db/fic2014.sql | 91 +++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/db/fic2014.sql b/db/fic2014.sql index 63dda3bd..0dfd2dd5 100644 --- a/db/fic2014.sql +++ b/db/fic2014.sql @@ -1,39 +1,39 @@ -- phpMyAdmin SQL Dump --- version 3.5.1 +-- version 4.0.5 -- http://www.phpmyadmin.net -- --- Client: localhost --- Généré le: Mer 09 Octobre 2013 à 23:52 --- Version du serveur: 5.5.32-log --- Version de PHP: 5.5.0-pl0-gentoo +-- Host: localhost +-- Generation Time: Oct 23, 2013 at 07:34 PM +-- Server version: 5.1.70-log +-- PHP Version: 5.5.4-pl0-gentoo -SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; -- --- Base de données: `fic2014` +-- Database: `fic2014` -- -- -------------------------------------------------------- -- --- Structure de la table `exercices` +-- Table structure for table `exercices` -- CREATE TABLE IF NOT EXISTS `exercices` ( - `id` varchar(100) COLLATE utf16_unicode_ci NOT NULL, + `id` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `id_theme` int(10) unsigned NOT NULL, - `require` varchar(100) COLLATE utf16_unicode_ci NOT NULL, + `require` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `level` tinyint(4) NOT NULL, `points` smallint(6) NOT NULL, - `statement` text COLLATE utf16_unicode_ci NOT NULL, + `statement` text COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- -------------------------------------------------------- -- --- Structure de la table `exercice_files` +-- Table structure for table `exercice_files` -- CREATE TABLE IF NOT EXISTS `exercice_files` ( @@ -48,7 +48,7 @@ CREATE TABLE IF NOT EXISTS `exercice_files` ( -- -------------------------------------------------------- -- --- Structure de la table `exercice_keys` +-- Table structure for table `exercice_keys` -- CREATE TABLE IF NOT EXISTS `exercice_keys` ( @@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS `exercice_keys` ( -- -------------------------------------------------------- -- --- Structure de la table `sessions` +-- Table structure for table `sessions` -- CREATE TABLE IF NOT EXISTS `sessions` ( @@ -79,7 +79,7 @@ CREATE TABLE IF NOT EXISTS `sessions` ( -- -------------------------------------------------------- -- --- Structure de la table `solved` +-- Table structure for table `solved` -- CREATE TABLE IF NOT EXISTS `solved` ( @@ -88,38 +88,45 @@ CREATE TABLE IF NOT EXISTS `solved` ( `id_exercice` int(10) unsigned NOT NULL, `time` datetime NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=1 ; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; -- -------------------------------------------------------- -- --- Structure de la table `themes` +-- Table structure for table `teams` +-- + +CREATE TABLE IF NOT EXISTS `teams` ( + `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `key_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `auth_level` tinyint(1) NOT NULL, + `company` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `team_members` +-- + +CREATE TABLE IF NOT EXISTS `team_members` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_team` int(10) unsigned NOT NULL, + `firstname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `lastname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `nickname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `themes` -- CREATE TABLE IF NOT EXISTS `themes` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `filename` varchar(255) COLLATE utf16_unicode_ci NOT NULL, + `filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=1 ; - --- -------------------------------------------------------- - --- --- Structure de la table `users` --- - -CREATE TABLE IF NOT EXISTS `users` ( - `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, - `username` varchar(255) COLLATE utf16_unicode_ci NOT NULL, - `password` binary(64) NOT NULL, - `auth_level` tinyint(1) NOT NULL, - `firstname` varchar(255) COLLATE utf16_unicode_ci NOT NULL, - `lastname` varchar(255) COLLATE utf16_unicode_ci NOT NULL, - `company` varchar(255) COLLATE utf16_unicode_ci NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_unicode_ci AUTO_INCREMENT=2 ; - - -INSERT INTO users (username, password, auth_level) -VALUES -("nemunaire", UNHEX('c1d050d16d8c90dae6fef376460299aa8d1cce7c5b299720a8e38952a77212f1019e2cd44ba58e0433c01cb4c81ab9a789c07df218b0b9f05af8d1198a3bd239'), 2); +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; From 5abb9d8713d10f2f96da3eef5733f02114b92045 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Thu, 24 Oct 2013 17:40:12 +0200 Subject: [PATCH 0044/2585] Deleted login.php, login.tpl, login.css --- htdocs/css/login.css | 37 ----------------------------- onyx/include/public/login.php | 29 ---------------------- onyx/tpl/bootstrap/public/login.tpl | 18 -------------- 3 files changed, 84 deletions(-) delete mode 100644 htdocs/css/login.css delete mode 100644 onyx/include/public/login.php delete mode 100644 onyx/tpl/bootstrap/public/login.tpl diff --git a/htdocs/css/login.css b/htdocs/css/login.css deleted file mode 100644 index f7bf2623..00000000 --- a/htdocs/css/login.css +++ /dev/null @@ -1,37 +0,0 @@ -body { - padding-top: 40px; - background-color: #eee; -} - -.form-signin { - max-width: 330px; - padding: 15px; - margin: 0 auto; -} -.form-signin .form-signin-heading, - -.form-signin .checkbox { - font-weight: normal; -} -.form-signin .form-control { - position: relative; - font-size: 16px; - height: auto; - padding: 10px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.form-signin .form-control:focus { - z-index: 2; -} -.form-signin input[type="text"] { - margin-bottom: -1px; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} -.form-signin input[type="password"] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; -} diff --git a/onyx/include/public/login.php b/onyx/include/public/login.php deleted file mode 100644 index 1b22cbac..00000000 --- a/onyx/include/public/login.php +++ /dev/null @@ -1,29 +0,0 @@ -escape($username); - $bdd->escape($password); - $hash = mdp($username, $password); - $result = $bdd->unique_query("SELECT id, username, auth_level FROM users - WHERE username='$username' - AND password=unhex('$hash')"); - - if (!empty($result) && $result['auth_level'] != 0) - { - $SESS->level = $result["auth_level"]; - $SESS->values = $result; - $SESS->put($result["id"]); - header("Location: /home"); - exit; - } -} - -$page = "public/login"; diff --git a/onyx/tpl/bootstrap/public/login.tpl b/onyx/tpl/bootstrap/public/login.tpl deleted file mode 100644 index 59a794ee..00000000 --- a/onyx/tpl/bootstrap/public/login.tpl +++ /dev/null @@ -1,18 +0,0 @@ -{extends file="layout-nav.tpl"} - -{block name=head} - -{/block} - -{block name=content} - -
- -
- -{/block} From 026660aa2ffb4a6581565457278c7a05bfb77c8d Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sat, 26 Oct 2013 02:49:38 +0200 Subject: [PATCH 0045/2585] Add script for certs --- misc/certs/CA.sh | 49 ++++++ misc/certs/openssl.cnf | 352 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 401 insertions(+) create mode 100755 misc/certs/CA.sh create mode 100644 misc/certs/openssl.cnf diff --git a/misc/certs/CA.sh b/misc/certs/CA.sh new file mode 100755 index 00000000..f8378fc1 --- /dev/null +++ b/misc/certs/CA.sh @@ -0,0 +1,49 @@ +# Create CA for client +#openssl genrsa -des3 -out ca.key 4096 +#openssl req -new -x509 -days 365 -key ca.key -out ca.crt +# +## Server cert +#openssl genrsa -des3 -out server.key 2028 +#openssl req -new -key server.key -out server.csr +# +## Self sign ?? +#openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt + +# TODO serial +# TODO common name + +OPENSSL_CONF=openssl.cnf + +[ $# -ne 1 ] && echo "Usage: $0 init + client NAME" + +case $1 in + "init" ) + echo "Create CA for signing client certs" + openssl genrsa -des3 -out ca.key 4096 + sed -i 's/=.*#CommonName/= FIC2014 CA#CommonNameEnd/' $OPENSSL_CONF + openssl req -batch -new -x509 -days 365 -key ca.key -out ca.crt + + echo "Create server cert" + openssl genrsa -des3 -out server.key 2048 + sed -i 's/=.*#CommonNameEnd/= FIC2014 Server#CommonNameEnd/' $OPENSSL_CONF + openssl req -batch -new -key server.key -out server.csr + openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt + rm server.csr + ;; + "client" ) + [ $# -ne 2 ] && "client Usage" + openssl genrsa -des3 -out client.key 2048 + sed -i "s/=.*#CommonNameEnd/= $2#CommonNameEnd/" $OPENSSL_CONF + openssl req -batch -new -key client.key -out client.csr + openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt + openssl pkcs12 -export -inkey client.key -in client.crt -name $2 -out ${2}.p12 + + rm client.key + rm client.csr + rm client.crt + ;; + "*" ) + echo "*" + ;; +esac diff --git a/misc/certs/openssl.cnf b/misc/certs/openssl.cnf new file mode 100644 index 00000000..d7afe95d --- /dev/null +++ b/misc/certs/openssl.cnf @@ -0,0 +1,352 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = /etc/ssl # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France + +localityName = Locality Name (eg, city) +localityName_default = Paris + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Epita + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = SRS + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_default = tata#CommonNameEndEndEndEndEnd +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) From 30135b4c6e1617e64b27141e56c5beafd649e2fb Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sat, 26 Oct 2013 02:49:59 +0200 Subject: [PATCH 0046/2585] Add install script --- misc/init_db.sql | 2 ++ misc/install.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ misc/server.conf | 5 ++++ 3 files changed, 75 insertions(+) create mode 100644 misc/init_db.sql create mode 100755 misc/install.sh create mode 100644 misc/server.conf diff --git a/misc/init_db.sql b/misc/init_db.sql new file mode 100644 index 00000000..e2ca05e8 --- /dev/null +++ b/misc/init_db.sql @@ -0,0 +1,2 @@ +DROP DATABASE IF EXISTS fic2014; +CREATE DATABASE fic2014; diff --git a/misc/install.sh b/misc/install.sh new file mode 100755 index 00000000..ede53942 --- /dev/null +++ b/misc/install.sh @@ -0,0 +1,68 @@ +#! /bin/sh + +# Install FIC 2014 server + +# Depends: +# +# nginx 1.4.3 +# openssh 6.3p1-1 +# iptables 1.4.19.1-1 +# mariadb 5.5.33.a-1 + +# Exit values +# 0 Everything is good +# 1 +# 2 File not found +# 3 Service not running + +# By default the config dir is .. +DIR=${PWD%/*} +CONF="server.conf" +BASENAME=`basename $0` +FULL_INSTALL=false + +display_help() +{ + # By default install only config files + # --full: install package, enable services, install config + echo "Usage: $BASENAME [--full] (alpha|beta)" + exit 1 +} + +HTTP_DIR="" +DB_TYPE="" +DB_NAME="" +DB_USER="" +DB_PASS="" + +parse_conf() +{ + if ! [ -f $CONF ]; then + echo "The configuration file: " $CONF " not found" + exit 2 + fi + HTTP_DIR=$(sed -n 's/[ \t]*http_root[ \t]*=[ \t]*\(.*\)[ \t]*/\1/p' $CONF) + DB_TYPE=$(sed -n 's/[ \t]*db_type[ \t]*=[ \t]*\(.*\)[ \t]*/\1/p' $CONF) + DB_NAME=$(sed -n 's/[ \t]*db_name[ \t]*=[ \t]*\(.*\)[ \t]*/\1/p' $CONF) + DB_USER=$(sed -n 's/[ \t]*db_user[ \t]*=[ \t]*\(.*\)[ \t]*/\1/p' $CONF) + DB_PASS=$(sed -n 's/[ \t]*db_pass[ \t]*=[ \t]*\(.*\)[ \t]*/\1/p' $CONF) +} + +INIT_DB="init_db.sql" + +init_db() +{ + if ! [ -f $INIT_DB ]; then + echo "The configuration file " $INIT_DB " not found" + exit 2 + fi + + if ! [ -S /var/run/mysqld/mysqld.sock ]; then + echo "The mysqld service is not running" + exit 3 + fi +} + +[ $# -ne 1 ] && display_help + +parse_conf diff --git a/misc/server.conf b/misc/server.conf new file mode 100644 index 00000000..c9ec3d86 --- /dev/null +++ b/misc/server.conf @@ -0,0 +1,5 @@ +http_root=/srv/http/fic2014-server +db_type=mysql +db_name=fic +db_user=toto +db_pass=toto42 From 7571c8c1b12655650dc1edae3271a381ec9b50b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 26 Oct 2013 08:56:06 +0200 Subject: [PATCH 0047/2585] Move directory tpl users to teams --- onyx/include/team/exercice.php | 2 +- onyx/include/team/home.php | 2 +- onyx/include/team/{change.php => me.php} | 2 +- onyx/include/team/summary.php | 2 +- onyx/include/team/team.php | 2 +- onyx/tpl/bootstrap/{users => teams}/home.tpl | 0 6 files changed, 5 insertions(+), 5 deletions(-) rename onyx/include/team/{change.php => me.php} (61%) rename onyx/tpl/bootstrap/{users => teams}/home.tpl (100%) diff --git a/onyx/include/team/exercice.php b/onyx/include/team/exercice.php index d8ace4ea..84856f02 100644 --- a/onyx/include/team/exercice.php +++ b/onyx/include/team/exercice.php @@ -3,4 +3,4 @@ if(!defined('ONYX')) exit; -return "team/exercice"; +return "teams/exercice"; diff --git a/onyx/include/team/home.php b/onyx/include/team/home.php index 7521d39f..eaa60a72 100644 --- a/onyx/include/team/home.php +++ b/onyx/include/team/home.php @@ -5,4 +5,4 @@ if(!defined('ONYX')) exit; $template->assign("teams", Team::get_teams()); $template->assign("top", Team::get_top()); -return "users/home"; +return "teams/home"; diff --git a/onyx/include/team/change.php b/onyx/include/team/me.php similarity index 61% rename from onyx/include/team/change.php rename to onyx/include/team/me.php index 8a234331..bf209f06 100644 --- a/onyx/include/team/change.php +++ b/onyx/include/team/me.php @@ -3,4 +3,4 @@ if(!defined('ONYX')) exit; -return "team/change"; +return "teams/change"; diff --git a/onyx/include/team/summary.php b/onyx/include/team/summary.php index 3ab8aeca..62a22790 100644 --- a/onyx/include/team/summary.php +++ b/onyx/include/team/summary.php @@ -3,4 +3,4 @@ if(!defined('ONYX')) exit; -return "team/summary"; +return "teams/summary"; diff --git a/onyx/include/team/team.php b/onyx/include/team/team.php index dcc68e71..98333fdc 100644 --- a/onyx/include/team/team.php +++ b/onyx/include/team/team.php @@ -8,7 +8,7 @@ try $template->assign("team", $team); - return "team/team"; + return "teams/team"; } catch($e) { diff --git a/onyx/tpl/bootstrap/users/home.tpl b/onyx/tpl/bootstrap/teams/home.tpl similarity index 100% rename from onyx/tpl/bootstrap/users/home.tpl rename to onyx/tpl/bootstrap/teams/home.tpl From f8eff22c225c88dc88f24198c002d404fc275b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 26 Oct 2013 08:59:59 +0200 Subject: [PATCH 0048/2585] Public part: home and team part --- htdocs/index.php | 12 +++++++----- onyx/include/public/team.php | 2 +- onyx/tpl/bootstrap/public/home.tpl | 5 +++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/htdocs/index.php b/htdocs/index.php index 57e1f8f3..50a4aeb4 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -12,6 +12,9 @@ if ($_SERVER["SERVER_NAME"] == "localhost" || $_SERVER["SERVER_NAME"] == "fic" | //Chargement de tout le nécessaire pour le site require_once("common.php"); +$template->assign("SALT_USER",SALT_USER); +$template->assign("SALT_ADMIN",SALT_ADMIN); + $n = preg_match_all("#[^/]+#", strtolower(gpc("p")), $out); $p = $out[0]; @@ -46,7 +49,6 @@ if ($n && $p[0] == SALT_ADMIN) else if ($n && $p[0] == SALT_USER) { $connected = true; - if ($n <= 1) $page = require("team/home.php"); else @@ -59,9 +61,9 @@ else if ($n && $p[0] == SALT_USER) { switch($p[2]) { - case "change/": - case "change": - $page = require("team/change.php"); + case "me/": + case "me": + $page = require("team/me.php"); break; case "summary": @@ -92,7 +94,7 @@ else $page = require("public/home.php"); else if ($n == 1) { - $TEAM = $p[0]; + $TEAM = intval(substr($p[0], 0, strpos($p[0], "-"))); $page = require("public/team.php"); } diff --git a/onyx/include/public/team.php b/onyx/include/public/team.php index dfd91661..71ccb620 100644 --- a/onyx/include/public/team.php +++ b/onyx/include/public/team.php @@ -10,7 +10,7 @@ try return "public/team"; } -catch($e) +catch(Exception $e) { return "404"; } diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index 68369382..fb80872d 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -3,4 +3,9 @@

Hello World!

+{foreach from=$teams item=i} + +{/foreach} {/block} From 867d1d6f74944dc42598af49fe56956cf5dc4a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 26 Oct 2013 09:00:21 +0200 Subject: [PATCH 0049/2585] Connected: fix top bar menu --- onyx/tpl/bootstrap/layout-nav.tpl | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/onyx/tpl/bootstrap/layout-nav.tpl b/onyx/tpl/bootstrap/layout-nav.tpl index 15f488ba..446e46f3 100644 --- a/onyx/tpl/bootstrap/layout-nav.tpl +++ b/onyx/tpl/bootstrap/layout-nav.tpl @@ -9,21 +9,13 @@ - FIC + FIC
From 73e1e8f127d0173c55f63d618ba5e0efc6add04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 26 Oct 2013 09:04:22 +0200 Subject: [PATCH 0050/2585] DB: theme require a name, not filename --- db/fic2014.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/fic2014.sql b/db/fic2014.sql index 0dfd2dd5..ec666486 100644 --- a/db/fic2014.sql +++ b/db/fic2014.sql @@ -127,6 +127,6 @@ CREATE TABLE IF NOT EXISTS `team_members` ( CREATE TABLE IF NOT EXISTS `themes` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; From c27a97ce6e1e0bcd5e513706df9a97c9ff004262 Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Sat, 26 Oct 2013 15:38:43 +0200 Subject: [PATCH 0051/2585] BDD: add 'teamname' and change feedfortest.sql --- db/feedfortests.sql | 103 ++++++++++++++++++++++++++++++-------------- db/fic2014.sql | 1 + 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/db/feedfortests.sql b/db/feedfortests.sql index 36fbafe2..b370d694 100644 --- a/db/feedfortests.sql +++ b/db/feedfortests.sql @@ -1,71 +1,108 @@ -INSERT INTO `fic`.`users` ( +INSERT INTO `fic`.`teams` ( `id` , -`username` , -`password` , +`team_name` , +`key_hash` , `auth_level` , -`firstname` , -`lastname` , `company` ) VALUES ( -'1', 'Alpha', '2134s65df423sdf132sdg431dsg', '1', 'Alph', 'A', 'Epitra' +'1', 'Team1', '2134s65df423sdf132sdg431dsg', '1', 'Epita' ), ( -'2', 'Beta', '2134s65df423sef132sdg431dsg', '1', 'Bet', 'A', 'Epitra' +'2', 'Team2', '2134s65df423sef132sdg431dsg', '1', 'Epita' ), ( -'3', 'Charli', '2134s45df423sdf132sdg431dsg', '1', 'Charl', 'I', 'Epitra' +'3', 'Team3', '2134s45df423sdf132sdg431dsg', '1', 'Epita' ), ( -'4', 'Delta', '2134s65df423sdf131sdg431dsg', '1', 'Delt', 'A', 'Epitra' +'4', 'Team4', '2134s65df423sdf131sdg431dsg', '1', 'Epita' ), ( -'5', 'Echo', '2134s65df423sdf132sdg431dfg', '1', 'Ech', 'O', 'Epitra' +'5', 'Team5', '2134s65df423sdf132sdg431dfg', '1', 'Epita' ), ( -'6', 'Foxtrot', '2134s65df423shf132sdg431dsg', '1', 'Fox', 'Trot', 'Epitra' +'6', 'Team6', '2134s65df423shf132sdg431dsg', '1', 'Epita' ), ( -'7', 'Golf', '2134s65df423sdf1f2sdg431dsg', '1', 'Gol', 'F', 'Epitra' +'7', 'Team7', '2134s65df423sdf1f2sdg431dsg', '1', 'Epita' ), ( -'8', 'Hotel', '2134s65df423sdf13zsdg431dsg', '1', 'Hot', 'El', 'Epitra' +'8', 'Team8', '2134s65df423sdf13zsdg431dsg', '1', 'Epita' ), ( -'9', 'India', '2134s65df423sdf13csdg431dsg', '1', 'Ind', 'Ia', 'Epitra' +'9', 'Team9', '2134s65df423sdf13csdg431dsg', '1', 'Epita' ), ( -'10', 'Juliet', '2134s65df4q3sdf132sdg431dsg', '1', 'Jule', 'Yer', 'Epitra' +'10', 'Team10', '2134s65df4q3sdf132sdg431dsg', '1', 'Epita' ), ( -'11', 'Kevlar', '2134s65df423sdf132s2g431dsg', '1', 'Krev', 'Lard', 'Epitra' +'11', 'Team11', '2134s65df423sdf132s2g431dsg', '1', 'Epita' ), ( -'12', 'Lambda', '2134s65df423sdf132sdg401dsg', '1', 'Lamb', 'Ada', 'Epitra' +'12', 'Team12', '2134s65df423sdf132sdg401dsg', '1', 'Epita' ), ( -'13' , 'Mike', '2134s65df423sdf132sdg401dsg', '1', 'Mi', 'Ke', 'Epitra' +'13' , 'Team13', '2134s65df423sdf132sdg401dsg', '1', 'Epita' ), ( -'14' , 'November', '2134s65df423sdf132sdg401dsg', '1', 'Nov', 'Ember', 'Epitra' +'14' , 'Team14', '2134s65df423sdf132sdg401dsg', '1', 'Epita' ), ( -'15' , 'Oscar', '2134s65df423sdf132sdg401dsg', '1', 'Os', 'Car', 'Epitra' +'15' , 'Team15', '2134s65df423sdf132sdg401dsg', '1', 'Epita' +); + +INSERT INTO `fic`.`team_members` ( +`id` , +`id_team` , +`firstname` , +`lastname` , +`nickname` +) +VALUES ( +'1', '1', 'Alph', 'A', 'Alominia' ), ( -'16' , 'Papa', '2134s65df423sdf132sdg401dsg', '1', 'Pa', 'Pa', 'Epitra' +'2', '1', 'Bet', 'A', 'CaptainSandwich' ), ( -'17' , 'Quebec', '2134s65df423sdf132sdg401dsg', '1', 'Que', 'Bec', 'Epitra' +'3', '2', 'Charl', 'I', 'Tintin' ), ( -'18' , 'Romeo', '2134s65df423sdf132sdg401dsg', '1', 'Rom', 'Eo', 'Epitra' +'4', '2', 'Delt', 'A', 'Wolwerin' ), ( -'19' , 'Sierra', '2134s65df423sdf132sdg401dsg', '1', 'Sier', 'Ra', 'Epitra' +'5', '3', 'Ech', 'O', 'Homer' ), ( -'20' , 'Tango', '2134s65df423sdf132sdg401dsg', '1', 'Tan', 'Go', 'Epitra' +'6', '3', 'Fox', 'Trot', 'KevBG91' ), ( -'21' , 'Uniform', '2134s65df423sdf132sdg401dsg', '1', 'Uni', 'Form', 'Epitra' +'7', '4', 'Gol', 'F', 'R2D2' ), ( -'22' , 'Victor', '2134s65df423sdf132sdg401dsg', '1', 'Vic', 'Tor', 'Epitra' +'8', '4', 'Hot', 'El', 'Corbaine' ), ( -'23' , 'Whiskey', '2134s65df423sdf132sdg401dsg', '1', 'Whis', 'Key', 'Epitra' +'9', '5', 'Ind', 'Ia', 'Lelama' ), ( -'24' , 'X-ray', '2134s65df423sdf132sdg401dsg', '1', 'X', 'Rey', 'Epitra' +'10', '5', 'Jule', 'Yer', 'Betrave' ), ( -'25' , 'Yankee', '2134s65df423sdf132sdg401dsg', '1', 'Yan', 'Kee', 'Epitra' +'11', '6', 'Krev', 'Lard', 'BlueSunday' ), ( -'26' , 'Zulu', '2134s65df423sdf132sdg401dsg', '1', 'Zul', 'Lu', 'Epitra' +'12', '6', 'Lamb', 'Ada', 'Chatpitre' ), ( -'27' , 'Zero', '2134s65df423sdf132sdg401dsg', '1', 'Ze', 'Ro', 'Epitra' +'13' , '7', 'Mi', 'Ke', 'Tournewsol' +), ( +'14' , '7', 'Nov', 'Ember', 'Dasilva' +), ( +'15' , '8', 'Os', 'Car', 'Laurie' +), ( +'16' , '8', 'Pa', 'Pa', 'Nowel' +), ( +'17' , '9', 'Que', 'Bec', 'Polyr' +), ( +'18' , '9', 'Rom', 'Eo', 'Granola' +), ( +'19' , '10', 'Sier', 'Ra', 'Petilus75' +), ( +'20' , '11', 'Tan', 'Go', 'Lolilol42' +), ( +'21' , '12', 'Uni', 'Form', 'JmLayfrite' +), ( +'22' , '13', 'Vic', 'Tor', 'Minerva' +), ( +'23' , '13', 'Whis', 'Key', 'Moly' +), ( +'24' , '14', 'X', 'Rey', 'Mistigri' +), ( +'25' , '14', 'Yan', 'Kee', 'Astroboy' +), ( +'26' , '15', 'Zul', 'Lu', 'Salameche' +), ( +'27' , '15', 'Ze', 'Ro', 'Mandy' ); INSERT INTO `fic`.`themes` ( `id` , -`filename` +`name` ) VALUES ( '1' , 'pdf.xml' diff --git a/db/fic2014.sql b/db/fic2014.sql index ec666486..1a5405ec 100644 --- a/db/fic2014.sql +++ b/db/fic2014.sql @@ -98,6 +98,7 @@ CREATE TABLE IF NOT EXISTS `solved` ( CREATE TABLE IF NOT EXISTS `teams` ( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `team_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `key_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `auth_level` tinyint(1) NOT NULL, `company` varchar(255) COLLATE utf8_unicode_ci NOT NULL, From 30a7f656165c15a6228824f79ce1454649084070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 26 Oct 2013 17:42:18 +0200 Subject: [PATCH 0052/2585] Add missing team.tpl page --- onyx/tpl/bootstrap/public/team.tpl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 onyx/tpl/bootstrap/public/team.tpl diff --git a/onyx/tpl/bootstrap/public/team.tpl b/onyx/tpl/bootstrap/public/team.tpl new file mode 100644 index 00000000..f9a9f87f --- /dev/null +++ b/onyx/tpl/bootstrap/public/team.tpl @@ -0,0 +1,16 @@ +{extends file="layout.tpl"} +{block name=content} +

+ {$team->company} +

+
    +
  • Score : {$team->get_pts()}
  • +
  • Membre{if count($team->get_members()) > 1}s{/if} : +
      + {foreach from=$team->get_members() item=m} +
    • {$m.lastname} {$m.firstname}
    • + {/foreach} +
    +
  • +
+{/block} From b069d8f4ed8280f3bf95417a59e64318a360650f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Sat, 26 Oct 2013 18:17:25 +0200 Subject: [PATCH 0053/2585] New class Member, use it in Team ; update DB schema --- db/fic2014.sql | 11 ++-- onyx/include/common.php | 1 + onyx/include/common/Member.class.php | 84 ++++++++++++++++++++++++++++ onyx/include/common/Team.class.php | 35 ++++++------ onyx/tpl/bootstrap/public/team.tpl | 4 +- 5 files changed, 110 insertions(+), 25 deletions(-) create mode 100644 onyx/include/common/Member.class.php diff --git a/db/fic2014.sql b/db/fic2014.sql index ec666486..01945b2e 100644 --- a/db/fic2014.sql +++ b/db/fic2014.sql @@ -100,7 +100,7 @@ CREATE TABLE IF NOT EXISTS `teams` ( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `key_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `auth_level` tinyint(1) NOT NULL, - `company` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `slogan` varchar(64) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; @@ -113,9 +113,10 @@ CREATE TABLE IF NOT EXISTS `teams` ( CREATE TABLE IF NOT EXISTS `team_members` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id_team` int(10) unsigned NOT NULL, - `firstname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `lastname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `nickname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `firstname` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `lastname` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `nickname` varchar(32) COLLATE utf8_unicode_ci NOT NULL, + `company` varchar(32) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; @@ -127,6 +128,6 @@ CREATE TABLE IF NOT EXISTS `team_members` ( CREATE TABLE IF NOT EXISTS `themes` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `name` varchar(32) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; diff --git a/onyx/include/common.php b/onyx/include/common.php index 6754e327..6e0f0067 100644 --- a/onyx/include/common.php +++ b/onyx/include/common.php @@ -7,6 +7,7 @@ if (empty($sess->values["connected"]) && !defined("xCSRF")) require_once("functions.php"); //Inclusion des principales fonctions require_once("common/Exercice.class.php"); +require_once("common/Member.class.php"); require_once("common/Team.class.php"); require_once("common/Theme.class.php"); diff --git a/onyx/include/common/Member.class.php b/onyx/include/common/Member.class.php new file mode 100644 index 00000000..677b9c37 --- /dev/null +++ b/onyx/include/common/Member.class.php @@ -0,0 +1,84 @@ +unique_query("SELECT id, id_team, firstname, lastname, nickname, company + FROM team_members WHERE id=" . intval($id)) or die($db->erreur()); + $db->deconnexion(); + + if (!empty($res)) + { + $this->id = $res['id']; + if (empty($team)) + $this->team = $res['id_team']; + else + $this->team = $team; + $this->firstname = $res['firstname']; + $this->lastname = $res['lastname']; + $this->nickname = $res['nickname']; + $this->company = $res['company']; + } + } + } + + function update() + { + $firstname = $this->firstname; + $lastname = $this->lastname; + $nickname = $this->nickname; + $company = $this->company; + + if (gettype($this->team) != "object") + $id_team = intval($this->team); + else + $id_team = $this->team->id; + + $db = new BDD(); + $db->escape($firstname); + $db->escape($lastname); + $db->escape($nickname); + $db->escape($company); + + if (empty($this->id)) + { + $db->query("INSERT INTO team_members + VALUES (NULL, ".intval($id_team).", '".$firstname."', '".$lastname."', '".$nickname."', '".$company."')"); + $this->id = $db->insert_id(); + $aff = ($this->id > 0); + } + else + { + $db->query("UPDATE team_members + SET id_team = ".intval($id_team).", firstname = '$firstname', lastname = '$lastname', nickname = '$lastname', company = '$company' + WHERE id = ".intval($this->id)); + $aff = $db->affected(); + } + $db->deconnexion(); + + return ($aff == 1); + } + + function get_team() + { + if (gettype($this->team) != "object") + $this->team = new Team(intval($this->team)); + + return $this->team; + } +} + +?> \ No newline at end of file diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 4debbf23..aeeb6799 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -17,8 +17,8 @@ class Team var $id = null; var $key_hash; var $auth_level; - var $company; - var $members = null; + var $slogan; + var $members = array(); var $points = null; // Constructor @@ -27,14 +27,14 @@ class Team if (!empty($id)) { $db = new BDD(); - $res = $db->unique_query("SELECT id, key_hash, company, auth_level + $res = $db->unique_query("SELECT id, key_hash, slogan, auth_level FROM teams WHERE id=" . intval($id)) or die($db->erreur()); if (!empty($res)) { $this->id = $res['id']; $this->key_hash = $res['key_hash']; - $this->company = $res['company']; + $this->slogan = $res['slogan']; $this->auth_level = $res['auth_level']; } $db->deconnexion(); @@ -46,23 +46,23 @@ class Team { $key_hash = $this->key_hash; $auth_level = intval($this->auth_level); - $company = $this->company; + $slogan = $this->slogan; $db = new BDD(); $db->escape($key_hash); - $db->escape($company); + $db->escape($slogan); if (empty($this->id)) { $db->query("INSERT INTO teams - VALUES (NULL, '".$key_hash."', ".$auth_level.", '".$company."')"); + VALUES (NULL, '".$key_hash."', ".$auth_level.", '".$slogan."')"); $this->id = $db->insert_id(); $aff = ($this->id > 0); } else { - $db->query("UPDATE users - SET auth_level = ".$auth_level.", key_hash = '".$key_hash."', company = '".$company."' + $db->query("UPDATE teams + SET auth_level = ".$auth_level.", key_hash = '".$key_hash."', slogan = '".$slogan."' WHERE id = ".intval($this->id)); $aff = $db->affected(); } @@ -75,8 +75,8 @@ class Team return $this->id; } - function get_company() { - return $this->company; + function get_slogan() { + return $this->slogan; } function get_auth_level() { @@ -85,18 +85,17 @@ class Team function get_members() { - if(!isset($this->members)) + if(count($this->members) == 0) { $db = new BDD(); - $res = $db->query("SELECT id, firstname, lastname, nickname - FROM team_members + $res = $db->query("SELECT id FROM team_members WHERE id_team = " . intval($this->id)); $db->deconnexion(); - if (!empty($res)) - $this->members = $res; + foreach($res as $member) + $this->members[] = new Member($member["id"], $this); } return $this->members; @@ -117,9 +116,9 @@ class Team $db->deconnexion(); if (!empty($res)) - { $this->points = $res['sum_points']; - } + else + $this->points = 0; } return $this->points; diff --git a/onyx/tpl/bootstrap/public/team.tpl b/onyx/tpl/bootstrap/public/team.tpl index f9a9f87f..39094e42 100644 --- a/onyx/tpl/bootstrap/public/team.tpl +++ b/onyx/tpl/bootstrap/public/team.tpl @@ -1,14 +1,14 @@ {extends file="layout.tpl"} {block name=content}

- {$team->company} + {$team->slogan}

- -
+ +
From fd855c0f0d43063f2600e878d9f3350f166eed6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Mon, 25 Nov 2013 15:38:42 +0100 Subject: [PATCH 0108/2585] Add clock.tpl --- onyx/tpl/bootstrap/clock.tpl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 onyx/tpl/bootstrap/clock.tpl diff --git a/onyx/tpl/bootstrap/clock.tpl b/onyx/tpl/bootstrap/clock.tpl new file mode 100644 index 00000000..05c184c2 --- /dev/null +++ b/onyx/tpl/bootstrap/clock.tpl @@ -0,0 +1,20 @@ +
+ + +
+
    +
  • +
  • :
  • +
  • +
  • :
  • +
  • +
+
From c5f96c8bb99db867fe6b2ae5f2fabc2c652fb479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Mon, 25 Nov 2013 15:55:12 +0100 Subject: [PATCH 0109/2585] Ignore submissions --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 571d5f74..cb02566c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ onyx/log/* onyx/config/root.xml onyx/db/*.profile.php onyx/tpl/*/*.html +submission/* From e137e755c07ce7947f74bef171c8d079dbd417e2 Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Mon, 25 Nov 2013 21:12:01 +0100 Subject: [PATCH 0110/2585] Add public array --- onyx/include/common/Team.class.php | 17 +++++++++++++ onyx/tpl/bootstrap/public/home.tpl | 40 ++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 7494898a..3a2cd470 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -232,4 +232,21 @@ class Team return $res['count_teams']; } + + public static function first_to_solve_exercice($id_exercice) + { + $db = new BDD(); + $res = $db->unique_query("SELECT t3.team_name as result + FROM solved AS t1 + INNER JOIN ( + SELECT MIN(s.time) AS minTime + FROM solved AS s + WHERE s.id_exercice = ".$id_exercice." + ) AS t2 + INNER JOIN teams AS t3 ON t1.id_team = t3.id + WHERE t1.time = t2.minTime"); + $db->deconnexion(); + + return $res['result']; + } } diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index 2fe5783b..6f0d757e 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -2,12 +2,38 @@ {block name=main}
-

Example

-

This is a example

-

This is a example

-

This is a example

-

This is a example

-

This is a example

-

This is a example

+ + + + + +{for $i=1 to $nbExoMax} + +{/for} + + + +{$total=0} +{foreach from=$themes item=theme} + + + {$themeID=$theme->get_id()} + {foreach from=$theme->get_exercices_ordered() item=exo} + {$teamName=""} + {for $i=0 to $nbExoMax} + {$teamName=Team::first_to_solve_exercice($exo->get_id())} + {/for} + {if $teamName != ""} + + {else} + + {/if} + {/foreach} + +{/foreach} + +
Exercice {$i}
{$theme->get_name()}{$teamName}
+ +
{/block} From a9fdcaf9f260b8634bc7c808725d10dee75ef23d Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 18:24:46 +0100 Subject: [PATCH 0111/2585] Use a variable to handle the misc_dir --- onyx/include/admin/certificate.php | 46 +++++++++++++++++++---------- onyx/include/admin/home.php | 27 ++++++++++++----- onyx/include/admin/import_users.php | 11 +++++-- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index ce7b4016..89e9ca61 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -24,39 +24,53 @@ function remove_directory($dir) function new_client($name) { - //TODO handle if already exist - putenv("OPENSSL_CONF=".ONYX. '../misc/openssl.cnf'); - putenv("TOP_DIR=".ONYX. '../misc/pki'); - $output = shell_exec(ONYX . "../misc/CA.sh -newclient $name"); + if (isset($VAR['misc_dir'])) + $misc_dir = $VAR['misc_dir']; + else + { + erreur("Merci d'ajouter la variable misc_dir dans root.xml"); + return "admin/home"; + } + + //TODO handle if already exist + putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); + putenv("TOP_DIR=$misc_dir/pki"); + $output = shell_exec("$misc_dir/CA.sh -newclient $name"); } if (!empty($p[2])) { + if (isset($VAR['misc_dir'])) + $misc_dir = $VAR['misc_dir']; + else + { + erreur("Merci d'ajouter la variable misc_dir dans root.xml"); + return "admin/home"; + } + + $misc_dir = $VAR['misc_dir']; + if ($p[2] == "newca") { - //TODO handle if already exist - putenv("OPENSSL_CONF=".ONYX. '../misc/openssl.cnf'); - putenv("TOP_DIR=".ONYX. '../misc/pki'); - $output = shell_exec(ONYX . '../misc/CA.sh -newca'); + putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); + putenv("TOP_DIR=$misc_dir/pki"); + $output = shell_exec("$misc_dir/CA.sh -newca"); - //TODO handle the path ? - $ca_file = ONYX . '../misc/pki/cacert.crt'; + $ca_file = "$misc_dir/pki/cacert.crt"; //TODO check permission ? if (file_exists($ca_file)) { - $data = openssl_x509_parse(file_get_contents(ONYX . '../misc/pki/cacert.crt')); + $data = openssl_x509_parse(file_get_contents("$misc_dir/pki/cacert.crt")); $template->assign("cert", $data); } } elseif ($p[2] == "deleteca") { - //TODO handle var path - $dir = ONYX . '../misc/pki'; - + $dir = "$misc_dir/pki"; remove_directory($dir); } } -//header("Location: /admin/"); -//exit; \ No newline at end of file +header("Location: /admin/"); +exit; diff --git a/onyx/include/admin/home.php b/onyx/include/admin/home.php index 2e333fa1..79bcbfcc 100644 --- a/onyx/include/admin/home.php +++ b/onyx/include/admin/home.php @@ -2,20 +2,31 @@ if(!defined('ONYX')) exit; -if (is_writable(ONYX."../misc/") && !is_dir(ONYX."../misc/pki/")) - mkdir(ONYX."../misc/pki/"); +if (isset($VAR['misc_dir'])) + $misc_dir = $VAR['misc_dir']; +else +{ + erreur("Merci d'ajouter la variable misc_dir dans root.xml"); + return "admin/home"; +} -$wright = is_writable(ONYX."../misc/pki/"); +if (is_writable($misc_dir) && !is_dir("$misc_dir/pki/")) + mkdir("$misc_dir/pki/"); + +$wright = is_writable("$misc_dir/pki/"); $template->assign("cert_writable", $wright); -//TODO handle the path ? -$ca_file = ONYX . '../misc/pki/cacert.crt'; +$ca_file = "$misc_dir/pki/cacert.crt"; -//TODO check permission ? if (file_exists($ca_file)) { - $data = openssl_x509_parse(file_get_contents(ONYX . '../misc/pki/cacert.crt')); - $template->assign("cert", $data); + if (!is_readable($ca_file)) + erreur("Impossible de lire le fichier"); + else + { + $data = openssl_x509_parse(file_get_contents(ONYX . '../misc/pki/cacert.crt')); + $template->assign("cert", $data); + } } return "admin/home"; diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index a8b328e5..aa28124d 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -6,8 +6,15 @@ include 'certificate.php'; if (!empty($_FILES["inputFile"]['tmp_name'])) { - //TODO use a variable to define the path - if (!file_exists(ONYX . "../misc/fic_pki/cacert.crt")) + if (isset($VAR['misc_dir'])) + $misc_dir = $VAR['misc_dir']; + else + { + erreur("Please add the misc_dir variable into root.xml"); + return "admin/import_users"; + } + + if (!file_exists("$misc_dir/pki/cacert.crt")) { erreur("The root certificate file not found, please create this first"); return "admin/import_users"; From 30802be380e3540af4c8ecd713f1ecbca0690515 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 19:02:49 +0100 Subject: [PATCH 0112/2585] Fixed create or delete ca redirection page --- onyx/include/admin/certificate.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index 89e9ca61..1fe836d7 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -70,7 +70,11 @@ if (!empty($p[2])) $dir = "$misc_dir/pki"; remove_directory($dir); } + + if ($p[2] == "deleteca" || $p[2] == "newca") + { + header("Location: /admin/"); + exit; + } } -header("Location: /admin/"); -exit; From e3f51487ab4d1c7e1d15642e8b31e30a76828475 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 19:18:51 +0100 Subject: [PATCH 0113/2585] Fixed client certificate generation --- onyx/include/admin/certificate.php | 10 +--------- onyx/include/admin/import_users.php | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index 1fe836d7..c80b2a66 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -22,16 +22,8 @@ function remove_directory($dir) } } -function new_client($name) +function new_client($name, $misc_dir) { - if (isset($VAR['misc_dir'])) - $misc_dir = $VAR['misc_dir']; - else - { - erreur("Merci d'ajouter la variable misc_dir dans root.xml"); - return "admin/home"; - } - //TODO handle if already exist putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); putenv("TOP_DIR=$misc_dir/pki"); diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index aa28124d..76c4f292 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -72,7 +72,7 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) if (!empty($team->team_name)) { //TODO save the certificate subject - new_client($team->team_name); + new_client($team->team_name, $misc_dir); } } } From 7cf991d537f2df8bf02587e653632477103316ad Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 19:36:28 +0100 Subject: [PATCH 0114/2585] Add a textarea to show the output of the CA.sh --- misc/CA.sh | 20 +++++++++++++++----- onyx/include/admin/certificate.php | 1 + onyx/include/admin/import_users.php | 4 +++- onyx/tpl/bootstrap/admin/import_users.tpl | 5 +++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index 1feb3e8c..6805446f 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -25,6 +25,8 @@ usage() [ $# -lt 1 ] && usage +OUTPUT=`mktemp` + case $1 in "-newca" ) # echo -e -n "${GREEN}Create the directories, take care this will delete" @@ -45,7 +47,11 @@ case $1 in sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= server #CERTTYPE/" $OPENSSL_CONF - pass=`pwgen 10 1` + pass=`pwgen 10 1` 2> $OUTPUT + if [ $? -ne 0 ]; then + cat $OUTPUT + exit 5 + fi openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ -out ${TOP_DIR}/${CAREQ} -passout pass:$pass \ @@ -72,7 +78,7 @@ case $1 in echo -e "${GREEN}Signing the Server crt${COLOR_RST}" openssl ca -policy policy_match -out server.crt -infiles server.csr if [ $? -ne 0 ]; then - echo -e "${RED}Signing failed${COLOR_RST}" + echo -e "${RED}Signing failed for new server${COLOR_RST}" rm -rf server.key server.crt server.csr exit 3 else @@ -94,7 +100,11 @@ case $1 in sed -i "s/=.*#COMMONNAME/= $2#COMMONNAME/" $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= client #CERTTYPE/" $OPENSSL_CONF - pass=`pwgen 10 1` + pass=`pwgen 10 1` 2> $OUTPUT + if [ $? -ne 0 ]; then + cat $OUTPUT + exit 5 + fi openssl req -batch -new -keyout ${2}.key -out ${2}.csr \ -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} @@ -103,14 +113,14 @@ case $1 in openssl ca -batch -policy policy_match -out ${2}.crt \ -config ${OPENSSL_CONF} -infiles ${2}.csr if [ $? -ne 0 ]; then - echo -e "${RED}Signing failed${COLOR_RST}" + echo -e "${RED}Signing failed for $2 ${COLOR_RST}" exit 3 fi # echo -e "${GREEN}Export the Client files to pkcs12${COLOR_RST}" openssl pkcs12 -export -inkey ${2}.key -in ${2}.crt -name ${2} \ -passin pass:$pass -out ${2}.p12 -passout pass:$pass if [ $? -ne 0 ]; then - echo -e "${RED}pkcs12 export failed${COLOR_RST}" + echo -e "${RED}pkcs12 export failed${COLOR_RST} for $2" exit 4 else echo -e "Exported pkcs12 file is ${2}.p12" diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index c80b2a66..24a8ddb7 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -28,6 +28,7 @@ function new_client($name, $misc_dir) putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); putenv("TOP_DIR=$misc_dir/pki"); $output = shell_exec("$misc_dir/CA.sh -newclient $name"); + return $output; } if (!empty($p[2])) diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index 76c4f292..b9b07dfc 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -31,6 +31,7 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) $elements = $xpath->query("//teams/team"); if (!is_null($elements)) { + $output = ""; foreach ($elements as $element) { $team = new Team(); @@ -72,9 +73,10 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) if (!empty($team->team_name)) { //TODO save the certificate subject - new_client($team->team_name, $misc_dir); + $output .= new_client($team->team_name, $misc_dir); } } + $template->assign("output", $output); } erreur("Fichier XML importé avec succès.", "success"); } diff --git a/onyx/tpl/bootstrap/admin/import_users.tpl b/onyx/tpl/bootstrap/admin/import_users.tpl index 73775932..72ed401c 100644 --- a/onyx/tpl/bootstrap/admin/import_users.tpl +++ b/onyx/tpl/bootstrap/admin/import_users.tpl @@ -10,4 +10,9 @@
+ +{if isset($output)} +

Output

+
{$output}
+{/if} {/block} From 04d96014092645071ffd26eda4b5c39c0fdb0ebb Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 20:59:22 +0100 Subject: [PATCH 0115/2585] Deleted heads bloc in layout and team.tpl --- onyx/tpl/bootstrap/admin/layout.tpl | 2 +- onyx/tpl/bootstrap/teams/team.tpl | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/onyx/tpl/bootstrap/admin/layout.tpl b/onyx/tpl/bootstrap/admin/layout.tpl index 393320ce..cf6b9d4a 100644 --- a/onyx/tpl/bootstrap/admin/layout.tpl +++ b/onyx/tpl/bootstrap/admin/layout.tpl @@ -3,7 +3,7 @@ {block name=head} {literal} {/literal} {/block} diff --git a/onyx/tpl/bootstrap/teams/team.tpl b/onyx/tpl/bootstrap/teams/team.tpl index 478e971e..eb92a925 100644 --- a/onyx/tpl/bootstrap/teams/team.tpl +++ b/onyx/tpl/bootstrap/teams/team.tpl @@ -1,9 +1,5 @@ {extends file="teams/layout.tpl"} -{block name=head} - -{/block} - {block name=content}

THIS IS TEAM From 3bd7654e81bd20eae821d4fdec13bea83f7e5d17 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 21:06:38 +0100 Subject: [PATCH 0116/2585] Delete href in logos and add Epita in the footer --- onyx/tpl/bootstrap/clock.tpl | 4 ---- onyx/tpl/bootstrap/layout.tpl | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/onyx/tpl/bootstrap/clock.tpl b/onyx/tpl/bootstrap/clock.tpl index 05c184c2..2b63efcb 100644 --- a/onyx/tpl/bootstrap/clock.tpl +++ b/onyx/tpl/bootstrap/clock.tpl @@ -1,13 +1,9 @@
    diff --git a/onyx/tpl/bootstrap/layout.tpl b/onyx/tpl/bootstrap/layout.tpl index 910a3a13..38523569 100644 --- a/onyx/tpl/bootstrap/layout.tpl +++ b/onyx/tpl/bootstrap/layout.tpl @@ -33,7 +33,8 @@
    From 124a7c2a32a017381357e5663e4a675a170d9be8 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Mon, 25 Nov 2013 21:30:53 +0100 Subject: [PATCH 0117/2585] Fixed error ouput when pwgen was not found --- misc/CA.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index 6805446f..a0133311 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -25,8 +25,6 @@ usage() [ $# -lt 1 ] && usage -OUTPUT=`mktemp` - case $1 in "-newca" ) # echo -e -n "${GREEN}Create the directories, take care this will delete" @@ -47,12 +45,14 @@ case $1 in sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= server #CERTTYPE/" $OPENSSL_CONF - pass=`pwgen 10 1` 2> $OUTPUT + type pwgen > /dev/null if [ $? -ne 0 ]; then - cat $OUTPUT + echo "command not found: pwgen" exit 5 fi + pass=`pwgen 10 1` + openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ -out ${TOP_DIR}/${CAREQ} -passout pass:$pass \ -config $OPENSSL_CONF @@ -100,12 +100,14 @@ case $1 in sed -i "s/=.*#COMMONNAME/= $2#COMMONNAME/" $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= client #CERTTYPE/" $OPENSSL_CONF - pass=`pwgen 10 1` 2> $OUTPUT + type pwgen > /dev/null if [ $? -ne 0 ]; then - cat $OUTPUT + echo "command not found: pwgen" exit 5 fi + pass=`pwgen 10 1` + openssl req -batch -new -keyout ${2}.key -out ${2}.csr \ -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} From 62fca492ad7c2eaff2d5927c3390bc8d40b7775a Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Mon, 25 Nov 2013 23:06:26 +0100 Subject: [PATCH 0118/2585] Add timestamp comparison in ranking system --- onyx/include/common/Team.class.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 3a2cd470..30b9f343 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -5,7 +5,21 @@ if(!defined('ONYX')) exit; function cmp_team_pts($i1, $i2) { if ($i1->get_pts() == $i2->get_pts()){ - return 0; + $db = new BDD(); + + $timestampi1 = $db->unique_query("SELECT MAX( s.time ) AS maxTime + FROM solved AS s + WHERE s.id_team =".$i1); + $timestampi2 = $db->unique_query("SELECT MAX( s.time ) AS maxTime + FROM solved AS s + WHERE s.id_team =".$i12); + + $db->deconnexion(); + + if ($timestampi1 < $timestampi2){ + return 1 + else + return -1 } else{ return ($i1->get_pts() < $i2->get_pts()) ? 1 : -1; From 11dc0c153a6c73db3e12422970e37db846606b5c Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Tue, 26 Nov 2013 20:25:25 +0100 Subject: [PATCH 0119/2585] Fix some code errors that should not be commited yesterday... (sry) --- onyx/include/common/Team.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 30b9f343..0e3c9ffe 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -9,17 +9,17 @@ function cmp_team_pts($i1, $i2) $timestampi1 = $db->unique_query("SELECT MAX( s.time ) AS maxTime FROM solved AS s - WHERE s.id_team =".$i1); + WHERE s.id_team =".$i1->get_id()); $timestampi2 = $db->unique_query("SELECT MAX( s.time ) AS maxTime FROM solved AS s - WHERE s.id_team =".$i12); + WHERE s.id_team =".$i2->get_id()); $db->deconnexion(); - if ($timestampi1 < $timestampi2){ - return 1 + if ($timestampi1['maxTime'] > $timestampi2['maxTime']) + return 1; else - return -1 + return -1; } else{ return ($i1->get_pts() < $i2->get_pts()) ? 1 : -1; From 67b5422c28b1970849803fb8a8b86c68f698f166 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Thu, 28 Nov 2013 16:03:36 +0100 Subject: [PATCH 0120/2585] Deleted team/home Change the default page of team to summary page --- htdocs/index.php | 2 +- onyx/include/team/home.php | 8 -------- onyx/tpl/bootstrap/teams/home.tpl | 11 ----------- 3 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 onyx/include/team/home.php delete mode 100644 onyx/tpl/bootstrap/teams/home.tpl diff --git a/htdocs/index.php b/htdocs/index.php index 372a9adb..e451421d 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -108,7 +108,7 @@ else if ($n && $p[0] == SALT_USER) $template->assign("themes", Theme::get_themes()); if ($n <= 2) - $page = require("team/team.php"); + $page = require("team/summary.php"); else { switch($p[2]) diff --git a/onyx/include/team/home.php b/onyx/include/team/home.php deleted file mode 100644 index eaa60a72..00000000 --- a/onyx/include/team/home.php +++ /dev/null @@ -1,8 +0,0 @@ -assign("teams", Team::get_teams()); -$template->assign("top", Team::get_top()); - -return "teams/home"; diff --git a/onyx/tpl/bootstrap/teams/home.tpl b/onyx/tpl/bootstrap/teams/home.tpl deleted file mode 100644 index 5bcb3d87..00000000 --- a/onyx/tpl/bootstrap/teams/home.tpl +++ /dev/null @@ -1,11 +0,0 @@ -{extends file="teams/layout.tpl"} - -{block name=head} - -{/block} - -{block name=content} -

    - YOUPIII !!! -

    -{/block} From b406ae93e3b54721d6dacdc533efdae481fb788e Mon Sep 17 00:00:00 2001 From: Li Chen Date: Thu, 28 Nov 2013 16:28:43 +0100 Subject: [PATCH 0121/2585] Add team informations in the me page --- onyx/include/team/me.php | 2 ++ onyx/tpl/bootstrap/teams/me.tpl | 32 +++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/onyx/include/team/me.php b/onyx/include/team/me.php index 053de859..b6a81f13 100644 --- a/onyx/include/team/me.php +++ b/onyx/include/team/me.php @@ -2,4 +2,6 @@ if(!defined('ONYX')) exit; +$template->assign("members", $TEAM->get_members()); + return "teams/me"; diff --git a/onyx/tpl/bootstrap/teams/me.tpl b/onyx/tpl/bootstrap/teams/me.tpl index eafc7f2c..bd05fbd7 100644 --- a/onyx/tpl/bootstrap/teams/me.tpl +++ b/onyx/tpl/bootstrap/teams/me.tpl @@ -1,7 +1,33 @@ {extends file="teams/layout.tpl"} {block name=content} -

    - THIS IS ME -

    +
    +
    +

    Information sur l'équipe

    +
    +
    + {if not empty($members)} + + + + + + + + + + {foreach from=$members item=member} + + + + + + + {/foreach} + +
    #PrénomNomPseudonymeEntreprise
    {$member->firstname}{$member->lastname}{$member->nickname}{$member->company}
    + {/if} +
    +
    + {/block} From 4f2dbf54703e7897cd725afc93dee5c12e18e8df Mon Sep 17 00:00:00 2001 From: Li Chen Date: Thu, 28 Nov 2013 17:01:31 +0100 Subject: [PATCH 0122/2585] Add progress bar in the me page Fixed class panel-body name in the me.tpl --- onyx/include/team/summary.php | 15 +++++++++++++++ onyx/tpl/bootstrap/teams/me.tpl | 2 +- onyx/tpl/bootstrap/teams/summary.tpl | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/onyx/include/team/summary.php b/onyx/include/team/summary.php index 4403c9ca..556a9298 100644 --- a/onyx/include/team/summary.php +++ b/onyx/include/team/summary.php @@ -2,7 +2,22 @@ if(!defined('ONYX')) exit; +$themes = Theme::get_themes(); +if (!empty($themes)) +{ + $max_exo = 0; + $res_exo = 0; + foreach($themes as $th) + { + $max_exo += $th->get_nb_exercices(); + //$res_exo += $TEAM->get_nb_res_exercices_by_theme($th->get_id()); + $res_exo += count($TEAM->get_solved_exercices($th->get_id())); + } + $percent = $res_exo * 100 / $max_exo; +} + $template->assign("themes", Theme::get_themes()); $template->assign("nbExoMax", Exercice::get_nb_exo_max()); +$template->assign("percent", $percent); return "teams/summary"; diff --git a/onyx/tpl/bootstrap/teams/me.tpl b/onyx/tpl/bootstrap/teams/me.tpl index bd05fbd7..7b73a58a 100644 --- a/onyx/tpl/bootstrap/teams/me.tpl +++ b/onyx/tpl/bootstrap/teams/me.tpl @@ -5,7 +5,7 @@

    Information sur l'équipe

    -
    +
    {if not empty($members)} diff --git a/onyx/tpl/bootstrap/teams/summary.tpl b/onyx/tpl/bootstrap/teams/summary.tpl index 944f6e13..cf025cba 100644 --- a/onyx/tpl/bootstrap/teams/summary.tpl +++ b/onyx/tpl/bootstrap/teams/summary.tpl @@ -1,5 +1,20 @@ {extends file="teams/layout.tpl"} {block name=content} +{if isset($percent)} +
    +
    +

    Progression

    +
    +
    +
    +
    + {$percent}% Complete +
    +
    +
    +
    +{/if} {include file="summary.tpl"} {/block} From dd766cf774e0c1a30df28a8757195cfd28dc70cb Mon Sep 17 00:00:00 2001 From: Li Chen Date: Thu, 28 Nov 2013 17:13:03 +0100 Subject: [PATCH 0123/2585] Team layout: change 'modifier' to 'info' --- onyx/tpl/bootstrap/teams/layout.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onyx/tpl/bootstrap/teams/layout.tpl b/onyx/tpl/bootstrap/teams/layout.tpl index 15921f1b..6be3e306 100644 --- a/onyx/tpl/bootstrap/teams/layout.tpl +++ b/onyx/tpl/bootstrap/teams/layout.tpl @@ -39,7 +39,7 @@ $(document).ready(function() { + {if $teams} @@ -19,6 +20,9 @@ @@ -29,6 +33,7 @@ + {/foreach} From c067f6dbbe754471e5008a01df9f4b1876cda9a3 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 00:24:53 +0100 Subject: [PATCH 0141/2585] Fixed undefined var in admin/home.tpl --- onyx/tpl/bootstrap/admin/home.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onyx/tpl/bootstrap/admin/home.tpl b/onyx/tpl/bootstrap/admin/home.tpl index 35c6d854..b9c60a39 100644 --- a/onyx/tpl/bootstrap/admin/home.tpl +++ b/onyx/tpl/bootstrap/admin/home.tpl @@ -16,7 +16,7 @@
  • [emailAddress] : {$cert['subject']['emailAddress']}
  • Supprimer - {elseif ! $cert_writable} + {elseif isset($cert_writable) && ! $cert_writable}
    Répertoire non accessible en écriture.
    Nouveau {else} From 745d8a8bd5e3196629c272b2728da1cb40408b9b Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 01:08:40 +0100 Subject: [PATCH 0142/2585] Fixed multiple team->update in import_users Show the pass at the end of import --- misc/CA.sh | 3 +-- onyx/include/admin/import_users.php | 13 +++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index 45911707..1f23c18e 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -181,8 +181,7 @@ case $1 in echo -e "Exported pkcs12 file is ${2}.p12" fi mv ${2}.crt ${TOP_DIR}/certs -# TODO handle this file - echo "$2:$pass" >> teams.pass + echo "$2:$pass" >> ${TOP_DIR}/../teams.pass clean "client" $2 ;; "-revoke" ) diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index c143971c..dece7040 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -48,15 +48,15 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) else if ($child->nodeName == "member") { - if (!$team->update()) + // Slogan rly needed ? + if (empty($team->id) && !$team->update()) { - $error .= "Unable to add team $team->team_name
    "; - continue; + $error .= "Unable to add team $team->team_name
    "; + continue; } $user = new Member(); $user->team = $team; - foreach ($child->childNodes as $child_member) { if ($child_member->nodeName == "firstname") @@ -87,6 +87,11 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) $output .= new_client($team->team_name, $misc_dir); } } + if (file_exists("$misc_dir/teams.pass")) + { + $output .= file_get_contents("$misc_dir/teams.pass"); + unlink("$misc_dir/teams.pass"); + } $template->assign("output", $output); } From 3f0a403fd4c08869bdd7e3f80dcd41395057e593 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 01:17:30 +0100 Subject: [PATCH 0143/2585] Add some confirmation before delete user or revoke certificate --- onyx/tpl/bootstrap/admin/users.tpl | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/onyx/tpl/bootstrap/admin/users.tpl b/onyx/tpl/bootstrap/admin/users.tpl index 201c04a4..6c9f0aa0 100644 --- a/onyx/tpl/bootstrap/admin/users.tpl +++ b/onyx/tpl/bootstrap/admin/users.tpl @@ -19,10 +19,15 @@
    @@ -41,10 +46,13 @@ From 964d3b067f663e36fd2b6cd3dc20ff1fae5d3a48 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 19:21:32 +0100 Subject: [PATCH 0144/2585] Dont show generate certificate and revoke together --- onyx/tpl/bootstrap/admin/users.tpl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/onyx/tpl/bootstrap/admin/users.tpl b/onyx/tpl/bootstrap/admin/users.tpl index 6c9f0aa0..5cb1d126 100644 --- a/onyx/tpl/bootstrap/admin/users.tpl +++ b/onyx/tpl/bootstrap/admin/users.tpl @@ -21,13 +21,16 @@ {$t->id}
    + + + {if not $t->revoked} - - + {else} + {/if}
    From 31eabf84b468305cd3fe4aeeb50a5a30c988f773 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 19:40:47 +0100 Subject: [PATCH 0145/2585] Move the function remove_team from list_users.php to Team.class Revoke certificates after drop all teams --- onyx/include/admin/certificate.php | 15 ++++++++----- onyx/include/admin/list_users.php | 35 ++++++++++++++++++++---------- onyx/include/common/Team.class.php | 9 ++++++++ onyx/tpl/bootstrap/admin/users.tpl | 2 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index 23a35290..580d6b62 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -31,6 +31,13 @@ function new_client($name, $misc_dir) return $output; } +function revoke_client($name, $misc_dir) +{ + putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); + putenv("TOP_DIR=$misc_dir/pki"); + $output = shell_exec("$misc_dir/CA.sh -revoke $name"); +} + if (!empty($p[2])) { if (isset($VAR['misc_dir'])) @@ -60,11 +67,9 @@ if (!empty($p[2])) $name = $_GET['name']; if (isset($name)) { - putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); - putenv("TOP_DIR=$misc_dir/pki"); - $output = shell_exec("$misc_dir/CA.sh -revoke $name"); - //TODO Check revocation failed - Team::set_revoked(TRUE, $name); + $output = revoke_client($name, $misc_dir); + //TODO Check revocation failed + Team::set_revoked(TRUE, $name); } } // Is new team diff --git a/onyx/include/admin/list_users.php b/onyx/include/admin/list_users.php index 3968bc16..3ac2871f 100644 --- a/onyx/include/admin/list_users.php +++ b/onyx/include/admin/list_users.php @@ -2,29 +2,40 @@ if(!defined('ONYX')) exit; -function remove_team($id) -{ - $db = new BDD(); - $db->query("DELETE FROM team_members WHERE id_team = ".$id); - $db->query("DELETE FROM solved WHERE id_team = ".$id); - $db->query("DELETE FROM teams WHERE id = ".$id); - $db->deconnexion(); -} +include 'certificate.php'; if (!empty($_GET["delete"])) { - $id_team = intval($_GET["delete"]); + if (isset($VAR['misc_dir'])) + $misc_dir = $VAR['misc_dir']; + else + { + erreur("Merci d'ajouter la variable misc_dir dans root.xml"); + return SALT_ADMIN."/users"; + } - remove_team($id_team); + $id_team = intval($_GET["delete"]); + revoke_client($_GET['name'], $misc_dir); + Team::remove_team($id_team); header("Location: /".SALT_ADMIN."/teams"); exit; } else if (isset($_GET["drop"])) { + if (isset($VAR['misc_dir'])) + $misc_dir = $VAR['misc_dir']; + else + { + erreur("Merci d'ajouter la variable misc_dir dans root.xml"); + return SALT_ADMIN."/users"; + } + foreach(Team::get_teams() as $team) { - remove_team($team->get_id()); + //TODO check output + revoke_client($team->team_name, $misc_dir); + Team::remove_team($team->get_id()); } header("Location: /".SALT_ADMIN."/teams"); @@ -33,4 +44,4 @@ else if (isset($_GET["drop"])) $template->assign("teams", Team::get_teams()); -return "admin/users"; \ No newline at end of file +return SALT_ADMIN."/users"; diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index d9b3a966..f2ba89e9 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -246,6 +246,15 @@ class Team return ($aff == 1); } + public static function remove_team($id) + { + $db = new BDD(); + $db->query("DELETE FROM team_members WHERE id_team = ".$id); + $db->query("DELETE FROM solved WHERE id_team = ".$id); + $db->query("DELETE FROM teams WHERE id = ".$id); + $db->deconnexion(); + } + public static function get_teams() { $db = new BDD(); diff --git a/onyx/tpl/bootstrap/admin/users.tpl b/onyx/tpl/bootstrap/admin/users.tpl index 5cb1d126..3745aa70 100644 --- a/onyx/tpl/bootstrap/admin/users.tpl +++ b/onyx/tpl/bootstrap/admin/users.tpl @@ -19,7 +19,7 @@ - + From 854da4a12a08f4e5807e3ea0b9e09d35d08d085b Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 20:04:49 +0100 Subject: [PATCH 0147/2585] Change the icone download to floppy-save in the list_users page --- onyx/tpl/bootstrap/admin/users.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onyx/tpl/bootstrap/admin/users.tpl b/onyx/tpl/bootstrap/admin/users.tpl index 3745aa70..387013bb 100644 --- a/onyx/tpl/bootstrap/admin/users.tpl +++ b/onyx/tpl/bootstrap/admin/users.tpl @@ -22,7 +22,7 @@ - + {if not $t->revoked} From ad5052bb992aaa94885cb354f5d35a240b990dfa Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 20:24:59 +0100 Subject: [PATCH 0148/2585] Add confimation to delete the root certificat --- onyx/tpl/bootstrap/admin/home.tpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/onyx/tpl/bootstrap/admin/home.tpl b/onyx/tpl/bootstrap/admin/home.tpl index b9c60a39..33a7366d 100644 --- a/onyx/tpl/bootstrap/admin/home.tpl +++ b/onyx/tpl/bootstrap/admin/home.tpl @@ -15,7 +15,8 @@
  • [CN] : {$cert['subject']['CN']}
  • [emailAddress] : {$cert['subject']['emailAddress']}
  • -
    Supprimer + Supprimer {elseif isset($cert_writable) && ! $cert_writable}
    Répertoire non accessible en écriture.
    Nouveau From 8f2edb704872c9d7cf8e472c87d3db628f2a11dd Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 20:29:59 +0100 Subject: [PATCH 0149/2585] Add catch NotFoundException in admin/exercice.php --- onyx/include/admin/exercice.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/onyx/include/admin/exercice.php b/onyx/include/admin/exercice.php index fa6858cd..415e1901 100644 --- a/onyx/include/admin/exercice.php +++ b/onyx/include/admin/exercice.php @@ -4,17 +4,33 @@ if(!defined('ONYX')) exit; $p = $out[0]; -if (isset($p[2])) +//TODO maybe move the try catch to index.html ? +try { + if (isset($p[2])) + { $tmp = explode("-", $p[2]); $id = intval($tmp[0]); if ($id == 0) return "404"; $theme = new Theme($id); $template->assign("theme", $theme); + } + + if (isset($p[3])) + $template->assign("ex", new Exercice($p[3], $theme)); +} +catch (ThemeNotFoundException $e) +{ + return "404"; +} +catch(ExerciceNotFoundException $e) +{ + return "404"; +} +catch(ExerciceNotFoundException $e) +{ + return "404"; } -if (isset($p[3])) - $template->assign("ex", new Exercice($p[3], $theme)); - return SALT_ADMIN."/exercice"; From 4d1918a530e7837eab4db4da72c7089178d95cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Mon, 9 Dec 2013 11:54:06 +0100 Subject: [PATCH 0150/2585] Add a script for generating static site --- gen_site.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 gen_site.sh diff --git a/gen_site.sh b/gen_site.sh new file mode 100755 index 00000000..52544b99 --- /dev/null +++ b/gen_site.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +BASEURL="localhost" + +cd `dirname "$0"` + +mkdir -p out +cd out + +wget -c -m http://$BASEURL/ http://$BASEURL/connected/ From e2173a7d4474e7d26033a397992e1a1bd63cde78 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Dec 2013 12:58:17 +0100 Subject: [PATCH 0151/2585] Modification for production --- htdocs/index.php | 7 +++++-- misc/openssl.cnf | 6 +++--- nginx.conf | 26 ++++++++++++++++++++------ onyx/config/sample.root.xml | 7 ++++++- onyx/tpl/bootstrap/clock.tpl | 6 +++--- onyx/tpl/bootstrap/layout.tpl | 6 +++--- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/htdocs/index.php b/htdocs/index.php index b14b78ba..0be26241 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -2,8 +2,9 @@ //Inclusion de l'API Onyx require_once(trim(file_get_contents('./.onyx'))); -define("SALT_USER", "connected"); -define("SALT_ADMIN", "admin"); +define("SALT_PUBLIC", $VAR["prefix_public"]); +define("SALT_USER", $VAR["prefix_teams"]); +define("SALT_ADMIN", $VAR["prefix_admin"]); //On active le débogage si l'on est sur le domaine de debug @@ -13,6 +14,8 @@ if ($_SERVER["SERVER_NAME"] == "localhost" || $_SERVER["SERVER_NAME"] == "fic" | //Chargement de tout le nécessaire pour le site require_once("common.php"); +$template->assign("SALT_CDN",SALT_PUBLIC); +$template->assign("SALT_PUBLIC",SALT_PUBLIC); $template->assign("SALT_USER",SALT_USER); $template->assign("SALT_ADMIN",SALT_ADMIN); diff --git a/misc/openssl.cnf b/misc/openssl.cnf index 95fa5f76..a8c067f9 100644 --- a/misc/openssl.cnf +++ b/misc/openssl.cnf @@ -39,7 +39,7 @@ default_ca = CA_default # The default ca section #################################################################### [ CA_default ] -dir = fic_pki #DIR # Where everything is kept +dir = /srv/fic2014-server/misc//pki #DIR # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. @@ -147,7 +147,7 @@ organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = SRS commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_default = toto#COMMONNAME +commonName_default = FIC2014 Server #COMMONNAME commonName_max = 64 emailAddress = Email Address @@ -176,7 +176,7 @@ basicConstraints=CA:FALSE # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. -nsCertType = client #CERTTYPE +nsCertType = server #CERTTYPE # For an object signing certificate this would be used. # nsCertType = objsign diff --git a/nginx.conf b/nginx.conf index 1a4f42e1..b7fc7845 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,12 +1,26 @@ server { - listen 80; - listen [::]:80; - server_name fic fic.p0m.fr fic.nemunai.re; + listen 443 ssl; + listen [::]:443 ipv6only=on; access_log /var/log/nginx/fic.access_log; - error_log /var/log/nginx/fic.error_log debug; + error_log /var/log/nginx/fic.error_log; - root /var/www/fic2014-server/htdocs; + root /srv/fic2014-server/htdocs; + index index.php; + + ssl_certificate /srv/fic2014-server/misc/server.crt; + ssl_certificate_key /srv/fic2014-server/misc/server.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + ssl_client_certificate /srv/fic2014-server/misc/pki/cacert.crt; + ssl_verify_client on; + add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; + + if ($ssl_client_s_dn !~ "/C=FR/ST=France/O=Epita/OU=SRS/") + { + return 401; + } location / { if (-f $request_filename) { @@ -39,7 +53,7 @@ server { { if (!-e $document_root$document_uri) { return 404; } include /etc/nginx/fastcgi.conf; - fastcgi_pass 127.0.0.1:9000; + fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; break; } diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index e6291018..0491002f 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -1,8 +1,13 @@ - + 1381441316 + /srv/fic2014-server/misc/ + /srv/fic2014-server/submission/ ]]> + challenge-public + challenge + challenge-admin 0 diff --git a/onyx/tpl/bootstrap/clock.tpl b/onyx/tpl/bootstrap/clock.tpl index 10b4febb..7cbddfeb 100644 --- a/onyx/tpl/bootstrap/clock.tpl +++ b/onyx/tpl/bootstrap/clock.tpl @@ -1,11 +1,11 @@
      diff --git a/onyx/tpl/bootstrap/layout.tpl b/onyx/tpl/bootstrap/layout.tpl index 38523569..12be4bb4 100644 --- a/onyx/tpl/bootstrap/layout.tpl +++ b/onyx/tpl/bootstrap/layout.tpl @@ -5,7 +5,7 @@ {block name=title}Challenge FIC2014{/block} - + - + @@ -38,7 +38,7 @@ - + {block name=end}{/block} From 49554c01c8d9bfc3991c5fa109d584e228a74689 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Dec 2013 12:58:20 +0100 Subject: [PATCH 0152/2585] Modification for production --- gen_site.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen_site.sh b/gen_site.sh index 52544b99..442b3511 100755 --- a/gen_site.sh +++ b/gen_site.sh @@ -7,4 +7,4 @@ cd `dirname "$0"` mkdir -p out cd out -wget -c -m http://$BASEURL/ http://$BASEURL/connected/ +wget -c -m https://$BASEURL/ https://$BASEURL/connected/ From c7d0f7d1e126f5085a5f671c47c96d3204aabb47 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Wed, 11 Dec 2013 17:20:26 +0100 Subject: [PATCH 0153/2585] Modification for two servers --- nginx-server-common.conf | 43 ++++++++++++++++++++++++ nginx-server.conf | 18 ++++++++++ nginx.conf | 66 ++++++++++++++++++------------------- onyx/config/sample.root.xml | 10 +++--- 4 files changed, 98 insertions(+), 39 deletions(-) create mode 100644 nginx-server-common.conf create mode 100644 nginx-server.conf diff --git a/nginx-server-common.conf b/nginx-server-common.conf new file mode 100644 index 00000000..c5d27bc7 --- /dev/null +++ b/nginx-server-common.conf @@ -0,0 +1,43 @@ + access_log /var/log/nginx/fic.access_log; + error_log /var/log/nginx/fic.error_log; + + root /var/www/fic2014-server/htdocs; + index index.php; + + add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; + + location / { + if (-f $request_filename) { + break; + } + if (-d $request_filename) { + break; + } + + rewrite ^/(.*)$ /index.php?p=$1 last; + } + + location ~* \favicon.ico$ { + access_log off; + expires 1d; + add_header Cache-Control public; + } + + location ~ ^/(img|js|css)/ { + access_log off; + expires 7d; + add_header Cache-Control public; + } + + location ~ /(\.ht|\.git|\.svn|\.onyx) { + return 403; + } + + location ~ .*.php$ + { + if (!-e $document_root$document_uri) { return 404; } + include /etc/nginx/fastcgi.conf; + fastcgi_pass unix:/var/run/fastcgi/php-fpm.sock; + fastcgi_index index.php; + break; + } diff --git a/nginx-server.conf b/nginx-server.conf new file mode 100644 index 00000000..ba338775 --- /dev/null +++ b/nginx-server.conf @@ -0,0 +1,18 @@ +server { + listen 443 ssl; + listen [::]:443 ipv6only=on ssl; + + ssl_certificate /var/www/fic2014-server/misc/server.crt; + ssl_certificate_key /var/www/fic2014-server/misc/server.key; +# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +# ssl_prefer_server_ciphers on; +# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + + include /var/www/fic2014-server/nginx-server-common.conf; +} + +server { + listen [::1]:80 ipv6only=on; + + include /var/www/fic2014-server/nginx-server-common.conf; +} diff --git a/nginx.conf b/nginx.conf index b7fc7845..796a8d48 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,60 +1,58 @@ server { listen 443 ssl; - listen [::]:443 ipv6only=on; + listen [::]:443 ipv6only=on ssl; + + root /var/www/fic2014-server/htdocs/; access_log /var/log/nginx/fic.access_log; error_log /var/log/nginx/fic.error_log; - root /srv/fic2014-server/htdocs; - index index.php; - - ssl_certificate /srv/fic2014-server/misc/server.crt; - ssl_certificate_key /srv/fic2014-server/misc/server.key; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; - ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; - ssl_client_certificate /srv/fic2014-server/misc/pki/cacert.crt; - ssl_verify_client on; + ssl_certificate /var/www/fic2014-server/misc/server.crt; + ssl_certificate_key /var/www/fic2014-server/misc/server.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + ssl_client_certificate /var/www/fic2014-server/misc/pki/cacert.crt; + ssl_verify_client on; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; - if ($ssl_client_s_dn !~ "/C=FR/ST=France/O=Epita/OU=SRS/") + location / { - return 401; - } + default_type text/html; + if ($ssl_client_s_dn !~ "/C=FR/ST=France/O=Epita/OU=SRS/") + { + return 401; + } - location / { - if (-f $request_filename) { - break; - } - if (-d $request_filename) { - break; - } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Team1/") { + root /var/www/fic2014-server/htdocs/connected/166$1; - rewrite ^/(.*)$ /index.php?p=$1 last; + rewrite ^/submission-([0-9]+)-([0-9]+).html$ /submission.php?team=166&theme=$1&exercice=$2 last; + } } location ~* \favicon.ico$ { - access_log off; - expires 1d; - add_header Cache-Control public; + access_log off; + expires 1d; + add_header Cache-Control public; } location ~ ^/(img|js|css)/ { - access_log off; - expires 7d; - add_header Cache-Control public; + access_log off; + expires 7d; + add_header Cache-Control public; } location ~ /(\.ht|\.git|\.svn|\.onyx) { - deny all; + return 403; } - location ~ .*.php$ + location /submission.php { - if (!-e $document_root$document_uri) { return 404; } - include /etc/nginx/fastcgi.conf; - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_index index.php; + root /var/www/fic2014-server/; + include /etc/nginx/fastcgi.conf; + fastcgi_pass unix:/var/run/fastcgi/php-fpm.sock; break; } + } diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index 0491002f..d94fd659 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -1,13 +1,13 @@ - + - 1381441316 - /srv/fic2014-server/misc/ - /srv/fic2014-server/submission/ - ]]> + 1386827772 + /var/www/fic2014-server/misc/ + /var/www/fic2014-server/submission/ challenge-public challenge challenge-admin + ]]> 0 From bc877802cc0aa47468a6a00bf3fec3df60cbc867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Wed, 11 Dec 2013 18:10:39 +0100 Subject: [PATCH 0154/2585] Start check submission script --- check.pl | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 check.pl diff --git a/check.pl b/check.pl new file mode 100755 index 00000000..2c12913a --- /dev/null +++ b/check.pl @@ -0,0 +1,80 @@ +#!/usr/bin/env perl + +use v5.10.1; +use strict; +use warnings; +use DBI; + +use Data::Dumper; + +# First, read PHP configuration to extract some settings +my $profile; +my $submission_dir; + +open my $conf, "<", "onyx/config/root.xml"; +for my $p (<$conf>) +{ + if ($p =~ /<(?:option|var) name="(.*)">(.*)<\/(?:option|var)>/) + { + $profile = $2 if ($1 eq "profile"); + $submission_dir = $2 if ($1 eq "submission_dir"); + } +} +close $conf; + +die("No DB profile found") if ! $profile; +die("submission_dir is not a directory") if ! $submission_dir || ! -d $submission_dir; + +# Read db settings +my %db_settings; +open my $dbprof, "<", "onyx/db/$profile.profile.php"; +while (<$dbprof>) +{ + if (/\$___profile\[['"](.+)['"]\] = ['"](.+)['"]/) + { + $db_settings{$1} = $2; + } +} +close $dbprof; + +my $dbh; +# List all files to treat +opendir(my $dh, $submission_dir) || die "Can't opendir submission_dir: $!"; +for my $f (readdir $dh) +{ + if ($f =~ /^([0-9]+)-([0-9]+)-([0-9]+)$/) + { + my $team = $1; + my $theme = $2; + my $exercice = $3; + + open my $fh, "<", "$submission_dir/$f"; + my $solution = <$fh>; + close $fh; + + $dbh = DBI->connect("DBI:mysql:database=$db_settings{db};host=$db_settings{host};port=3306", + $db_settings{user}, $db_settings{pass}, + {'RaiseError' => 1, 'PrintError' => 1}) + or die $DBI::errstr if !$dbh; + + my $sth = query($dbh, "SELECT format, value FROM exercice_keys WHERE id_exercice = ".int($exercice)); + + while (my $row = get_row($sth)) + { + say Dumper($row); + } + } +} +closedir $dh; + +$dbh->disconnect() if $dbh; + +sub query +{ + my $sth = $_[0]->prepare($_[1]); + $sth->execute(); + + die($_[0]->errstr) if (!$sth); + + return $sth; +} From 9109c3e3e019da5f89ce957ba2d6a2c5c75d6fd6 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Wed, 11 Dec 2013 18:11:32 +0100 Subject: [PATCH 0155/2585] Add gencrl into CA.sh --- misc/CA.sh | 34 ++++++++++++++++++++++++------ onyx/include/admin/certificate.php | 4 +++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index 1f23c18e..aa0f6212 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -25,7 +25,7 @@ END_BOLD="" usage() { - echo "Usage: $0 (-newca|-newserver|-newclient NAME|-revoke NAME)" + echo "Usage: $0 (-newca|-newserver|-newclient NAME|-revoke NAME|-gencrl)" exit 1 } @@ -38,8 +38,9 @@ clean() mkdir -p ${TOP_DIR}/newcerts mkdir -p ${TOP_DIR}/private mkdir -p ${TOP_DIR}/pkcs + echo "01" > ${TOP_DIR}/crlnumber elif [ "$1" = "client" ]; then - rm -rf ${2}.key ${2}.csr + rm -rf ${TOP_DIR}/${2}.key ${TOP_DIR}/${2}.csr fi rm -rf $OUTPUT } @@ -151,7 +152,7 @@ case $1 in pass=`pwgen -n -B -y 12 1` - openssl req -batch -new -keyout ${2}.key -out ${2}.csr \ + openssl req -batch -new -keyout ${TOP_DIR}/${2}.key -out ${TOP_DIR}/${2}.csr \ -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} > $OUTPUT 2>&1 if [ $? -ne 0 ]; then cat $OUTPUT @@ -160,8 +161,8 @@ case $1 in fi echo -e "${GREEN}Signing the Client crt${COLOR_RST}" - openssl ca -batch -policy policy_match -out ${2}.crt \ - -config ${OPENSSL_CONF} -infiles ${2}.csr > $OUTPUT 2>&1 + openssl ca -batch -policy policy_match -out ${TOP_DIR}/${2}.crt \ + -config ${OPENSSL_CONF} -infiles ${TOP_DIR}/${2}.csr > $OUTPUT 2>&1 if [ $? -ne 0 ]; then echo -e "${RED}Signing failed for $2 ${COLOR_RST}" cat $OUTPUT @@ -169,7 +170,7 @@ case $1 in exit 3 fi echo -e "${GREEN}Export the Client files to pkcs12${COLOR_RST}" - openssl pkcs12 -export -inkey ${2}.key -in ${2}.crt -name ${2} \ + openssl pkcs12 -export -inkey ${TOP_DIR}/${2}.key -in ${TOP_DIR}/${2}.crt -name ${2} \ -passin pass:$pass -out ${TOP_DIR}/pkcs/${2}.p12 \ -passout pass:$pass > $OUTPUT 2>&1 if [ $? -ne 0 ]; then @@ -180,8 +181,9 @@ case $1 in else echo -e "Exported pkcs12 file is ${2}.p12" fi - mv ${2}.crt ${TOP_DIR}/certs + mv ${TOP_DIR}/${2}.crt ${TOP_DIR}/certs echo "$2:$pass" >> ${TOP_DIR}/../teams.pass + echo "$pass" clean "client" $2 ;; "-revoke" ) @@ -200,7 +202,25 @@ case $1 in fi rm ${TOP_DIR}/certs/${2}.crt rm ${TOP_DIR}/pkcs/${2}.p12 + + echo -e "${GREEN}Generate crl.pem${COLOR_RST}" + openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + echo -e "${RED}Generate crl.pem failed" + cat $OUTPUT + exit 5 + fi + ;; + "-gencrl" ) + echo -e "${GREEN}Generate crl.pem${COLOR_RST}" + openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + echo -e "${RED}Generate crl.pem failed" + cat $OUTPUT + exit 5 + fi + ;; * ) usage ;; diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index 580d6b62..5698f903 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -80,8 +80,10 @@ if (!empty($p[2])) //TODO check revoked attribute if (isset($name)) { - new_client($name, $misc_dir); + $output = new_client($name, $misc_dir); Team::set_revoked(FALSE, $name); + erreur($output, "sucess"); + return "admin/import_users"; } } elseif ($p[2] == "get") From 2b88c05dd77297235add38da2b700b3eeb3211ec Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Wed, 11 Dec 2013 18:12:12 +0100 Subject: [PATCH 0156/2585] Add ssl_crl in nginx.conf --- nginx.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.conf b/nginx.conf index 796a8d48..5bcfbb8e 100644 --- a/nginx.conf +++ b/nginx.conf @@ -15,7 +15,8 @@ server { ssl_client_certificate /var/www/fic2014-server/misc/pki/cacert.crt; ssl_verify_client on; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; - + ssl_crl /var/www/fic2014-server/misc/pki/crl.pem; + location / { default_type text/html; From 812f87c22e57266fe1358ddb190142f06e33bae6 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Wed, 11 Dec 2013 19:16:51 +0100 Subject: [PATCH 0157/2585] Exercice.class.php: Fixed intval in exercice id --- onyx/include/common/Exercice.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/onyx/include/common/Exercice.class.php b/onyx/include/common/Exercice.class.php index 8d8bf053..48010ae2 100644 --- a/onyx/include/common/Exercice.class.php +++ b/onyx/include/common/Exercice.class.php @@ -135,12 +135,14 @@ class Exercice do { array_push($checked, $exo); - $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = ".intval($exo)); + $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = ".$exo); $exo = $res['require']; $ret++; } while ($exo != "" && !in_array($exo, $checked)); $this->number = $ret; + + $db->deconnexion(); } function update($create) From b3beb516b05463d1d05c1766b737661067f94a4c Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Wed, 11 Dec 2013 19:18:45 +0100 Subject: [PATCH 0158/2585] Modify get_top for TOP3 themes --- onyx/include/common/Team.class.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index f2ba89e9..42f928ed 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -2,7 +2,7 @@ if(!defined('ONYX')) exit; -function cmp_team_pts($i1, $i2) +function cmp_team_pts($i1, $i2, $idTheme) { if ($i1->get_pts() == $i2->get_pts()){ $db = new BDD(); @@ -22,7 +22,7 @@ function cmp_team_pts($i1, $i2) return -1; } else{ - return ($i1->get_pts() < $i2->get_pts()) ? 1 : -1; + return ($i1->get_pts($idTheme) < $i2->get_pts($idTheme)) ? 1 : -1; } } @@ -147,17 +147,29 @@ class Team return $this->members; } - function get_pts() + function get_pts($themeID=-1) { if(!isset($this->points)) { $db = new BDD(); + $res = null; - $res = $db->unique_query("SELECT E.id, S.id_team, SUM(E.points) as sum_points + if ($themeID != -1) + { + $res = $db->unique_query("SELECT E.id, S.id_team, SUM(E.points) as sum_points FROM exercices E LEFT OUTER JOIN solved S ON E.id = S.id_exercice WHERE S.id_team = ".$this->id." GROUP BY S.id_team"); + } + else + { + $res = $db->unique_query("SELECT E.id, S.id_team, SUM(E.points) as sum_points + FROM exercices E + LEFT OUTER JOIN solved S ON E.id = S.id_exercice + WHERE S.id_team = ".$this->id." AND E.id_theme = ".$themeID." + GROUP BY S.id_team"); + } $db->deconnexion(); @@ -269,11 +281,11 @@ class Team return $array; } - public static function get_top($nb=0) + public static function get_top($nb=0, $idTheme=-1) { $teams = Team::get_teams(); - usort($teams, "cmp_team_pts"); + usort($teams, "cmp_team_pts", $idTheme); if ($nb != 0) $teams = array_slice($teams, 0, $nb); From 60ec66ee2d9646b04b4e68ec78cc44f4e665d8a2 Mon Sep 17 00:00:00 2001 From: Quentin Grosyeux Date: Thu, 12 Dec 2013 17:40:49 +0100 Subject: [PATCH 0159/2585] Summary display correction --- onyx/tpl/bootstrap/summary.tpl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/onyx/tpl/bootstrap/summary.tpl b/onyx/tpl/bootstrap/summary.tpl index d0350e49..6c2572de 100644 --- a/onyx/tpl/bootstrap/summary.tpl +++ b/onyx/tpl/bootstrap/summary.tpl @@ -14,6 +14,7 @@
    {$sum=0} + {$cpt=0} {$themeID=$theme->get_id()} {$solved_exercices=$my_team->get_solved_exercices($themeID)} {foreach from=$theme->get_exercices_ordered() item=exo} @@ -30,8 +31,12 @@ {else} {/if} + {$cpt=$cpt+1} {/foreach} - + {for $i=$cpt to $nbExoMax-1} + + {/for} + {$total=$total+$sum} {/foreach} @@ -42,4 +47,4 @@ -
    Membres Points PlaceRévoqué
    {$t->id}
    + + +
    {$t->team_name} {$t->slogan}{$t->get_pts()} {$t->get_rank()}{if $t->revoked}Oui{else}Non{/if}
    {$t->id}
    - - - - + + + + + + + +
    {$t->team_name} {$t->slogan}
    - Importer + + Importer {if $teams} - Exporter - Vider + + Exporter + + Vider {/if}
    {$t->team_name} {$t->slogan}
    {$t->id}
    - + From 5656d116afe5c354f7e0ecd436ab69b34b0b7c9b Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 1 Dec 2013 20:03:20 +0100 Subject: [PATCH 0146/2585] Fixed bad url in theme page --- onyx/include/admin/exercice.php | 13 ++++++++++--- onyx/tpl/bootstrap/admin/exercice.tpl | 12 ++++++++++-- onyx/tpl/bootstrap/admin/themes.tpl | 4 ++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/onyx/include/admin/exercice.php b/onyx/include/admin/exercice.php index 3a925efb..fa6858cd 100644 --- a/onyx/include/admin/exercice.php +++ b/onyx/include/admin/exercice.php @@ -5,9 +5,16 @@ if(!defined('ONYX')) exit; $p = $out[0]; if (isset($p[2])) - $template->assign("theme", $p[2]); +{ + $tmp = explode("-", $p[2]); + $id = intval($tmp[0]); + if ($id == 0) + return "404"; + $theme = new Theme($id); + $template->assign("theme", $theme); +} if (isset($p[3])) - $template->assign("ex", $p[3]); + $template->assign("ex", new Exercice($p[3], $theme)); -return "admin/exercice"; +return SALT_ADMIN."/exercice"; diff --git a/onyx/tpl/bootstrap/admin/exercice.tpl b/onyx/tpl/bootstrap/admin/exercice.tpl index 1537536f..605034b2 100644 --- a/onyx/tpl/bootstrap/admin/exercice.tpl +++ b/onyx/tpl/bootstrap/admin/exercice.tpl @@ -1,7 +1,15 @@ {extends file="admin/layout.tpl"} {block name=content}

    - Theme: {$theme}
    - Exercice: {$ex} + Theme: {$theme->name}
    + {if isset($ex)} + Exercice: {$ex->id} + {else} +

      + {foreach $theme->get_exercices_ordered() as $ex} +
    • {$ex->get_name()}
    • + {/foreach} +
    + {/if}

    {/block} diff --git a/onyx/tpl/bootstrap/admin/themes.tpl b/onyx/tpl/bootstrap/admin/themes.tpl index 150ded87..86c9bf2b 100644 --- a/onyx/tpl/bootstrap/admin/themes.tpl +++ b/onyx/tpl/bootstrap/admin/themes.tpl @@ -19,10 +19,10 @@ Exporter
    {$t->name}{$t->name} FIXME
    {$theme->get_name()}{$pts}{$sum}{$sum}
    {$total}
    + \ No newline at end of file From 0f7c1bc7e9381838be0c4ba002e90d9762f9981c Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 12 Dec 2013 16:43:01 +0100 Subject: [PATCH 0160/2585] Fixed sha1 Exercice.class --- onyx/include/common/Exercice.class.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/onyx/include/common/Exercice.class.php b/onyx/include/common/Exercice.class.php index 48010ae2..df3cde50 100644 --- a/onyx/include/common/Exercice.class.php +++ b/onyx/include/common/Exercice.class.php @@ -16,6 +16,8 @@ class Exercice function Exercice($id=null, $theme=null) { + global $VAR; + if (!empty($id)) { $db = new BDD(); @@ -33,7 +35,13 @@ class Exercice // Decode sha1 if ($this->files) foreach($this->files as &$f) + { + $f["path_orig"] = $f["path"]; + if (isset($VAR["files_dir"])) + $f["path"] = $VAR["files_dir"].$f["path"]; + $f["basename"] = basename($f["path"]); $f["sha1"] = strhex($f["sha1"]); + } $this->keys = $db->query("SELECT `id`, `format`, `value` FROM exercice_keys @@ -135,7 +143,7 @@ class Exercice do { array_push($checked, $exo); - $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = ".$exo); + $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = '".$exo."'"); $exo = $res['require']; $ret++; } while ($exo != "" && !in_array($exo, $checked)); @@ -181,7 +189,7 @@ class Exercice $format = $key['format']; $value = $key['value']; if (isset($key['id'])) - $kid = intval($key['id']); + $kid = $key['id']; else $kid = 0; @@ -219,14 +227,14 @@ class Exercice if (!isset($file['id'])) { $db->query("INSERT INTO exercice_files - VALUES (NULL, '".$id."', '".$path."', '".$name."', '".$sha1."');"); + VALUES (NULL, '".$id."', '".$path."', '".$name."', UNHEX('".$sha1."'));"); $this->files[$k]['id'] = $db->insert_id(); } else { $db->query("UPDATE exercice_files - SET `path` = '".$path."', `name` = '".$name."', `sha1` = '".$sha1."' + SET `path` = '".$path."', `name` = '".$name."', `sha1` = UNHEX('".$sha1."') WHERE id = ".$fid); } } From 01624d389c56a069de6ec9678607e4eb5d027aa1 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 12 Dec 2013 17:00:35 +0100 Subject: [PATCH 0161/2585] Fixed themes drop --- onyx/include/admin/list_themes.php | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/onyx/include/admin/list_themes.php b/onyx/include/admin/list_themes.php index b8e40b76..5b74f0b9 100644 --- a/onyx/include/admin/list_themes.php +++ b/onyx/include/admin/list_themes.php @@ -8,9 +8,11 @@ function remove_themes($id) $res = $db->query("SELECT id FROM exercices WHERE id_theme = ".$id); foreach($res as $r) { - $db->query("DELETE FROM exercice_files WHERE id_exercice = ".$id); - $db->query("DELETE FROM exercice_keys WHERE id_exercice = ".$id); - $db->query("DELETE FROM solved WHERE id_exercice = ".$id); + $id_ex = $r['id']; + $db->escape($id_ex); + $db->query("DELETE FROM exercice_files WHERE id_exercice = '".$id_ex."'"); + $db->query("DELETE FROM exercice_keys WHERE id_exercice = '".$id_ex."'"); + $db->query("DELETE FROM solved WHERE id_exercice = '".$id_ex."'"); } $db->query("DELETE FROM exercices WHERE id_theme = ".$id); @@ -29,10 +31,13 @@ if (!empty($_GET["delete"])) } else if (isset($_GET["drop"])) { - foreach(Theme::get_themes() as $thm) - { - remove_themes($thm->get_id()); - } + $db = new BDD(); + $db->query("TRUNCATE exercice_files"); + $db->query("TRUNCATE exercice_keys"); + $db->query("TRUNCATE exercices"); + $db->query("TRUNCATE themes"); + $db->query("TRUNCATE solved"); + $db->deconnexion(); header("Location: /".SALT_ADMIN."/themes"); exit; @@ -40,4 +45,4 @@ else if (isset($_GET["drop"])) $template->assign("themes", Theme::get_themes()); -return "admin/themes"; \ No newline at end of file +return "admin/themes"; From 60f950dd6c1055b61b2bb94e8381db5594b42f70 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 12 Dec 2013 18:02:16 +0100 Subject: [PATCH 0162/2585] Add file_dir into sample.root.xml --- onyx/config/sample.root.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index d94fd659..4d05ed20 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -2,6 +2,7 @@ 1386827772 + /var/www/fic2014-server/files/ /var/www/fic2014-server/misc/ /var/www/fic2014-server/submission/ challenge-public From 4b101ef4b2f0e39865ee10b2fbae0808764c8cc6 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 12 Dec 2013 19:33:18 +0100 Subject: [PATCH 0163/2585] Modify public theme --- onyx/tpl/bootstrap/public/home.tpl | 5 ++--- onyx/tpl/bootstrap/public/layout.tpl | 1 - onyx/tpl/bootstrap/summary.tpl | 6 +++--- onyx/tpl/bootstrap/teams/exercice.tpl | 4 ++-- onyx/tpl/bootstrap/teams/theme.tpl | 4 ++-- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index 6f0d757e..73af278d 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -1,9 +1,9 @@ {extends file="public/layout.tpl"} {block name=main} -
    +
    - +
    @@ -33,7 +33,6 @@ {/foreach}
    -
    {/block} diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index 1ce60ca4..d6022bdc 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -36,7 +36,6 @@ {foreach from=$teams item=my_team key=k}
    -

    {$my_team->get_name()}

    {include file="summary.tpl"}
    diff --git a/onyx/tpl/bootstrap/summary.tpl b/onyx/tpl/bootstrap/summary.tpl index 6c2572de..71b33b7c 100644 --- a/onyx/tpl/bootstrap/summary.tpl +++ b/onyx/tpl/bootstrap/summary.tpl @@ -1,7 +1,7 @@ - +
    - + {for $i=1 to $nbExoMax} {/for} @@ -47,4 +47,4 @@ -
    {$my_team->get_name()}Exercice {$i}{$total}
    \ No newline at end of file + diff --git a/onyx/tpl/bootstrap/teams/exercice.tpl b/onyx/tpl/bootstrap/teams/exercice.tpl index 387c43f8..f9151160 100644 --- a/onyx/tpl/bootstrap/teams/exercice.tpl +++ b/onyx/tpl/bootstrap/teams/exercice.tpl @@ -33,7 +33,7 @@ {if file_exists($file['path'])} - + @@ -56,7 +56,7 @@ {if $cur_exercice->has_solved($my_team)} Déjà résolu à {$cur_exercice->has_solved($my_team)|date_format:"%H:%M:%S"} :) {else} -
    +
    diff --git a/onyx/tpl/bootstrap/teams/theme.tpl b/onyx/tpl/bootstrap/teams/theme.tpl index 4b043282..14b4052f 100644 --- a/onyx/tpl/bootstrap/teams/theme.tpl +++ b/onyx/tpl/bootstrap/teams/theme.tpl @@ -6,9 +6,9 @@

    {foreach from=$cur_theme->get_exercices_ordered() item=exercice} {if $exercice->has_solved($my_team)} - {link class="btn btn-success" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name()}/{$exercice->get_id()}" label="{$exercice->get_name()}"} + {link class="btn btn-success" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name_url()}/{$exercice->get_id()}" label="{$exercice->get_name()}"} {elseif $exercice->is_unlocked($my_team)} - {link class="btn btn-primary" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name()}/{$exercice->get_id()}" label="{$exercice->get_name()}"} + {link class="btn btn-primary" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name_url()}/{$exercice->get_id()}" label="{$exercice->get_name()}"} {else} {$exercice->get_name()} {/if} From bbec08ac4ff80565fbe565f7167b0e5cb78b2b9f Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 13 Dec 2013 18:45:25 +0100 Subject: [PATCH 0164/2585] Server synchronisation --- check.pl | 58 +++++++++++++++++++++++++--- gen_site.sh | 83 +++++++++++++++++++++++++++++++++++++++- nginx-server-common.conf | 7 +++- nginx.conf | 41 +++++++++++++++----- submission.php | 24 ++++++++++++ synchro.sh | 23 +++++++++++ 6 files changed, 218 insertions(+), 18 deletions(-) create mode 100644 submission.php create mode 100755 synchro.sh diff --git a/check.pl b/check.pl index 2c12913a..9d88f259 100755 --- a/check.pl +++ b/check.pl @@ -4,14 +4,20 @@ use v5.10.1; use strict; use warnings; use DBI; +use File::Basename; -use Data::Dumper; +#Return number of good solutions +my $exit = 0; + +my $root = dirname(__FILE__); + +chdir($root); # First, read PHP configuration to extract some settings my $profile; my $submission_dir; -open my $conf, "<", "onyx/config/root.xml"; +open my $conf, "<", "$root/onyx/config/root.xml"; for my $p (<$conf>) { if ($p =~ /<(?:option|var) name="(.*)">(.*)<\/(?:option|var)>/) @@ -27,7 +33,7 @@ die("submission_dir is not a directory") if ! $submission_dir || ! -d $submissio # Read db settings my %db_settings; -open my $dbprof, "<", "onyx/db/$profile.profile.php"; +open my $dbprof, "<", "$root/onyx/db/$profile.profile.php"; while (<$dbprof>) { if (/\$___profile\[['"](.+)['"]\] = ['"](.+)['"]/) @@ -42,8 +48,10 @@ my $dbh; opendir(my $dh, $submission_dir) || die "Can't opendir submission_dir: $!"; for my $f (readdir $dh) { - if ($f =~ /^([0-9]+)-([0-9]+)-([0-9]+)$/) + if ($f =~ /^([0-9]+)-([0-9]+)-([a-zA-Z0-9_]+)$/) { + my $good = -1; + my $team = $1; my $theme = $2; my $exercice = $3; @@ -57,18 +65,51 @@ for my $f (readdir $dh) {'RaiseError' => 1, 'PrintError' => 1}) or die $DBI::errstr if !$dbh; - my $sth = query($dbh, "SELECT format, value FROM exercice_keys WHERE id_exercice = ".int($exercice)); + my $sth = query($dbh, "SELECT format, value FROM exercice_keys WHERE id_exercice = '$exercice';"); + # Check solutions while (my $row = get_row($sth)) { - say Dumper($row); + $good = 1 if ($good == -1); + + my $type = @$row[0]; + my $sol = @$row[1]; + + if ($type eq "raw" && $sol ne $solution) { + $good = 0; + last; + } + elsif ($type ne "raw") { + $good = 0; + warn "$type not implemented"; + last; + } } + + # Register solve + if ($good == -1) { + say "Exercice $exercice doesn't exist ; given by team $team in theme $theme."; + } + elsif ($good == 1) + { + say "Team $team solve exercice $exercice in $theme at ".localtime(); + query($dbh, "INSERT INTO solved (id_team, id_exercice, time) VALUES ($team, '$exercice', CURRENT_TIMESTAMP);"); + $exit++; + } + else { + say "Team $team didn't give the correct answer for exercice $exercice."; + } + + # Remove the file + unlink("$submission_dir/$f"); } } closedir $dh; $dbh->disconnect() if $dbh; +exit( $exit > 126 ? 126 : $exit ); + sub query { my $sth = $_[0]->prepare($_[1]); @@ -78,3 +119,8 @@ sub query return $sth; } + +sub get_row +{ + return $_[0]->fetchrow_arrayref(); +} diff --git a/gen_site.sh b/gen_site.sh index 442b3511..974eeb67 100755 --- a/gen_site.sh +++ b/gen_site.sh @@ -1,10 +1,91 @@ #!/bin/sh BASEURL="localhost" +SALT_TEAM="connected" +OUT_TEAM="./teams" + +MAX_PARAL=9 + +DEBUG=0 + cd `dirname "$0"` +if [ "$UID" = "0" ] +then + SCRIPT=`pwd`/`basename "$0"` + su -c "sh -c '$SCRIPT $@'" synchro + exit $? +fi + +if [ -f "/tmp/generate_site" ] +then + echo "This script is already running" 1>&2 + echo "Remove the file /tmp/generate_site if you are sure this is not true" 1>&2 + exit 1 +fi + +touch /tmp/generate_site + +WGET_OPT="--no-check-certificate -c" + +if [ $DEBUG -ne 1 ] +then + WGET_OPT="-q" +fi + mkdir -p out cd out -wget -c -m https://$BASEURL/ https://$BASEURL/connected/ +# First, remove existing version if any +rm -rf "$BASEURL" "$OUT_TEAM" + +wget $WGET_OPT -m -b "http://$BASEURL/" -o /dev/null + +mkdir -p "$BASEURL" +ln -sf "`pwd`/../files/" "$BASEURL/files" + +NB=0 +PIDLIST= +# Get list of teams and fetch them in parallel +for l in $(curl -k "http://$BASEURL/$SALT_TEAM/" 2> /dev/null | grep -oE "/[^/]+/[0-9]+/") +do + ( + wget $WGET_OPT -m "http://$BASEURL/$l" + + for m in $(grep -R " Date: Fri, 13 Dec 2013 18:48:13 +0100 Subject: [PATCH 0165/2585] Thursday release --- .gitignore | 1 + misc/openssl.cnf | 6 +++--- onyx/include/common/Team.class.php | 15 +++++++++------ onyx/include/common/Theme.class.php | 5 +++++ onyx/tpl/bootstrap/public/layout.tpl | 2 +- onyx/tpl/bootstrap/summary.tpl | 2 +- onyx/tpl/bootstrap/teams/me.tpl | 1 - 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index cb02566c..b1d213ad 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ onyx/config/root.xml onyx/db/*.profile.php onyx/tpl/*/*.html submission/* +misc/openssl.cnf diff --git a/misc/openssl.cnf b/misc/openssl.cnf index a8c067f9..a0183194 100644 --- a/misc/openssl.cnf +++ b/misc/openssl.cnf @@ -39,7 +39,7 @@ default_ca = CA_default # The default ca section #################################################################### [ CA_default ] -dir = /srv/fic2014-server/misc//pki #DIR # Where everything is kept +dir = /var/www/fic2014-server/misc//pki #DIR # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. @@ -147,7 +147,7 @@ organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = SRS commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_default = FIC2014 Server #COMMONNAME +commonName_default = Groupe_8#COMMONNAME commonName_max = 64 emailAddress = Email Address @@ -176,7 +176,7 @@ basicConstraints=CA:FALSE # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. -nsCertType = server #CERTTYPE +nsCertType = client #CERTTYPE # For an object signing certificate this would be used. # nsCertType = objsign diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 42f928ed..83aae4e7 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -121,6 +121,10 @@ class Team return $this->team_name; } + function get_name_url() { + return urlencode($this->team_name); + } + function get_auth_level() { return $this->auth_level; } @@ -195,10 +199,10 @@ class Team function get_rank() { $teams = Team::get_top(); - for ($i = 0; $i < 10; $i++){ - $tid = $teams[$i]->get_id(); - if ($tid == $this->id) - return $i; + foreach($teams as $k => $t) + { + if ($t->get_id() == $this->id) + return $k + 1; } return 0; @@ -232,9 +236,8 @@ class Team $i = 0; if ($ids) { - foreach ($ids as $id){ + foreach ($ids as $id) $array[] = new Exercice($id['id_exercice']); - } } return $array; diff --git a/onyx/include/common/Theme.class.php b/onyx/include/common/Theme.class.php index 15f81d41..9ff832c4 100644 --- a/onyx/include/common/Theme.class.php +++ b/onyx/include/common/Theme.class.php @@ -60,6 +60,11 @@ class Theme return $this->name; } + function get_name_url() + { + return urlencode($this->name); + } + function get_id() { return $this->id; diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index d6022bdc..a71a787b 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -54,7 +54,7 @@ $(document).ready(function() { update_end(); $('#carousel-team').carousel({ - interval: 2000 }); + interval: 5000 }); setInterval( function() { update_end(); diff --git a/onyx/tpl/bootstrap/summary.tpl b/onyx/tpl/bootstrap/summary.tpl index 71b33b7c..e65c6d12 100644 --- a/onyx/tpl/bootstrap/summary.tpl +++ b/onyx/tpl/bootstrap/summary.tpl @@ -12,7 +12,7 @@ {$total=0} {foreach from=$themes item=theme} - {$theme->get_name()} + {$theme->get_name()} {$sum=0} {$cpt=0} {$themeID=$theme->get_id()} diff --git a/onyx/tpl/bootstrap/teams/me.tpl b/onyx/tpl/bootstrap/teams/me.tpl index 7b73a58a..ca4ec59d 100644 --- a/onyx/tpl/bootstrap/teams/me.tpl +++ b/onyx/tpl/bootstrap/teams/me.tpl @@ -9,7 +9,6 @@ {if not empty($members)} - From 134f6be772fb13ef6e97a2b3afa9c826c3177cc5 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 13 Dec 2013 19:02:44 +0100 Subject: [PATCH 0166/2585] Disable the print of difficulty (always 0) --- onyx/tpl/bootstrap/teams/exercice.tpl | 1 - 1 file changed, 1 deletion(-) diff --git a/onyx/tpl/bootstrap/teams/exercice.tpl b/onyx/tpl/bootstrap/teams/exercice.tpl index f9151160..d07770c8 100644 --- a/onyx/tpl/bootstrap/teams/exercice.tpl +++ b/onyx/tpl/bootstrap/teams/exercice.tpl @@ -7,7 +7,6 @@
      -
    • Difficulté : {$cur_exercice->level}
    • Gain : {$cur_exercice->points}
    • Description : {$cur_exercice->statement}
    From 6cabc4003f2b9a4b38587f82b09bce3a11ac6b91 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 13 Dec 2013 20:03:04 +0100 Subject: [PATCH 0167/2585] Revert "Modify get_top for TOP3 themes" This reverts commit b3beb516b05463d1d05c1766b737661067f94a4c. --- onyx/include/common/Team.class.php | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 83aae4e7..35a48d45 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -2,7 +2,7 @@ if(!defined('ONYX')) exit; -function cmp_team_pts($i1, $i2, $idTheme) +function cmp_team_pts($i1, $i2) { if ($i1->get_pts() == $i2->get_pts()){ $db = new BDD(); @@ -22,7 +22,7 @@ function cmp_team_pts($i1, $i2, $idTheme) return -1; } else{ - return ($i1->get_pts($idTheme) < $i2->get_pts($idTheme)) ? 1 : -1; + return ($i1->get_pts() < $i2->get_pts()) ? 1 : -1; } } @@ -151,29 +151,17 @@ class Team return $this->members; } - function get_pts($themeID=-1) + function get_pts() { if(!isset($this->points)) { $db = new BDD(); - $res = null; - if ($themeID != -1) - { - $res = $db->unique_query("SELECT E.id, S.id_team, SUM(E.points) as sum_points + $res = $db->unique_query("SELECT E.id, S.id_team, SUM(E.points) as sum_points FROM exercices E LEFT OUTER JOIN solved S ON E.id = S.id_exercice WHERE S.id_team = ".$this->id." GROUP BY S.id_team"); - } - else - { - $res = $db->unique_query("SELECT E.id, S.id_team, SUM(E.points) as sum_points - FROM exercices E - LEFT OUTER JOIN solved S ON E.id = S.id_exercice - WHERE S.id_team = ".$this->id." AND E.id_theme = ".$themeID." - GROUP BY S.id_team"); - } $db->deconnexion(); @@ -284,11 +272,11 @@ class Team return $array; } - public static function get_top($nb=0, $idTheme=-1) + public static function get_top($nb=0) { $teams = Team::get_teams(); - usort($teams, "cmp_team_pts", $idTheme); + usort($teams, "cmp_team_pts"); if ($nb != 0) $teams = array_slice($teams, 0, $nb); From 10eb72688fce178e42ee60f0c7a75eefdc7a78c7 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 13 Dec 2013 20:11:26 +0100 Subject: [PATCH 0168/2585] Add some check before solving exercice --- check.pl | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/check.pl b/check.pl index 9d88f259..4c87106b 100755 --- a/check.pl +++ b/check.pl @@ -65,7 +65,7 @@ for my $f (readdir $dh) {'RaiseError' => 1, 'PrintError' => 1}) or die $DBI::errstr if !$dbh; - my $sth = query($dbh, "SELECT format, value FROM exercice_keys WHERE id_exercice = '$exercice';"); + my $sth = query($dbh, "SELECT format, value FROM exercice_keys WHERE id_exercice = ".$dbh->quote($exercice)); # Check solutions while (my $row = get_row($sth)) @@ -88,16 +88,40 @@ for my $f (readdir $dh) # Register solve if ($good == -1) { - say "Exercice $exercice doesn't exist ; given by team $team in theme $theme."; + say localtime().": Exercice $exercice doesn't exist ; given by team $team in theme $theme."; } elsif ($good == 1) { - say "Team $team solve exercice $exercice in $theme at ".localtime(); - query($dbh, "INSERT INTO solved (id_team, id_exercice, time) VALUES ($team, '$exercice', CURRENT_TIMESTAMP);"); - $exit++; + # Check if the exercice exists + $sth = query($dbh, "SELECT `require` FROM exercices E WHERE E.id_theme = $theme AND E.id = ".$dbh->quote($exercice)); + if ($sth->rows && (my $row = get_row($sth))) + { + # Check if the team has solved dependancies + $sth = query($dbh, "SELECT COUNT(S.id) FROM solved S WHERE S.id_exercice = ".$dbh->quote(@$row[0])) if @$row[0]; + if (! (@$row[0] && $sth->rows)) + { + # Check if the team has not already solved this exercice + $sth = query($dbh, "SELECT COUNT(S.id) FROM solved S WHERE S.id_exercice = ".$dbh->quote($exercice)); + if (! $sth->rows) + { + say localtime().": Team $team solve exercice $exercice in $theme"; + query($dbh, "INSERT INTO solved (id_team, id_exercice, time) VALUES ($team, ".$dbh->quote($exercice).", CURRENT_TIMESTAMP);"); + $exit++; + } + else { + warn localtime().": Team $team try to solve exercice $exercice in $theme but ALREADY solved it"; + } + } + else { + warn localtime().": Team $team try to solve exercice $exercice in $theme but has NOT SOLVED required exercice ".@$row[0]; + } + } + else { + warn localtime().": Team $team try to solve exercice $exercice in $theme but does not exist"; + } } else { - say "Team $team didn't give the correct answer for exercice $exercice."; + say localtime().": Team $team didn't give the correct answer for exercice $exercice."; } # Remove the file From c349769425ada01d6755bec979393763e7695473 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sat, 14 Dec 2013 06:11:14 +0100 Subject: [PATCH 0169/2585] Friday release --- check.pl | 17 +++--- clear_cache.sh | 15 +++++ gen_site.sh | 83 ++++++++++++++++++++++---- launch.sh | 53 ++++++++++++++++ nginx.conf | 1 + onyx/include/admin/list_themes.php | 2 + onyx/include/common/Exercice.class.php | 58 ++++++++++++++++-- onyx/include/common/Team.class.php | 47 ++++++++------- onyx/include/common/Theme.class.php | 19 +++++- onyx/require/cache.php | 31 ++++++---- onyx/tpl/bootstrap/public/home.tpl | 26 ++++++-- onyx/tpl/bootstrap/public/layout.tpl | 25 +++----- onyx/tpl/bootstrap/public/score.tpl | 1 - onyx/tpl/bootstrap/summary.tpl | 10 ++-- onyx/tpl/bootstrap/teams/exercice.tpl | 2 +- synchro.sh | 18 ++++-- 16 files changed, 319 insertions(+), 89 deletions(-) create mode 100755 clear_cache.sh create mode 100755 launch.sh diff --git a/check.pl b/check.pl index 4c87106b..147e5ca0 100755 --- a/check.pl +++ b/check.pl @@ -88,23 +88,26 @@ for my $f (readdir $dh) # Register solve if ($good == -1) { - say localtime().": Exercice $exercice doesn't exist ; given by team $team in theme $theme."; + say STDERR localtime().": Exercice $exercice doesn't exist ; given by team $team in theme $theme."; } elsif ($good == 1) { # Check if the exercice exists $sth = query($dbh, "SELECT `require` FROM exercices E WHERE E.id_theme = $theme AND E.id = ".$dbh->quote($exercice)); - if ($sth->rows && (my $row = get_row($sth))) + if ($sth->rows) { + my $row = get_row($sth); + # Check if the team has solved dependancies - $sth = query($dbh, "SELECT COUNT(S.id) FROM solved S WHERE S.id_exercice = ".$dbh->quote(@$row[0])) if @$row[0]; - if (! (@$row[0] && $sth->rows)) + $sth = query($dbh, "SELECT S.id FROM solved S WHERE S.id_exercice = ".$dbh->quote(@$row[0])) if @$row[0]; + if (! @$row[0] || $sth->rows) { # Check if the team has not already solved this exercice - $sth = query($dbh, "SELECT COUNT(S.id) FROM solved S WHERE S.id_exercice = ".$dbh->quote($exercice)); + $sth = query($dbh, "SELECT S.id FROM solved S WHERE S.id_exercice = ".$dbh->quote($exercice)); if (! $sth->rows) { - say localtime().": Team $team solve exercice $exercice in $theme"; + say $team; + say STDERR localtime().": Team $team solve exercice $exercice in $theme"; query($dbh, "INSERT INTO solved (id_team, id_exercice, time) VALUES ($team, ".$dbh->quote($exercice).", CURRENT_TIMESTAMP);"); $exit++; } @@ -121,7 +124,7 @@ for my $f (readdir $dh) } } else { - say localtime().": Team $team didn't give the correct answer for exercice $exercice."; + say STDERR localtime().": Team $team didn't give the correct answer for exercice $exercice."; } # Remove the file diff --git a/clear_cache.sh b/clear_cache.sh new file mode 100755 index 00000000..cb528dd4 --- /dev/null +++ b/clear_cache.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +cd `dirname "$0"` + +for n in "$@" +do + MD5=`echo -n $n | md5sum | cut -d " " -f 1` + if [ -f "onyx/cache/$MD5.cache.php" ] + then + rm -f "onyx/cache/$MD5.cache.php" + echo "--- $n deleted" + else + echo "/!\\ $n not found ($MD5)" + fi +done diff --git a/gen_site.sh b/gen_site.sh index 974eeb67..4667aea2 100755 --- a/gen_site.sh +++ b/gen_site.sh @@ -4,7 +4,7 @@ BASEURL="localhost" SALT_TEAM="connected" OUT_TEAM="./teams" -MAX_PARAL=9 +MAX_PARAL=10 DEBUG=0 @@ -34,8 +34,13 @@ then WGET_OPT="-q" fi +./clear_cache.sh top + mkdir -p out -cd out + +ORIG_DIR=`pwd` +MYTMPDIR=`mktemp -d` +cd "$MYTMPDIR" # First, remove existing version if any rm -rf "$BASEURL" "$OUT_TEAM" @@ -43,15 +48,38 @@ rm -rf "$BASEURL" "$OUT_TEAM" wget $WGET_OPT -m -b "http://$BASEURL/" -o /dev/null mkdir -p "$BASEURL" -ln -sf "`pwd`/../files/" "$BASEURL/files" +ln -sf "$ORIG_DIR/files/" "$BASEURL/files" + +# Get list of teams +TEAMS= +if [ $# -gt 0 ] +then + while [ $# -gt 0 ] + do + TEAMS="$TEAMS /$SALT_TEAM/$1/" + shift + done + FULLSYNC=0 +else + for l in $(curl -k "http://$BASEURL/$SALT_TEAM/" 2> /dev/null | grep -oE "/[^/]+/[0-9]+/") + do + TEAMS="$TEAMS $l" + done + FULLSYNC=1 +fi + +echo "Team list to generate: $TEAMS" NB=0 PIDLIST= -# Get list of teams and fetch them in parallel -for l in $(curl -k "http://$BASEURL/$SALT_TEAM/" 2> /dev/null | grep -oE "/[^/]+/[0-9]+/") +# Fetch them in parallel +for l in $TEAMS do ( - wget $WGET_OPT -m "http://$BASEURL/$l" + if ! wget $WGET_OPT -m "http://$BASEURL/$l" + then + exit 1 + fi for m in $(grep -R "&2 + exit $ERR + +else + MOREOPT= + if [ "$FULL" -eq "1" ] + then + MOREOPT="--delete" + fi + # Ok, now, sync files with prod + rsync -av $MOREOPT * "$ORIG_DIR/out" + + cd "$ORIG_DIR" + rm -rf "$MYTMPDIR" +fi diff --git a/launch.sh b/launch.sh new file mode 100755 index 00000000..5847e65c --- /dev/null +++ b/launch.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +cd `dirname "$0"` + +if [ "$UID" = "0" ] +then + SCRIPT=`pwd`/`basename "$0"` + su -c "sh $SCRIPT" synchro + exit $? +fi + +touch ./logs/checks.log +tail -f ./logs/checks.log & + +FULLREGEN=0 + +while true; +do + if [ "$FULLREGEN" != "0" ] + then + ./synchro.sh + else + ./synchro.sh delete + fi + + if [ `ls submission | wc -l` -gt 1 ] + then + TMPF=`mktemp` + if ! ./check.pl 2>> ./logs/checks.log > "$TMPF" + then + FULLREGEN=1 + fi + + if [ `cat "$TMPF" | wc -l` -gt 0 ] + then + while ! cat "$TMPF" | xargs ./gen_site.sh + do + echo "FAIL regeneration, retry..." 1>&2 + done + fi + rm "$TMPF" + + elif [ "$FULLREGEN" != "0" ] + then + while ! ./gen_site.sh; do + echo "FAIL regeneration, retry..." 1>&2 + done + FULLREGEN=0 + + else + sleep 1 + fi +done diff --git a/nginx.conf b/nginx.conf index 1ed8be7d..04144ca7 100644 --- a/nginx.conf +++ b/nginx.conf @@ -21,6 +21,7 @@ server { location / { default_type text/html; + expires epoch; set $team 0; diff --git a/onyx/include/admin/list_themes.php b/onyx/include/admin/list_themes.php index 5b74f0b9..a52a60f1 100644 --- a/onyx/include/admin/list_themes.php +++ b/onyx/include/admin/list_themes.php @@ -18,6 +18,8 @@ function remove_themes($id) $db->query("DELETE FROM exercices WHERE id_theme = ".$id); $db->query("DELETE FROM themes WHERE id = ".$id); $db->deconnexion(); + + Cache::del("ordered_th".$id); } if (!empty($_GET["delete"])) diff --git a/onyx/include/common/Exercice.class.php b/onyx/include/common/Exercice.class.php index df3cde50..d74111f9 100644 --- a/onyx/include/common/Exercice.class.php +++ b/onyx/include/common/Exercice.class.php @@ -75,6 +75,23 @@ class Exercice } } + static function __set_state(array $array) + { + $tmp = new Exercice(); + + $tmp->id = $array["id"]; + $tmp->number = $array["number"]; + $tmp->theme = $array["theme"]; + $tmp->require = $array["require"]; + $tmp->level = $array["level"]; + $tmp->points = $array["points"]; + $tmp->statement = $array["statement"]; + $tmp->files = $array["files"]; + $tmp->keys = $array["keys"]; + + return $tmp; + } + function get_id() { return $this->id; @@ -89,10 +106,12 @@ class Exercice // trié par date function get_solved() { - $db = new BDD(); + $id = $this->id; + $db = new BDD(); + $db->escape($id); $res = $db->query("SELECT `id_team`, `time` FROM solved - WHERE id_exercice = '$this->id' + WHERE id_exercice = '$id' ORDER BY time"); $db->deconnexion(); @@ -105,11 +124,13 @@ class Exercice if ($this->require == "") return 1; - $db = new BDD(); + $req = $this->require; + $db = new BDD(); + $db->escape($req); $res = $db->unique_query("SELECT `id` FROM solved WHERE id_team = '".intval($team->id)."' - AND id_exercice = '$this->require'"); + AND id_exercice = '$req'"); $db->deconnexion(); if (empty($res)) return 0; @@ -118,9 +139,11 @@ class Exercice function has_solved($team) { - $db = new BDD(); + $id = $this->id; - $res = $db->unique_query("SELECT `time` FROM solved WHERE id_exercice = '$this->id' + $db = new BDD(); + $db->escape($id); + $res = $db->unique_query("SELECT `time` FROM solved WHERE id_exercice = '$id' AND id_team = ".intval($team->get_id())); $db->deconnexion(); @@ -143,6 +166,7 @@ class Exercice do { array_push($checked, $exo); + $db->escape($exo); $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = '".$exo."'"); $exo = $res['require']; $ret++; @@ -278,6 +302,28 @@ class Exercice return $res['max']; } + + public function first_to_solve_exercice() + { + $db = new BDD(); + + $id = $this->id; + $db->escape($id); + + $res = $db->unique_query("SELECT t3.team_name as result + FROM solved AS t1 + INNER JOIN ( + SELECT MIN(s.time) AS minTime + FROM solved AS s + WHERE s.id_exercice = '".$id."' + ) AS t2 + INNER JOIN teams AS t3 ON t1.id_team = t3.id + WHERE t1.time = t2.minTime"); + $db->deconnexion(); + + return $res['result']; + } + } class ExerciceNotFoundException extends Exception diff --git a/onyx/include/common/Team.class.php b/onyx/include/common/Team.class.php index 35a48d45..88b4c8ec 100644 --- a/onyx/include/common/Team.class.php +++ b/onyx/include/common/Team.class.php @@ -60,6 +60,22 @@ class Team } } + static function __set_state(array $array) + { + $tmp = new Team(); + + $tmp->id = $array["id"]; + $tmp->team_name = $array["team_name"]; + $tmp->key_hash = $array["key_hash"]; + $tmp->auth_level = $array["auth_level"]; + $tmp->slogan = $array["slogan"]; + $tmp->members = $array["members"]; + $tmp->points = $array["points"]; + $tmp->revoked = $array["revoked"]; + + return $tmp; + } + // Class methods function update() { @@ -274,14 +290,20 @@ class Team public static function get_top($nb=0) { - $teams = Team::get_teams(); + $top = Cache::read("top"); + if (empty($top)) + { + $top = Team::get_teams(); - usort($teams, "cmp_team_pts"); + usort($top, "cmp_team_pts"); + + Cache::set("top", $top); + } if ($nb != 0) - $teams = array_slice($teams, 0, $nb); + $top = array_slice($top, 0, $nb); - return $teams; + return $top; } public static function get_nb_teams() @@ -292,21 +314,4 @@ class Team return $res['count_teams']; } - - public static function first_to_solve_exercice($id_exercice) - { - $db = new BDD(); - $res = $db->unique_query("SELECT t3.team_name as result - FROM solved AS t1 - INNER JOIN ( - SELECT MIN(s.time) AS minTime - FROM solved AS s - WHERE s.id_exercice = ".$id_exercice." - ) AS t2 - INNER JOIN teams AS t3 ON t1.id_team = t3.id - WHERE t1.time = t2.minTime"); - $db->deconnexion(); - - return $res['result']; - } } diff --git a/onyx/include/common/Theme.class.php b/onyx/include/common/Theme.class.php index 9ff832c4..c155fcb7 100644 --- a/onyx/include/common/Theme.class.php +++ b/onyx/include/common/Theme.class.php @@ -29,6 +29,16 @@ class Theme } } + static function __set_state(array $array) + { + $tmp = new Theme(); + + $tmp->id = $array["id"]; + $tmp->name = $array["name"]; + + return $tmp; + } + function update() { $name = $this->name; @@ -52,6 +62,8 @@ class Theme } $db->deconnexion(); + Cache::del("ordered_th".$this->id); + return ($aff == 1); } @@ -93,6 +105,10 @@ class Theme function get_exercices_ordered() { + $res = Cache::read("ordered_th".$this->id); + if (!empty($res)) + return $res; + $db = new BDD(); $res = $db->query("SELECT E.id, E.require FROM exercices E INNER JOIN themes T ON T.id = E.id_theme @@ -130,13 +146,14 @@ class Theme foreach($res as &$r) $r = new Exercice($r["id"]); + Cache::set("ordered_th".$this->id, $res); return $res; } public static function get_themes() { $db = new BDD(); - $ids = $db->query("SELECT `id` FROM `themes`"); + $ids = $db->query("SELECT `id` FROM `themes` ORDER BY `name`"); $db->deconnexion(); $array = array(); diff --git a/onyx/require/cache.php b/onyx/require/cache.php index 70564154..0971f736 100644 --- a/onyx/require/cache.php +++ b/onyx/require/cache.php @@ -2,34 +2,45 @@ class Cache { - + static function set($id,$var) { $file = ''; - - file_put_contents(ONYX.'cache/'.md5($id).'.cache.php',$file) or trigger_error('dossier cache inaccessible en écriture.',E_USER_ERROR); + + $tmpfname = tempnam("/tmp", "cache"); + + if(file_put_contents($tmpfname, $file, LOCK_EX) !== FALSE) + rename($tmpfname, ONYX.'cache/'.md5($id).'.cache.php') or trigger_error('dossier cache inaccessible en écriture.',E_USER_ERROR); + else + trigger_error('impossible d\'?crire dans '.$tmpfname,E_USER_ERROR); } - + static function read($id) { if(!is_readable(ONYX.'cache/'.md5($id).'.cache.php')) return FALSE; - - include(ONYX.'cache/'.md5($id).'.cache.php'); - if(!$cache) return FALSE; + + $tmpfname = tempnam("/tmp", "cache"); + copy(ONYX.'cache/'.md5($id).'.cache.php', $tmpfname); + + include($tmpfname); + + unlink($tmpfname); + + if(empty($cache)) return FALSE; return $cache; } - + static function del($id) { if(!is_file(ONYX.'cache/'.md5($id).'.cache.php')) return FALSE; return unlink(ONYX.'cache/'.md5($id).'.cache.php'); } - + static function flush() { foreach(glob(ONYX.'cache/*.cache.php') as $file) unlink($file); } - + } ?> \ No newline at end of file diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index 73af278d..e97c2cef 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -1,9 +1,13 @@ {extends file="public/layout.tpl"} {block name=main} -
    - -
    # Prénom Nom Pseudonyme
    + {if isset($teams)} +
    @@ -21,7 +25,7 @@ {foreach from=$theme->get_exercices_ordered() item=exo} {$teamName=""} {for $i=0 to $nbExoMax} - {$teamName=Team::first_to_solve_exercice($exo->get_id())} + {$teamName=$exo->first_to_solve_exercice()} {/for} {if $teamName != ""} @@ -33,6 +37,20 @@ {/foreach}
    {$teamName}
    +

    +
    + {foreach from=$teams item=my_team key=k} +
    +
    + {include file="summary.tpl"} +
    + {/foreach} +
    +
    +{/if} + + + {/block} diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index a71a787b..da0bfa40 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -17,32 +17,23 @@ {/if}
    -
    +

    Top 10

    {foreach from=$top item=t key=k} -
    {$k+1}. {link href="{$t->id}-{$t->get_name()}" href_prefix="/" label=$t->get_name()}
    +
    {$k+1}. {link href="{$t->id}-{$t->get_name()}" href_prefix="/" label=$t->get_name()} + +{$t->get_pts()} + +
    {/foreach}
    -
    +
    {block name=main}{/block}
    -{if isset($teams)} - -{/if}
    {/block} @@ -54,7 +45,7 @@ $(document).ready(function() { update_end(); $('#carousel-team').carousel({ - interval: 5000 }); + interval: 10000 }); setInterval( function() { update_end(); diff --git a/onyx/tpl/bootstrap/public/score.tpl b/onyx/tpl/bootstrap/public/score.tpl index 5b113b44..1bfec7c4 100644 --- a/onyx/tpl/bootstrap/public/score.tpl +++ b/onyx/tpl/bootstrap/public/score.tpl @@ -2,7 +2,6 @@ {block name=main}
    -

    {$my_team->get_name()}

    {include file="summary.tpl"}
    {/block} diff --git a/onyx/tpl/bootstrap/summary.tpl b/onyx/tpl/bootstrap/summary.tpl index e65c6d12..1eed15df 100644 --- a/onyx/tpl/bootstrap/summary.tpl +++ b/onyx/tpl/bootstrap/summary.tpl @@ -1,7 +1,7 @@ - +
    - + {for $i=1 to $nbExoMax} {/for} @@ -12,7 +12,7 @@ {$total=0} {foreach from=$themes item=theme} - + {$sum=0} {$cpt=0} {$themeID=$theme->get_id()} @@ -43,8 +43,8 @@ - - + +
    {$my_team->get_name()}{$my_team->get_name()}Exercice {$i}
    {$theme->get_name()}{$theme->get_name()}
    Total :{$total}Total :{$total}
    diff --git a/onyx/tpl/bootstrap/teams/exercice.tpl b/onyx/tpl/bootstrap/teams/exercice.tpl index d07770c8..a487174c 100644 --- a/onyx/tpl/bootstrap/teams/exercice.tpl +++ b/onyx/tpl/bootstrap/teams/exercice.tpl @@ -8,7 +8,7 @@
    • Gain : {$cur_exercice->points}
    • -
    • Description : {$cur_exercice->statement}
    • +
    • Description : {$cur_exercice->statement|escape|nl2br}
    diff --git a/synchro.sh b/synchro.sh index 4ffc1ef3..9ea8a4b9 100755 --- a/synchro.sh +++ b/synchro.sh @@ -5,17 +5,23 @@ cd `dirname "$0"` if [ "$UID" = "0" ] then SCRIPT=`pwd`/`basename "$0"` - su -c "sh $SCRIPT" synchro + su -c "sh $SCRIPT $@" synchro exit $? fi -rsync -e ssh -av --delete out/localhost/* phobos:~/htdocs/ -rsync -e ssh -av --delete out/teams phobos:~/ -rsync -e ssh -av --delete files phobos:~/ -rsync -e ssh -av --delete misc phobos:~/ +OPTS= +if [ "$1" = "delete" ] +then + OPTS="$OPTS --delete" +fi + +rsync -e ssh -av $OPTS out/localhost/* phobos:~/htdocs/ +rsync -e ssh -av $OPTS out/teams phobos:~/ +rsync -e ssh -av $OPTS files phobos:~/ +rsync -e ssh -av $OPTS misc phobos:~/ scp nginx.conf submission.php phobos:~/ -rsync -e ssh -av --delete out/localhost/* phobos:~/htdocs/ +rsync -e ssh -av $OPTS out/localhost/* phobos:~/htdocs/ rsync -e ssh -av phobos:~/submission/ submission/ ssh phobos "rm ~/submission/*" From 7a42ea56b06d9a171a9ecc4e96d82ac1021f9abe Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sat, 11 Jan 2014 17:02:46 +0100 Subject: [PATCH 0170/2585] Add refresh in public/home.tpl --- onyx/tpl/bootstrap/public/home.tpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index e97c2cef..6751cbcf 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -1,5 +1,9 @@ {extends file="public/layout.tpl"} +{block name=head2} + +{/block} + {block name=main} {if isset($teams)} +{/block} From 147bb5be5567ca444037a7b8e87cc5ff940def82 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 10:43:16 +0100 Subject: [PATCH 0196/2585] Check localtime before check an answer --- check.pl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/check.pl b/check.pl index 2840f349..095af269 100755 --- a/check.pl +++ b/check.pl @@ -30,6 +30,17 @@ for my $p (<$conf>) } close $conf; +my $end_time = 1999999999; +if (-f "$root/misc/challenge_started") +{ + open my $conf, "<", "$root/misc/challenge_started"; + $end_time = <$conf>; + close $conf; + chomp($end_time); + $end_time += 14400; +} + +die("TIME expired!") if time() > $end_time; die("No DB profile found") if ! $profile; die("submission_dir is not a directory") if ! $submission_dir || ! -d $submission_dir; From 5b2b4265a4ca06736cc541f992fdfb655f6e3a21 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 10:58:59 +0100 Subject: [PATCH 0197/2585] Can use comm-socket with argument --- comm-socket.pl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/comm-socket.pl b/comm-socket.pl index e9c1b0f3..3748db21 100644 --- a/comm-socket.pl +++ b/comm-socket.pl @@ -7,12 +7,22 @@ use threads; die("Give at least the socket file as argument") if (! @ARGV); +my $sock_path = shift @ARGV; + my $socket = IO::Socket::UNIX->new( Type => SOCK_STREAM, - Peer => $ARGV[0], + Peer => $sock_path, ); -die "Can't create socket: $!" unless $socket; +die "Can't read socket ($sock_path): $!" unless $socket; + +if (@ARGV) +{ + while (my $arg = shift @ARGV) + { + say $socket $arg; + } +} my $s = IO::Select->new(); From 0774eb7009d5ffa0e61d0546043712cfb0cb41de Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 11:11:11 +0100 Subject: [PATCH 0198/2585] Fix obscur deletion in admin panel; add Whirlpool hash --- onyx/include/admin/exercice.php | 2 +- onyx/include/common/Exercice.class.php | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/onyx/include/admin/exercice.php b/onyx/include/admin/exercice.php index c1d2b9ab..e4507cc8 100644 --- a/onyx/include/admin/exercice.php +++ b/onyx/include/admin/exercice.php @@ -2,7 +2,7 @@ if(!defined('ONYX')) exit; -$template->assign("fortyp", array("raw" => "RAW", "sha1" => "SHA-1", "md5" => "MD5", "sha224" => "SHA-224", "sha256" => "SHA-256", "sha384" => "SHA-384", "sha512" => "SHA-512")); +$template->assign("fortyp", array("raw" => "RAW", "sha1" => "SHA-1", "md5" => "MD5", "sha224" => "SHA-224", "sha256" => "SHA-256", "sha384" => "SHA-384", "sha512" => "SHA-512", "whirlpool" => "Whirlpool")); $p = $out[0]; diff --git a/onyx/include/common/Exercice.class.php b/onyx/include/common/Exercice.class.php index d01e8e93..7fade8d4 100644 --- a/onyx/include/common/Exercice.class.php +++ b/onyx/include/common/Exercice.class.php @@ -301,8 +301,11 @@ class Exercice function flush_keys() { + $id = $this->id; + $db = new BDD(); - $db->query("DELETE FROM exercice_keys WHERE id_exercice = ".intval($this->id)); + $db->escape($id); + $db->query("DELETE FROM exercice_keys WHERE id_exercice = '$id'"); $db->deconnexion(); $this->keys = array(); @@ -312,9 +315,9 @@ class Exercice { if ($format == "raw") { - $this->add_key("sha1", hash("sha1", $value)); + $this->add_key("sha256", hash("sha256", $value)); $this->add_key("sha512", hash("sha512", $value)); - $this->add_key("md5", hash("md5", $value)); + $this->add_key("whirlpool", hash("whirlpool", $value)); } else $this->keys[] = array( From b145741db0253e096e60d26dbb02859a613c30f7 Mon Sep 17 00:00:00 2001 From: Thibaut Le Page <`echo dGhpbHAuaXMK | base64 -d`@gmail.com> Date: Mon, 20 Jan 2014 11:16:55 +0100 Subject: [PATCH 0199/2585] final version --- epita.pdf | Bin 0 -> 4982 bytes guide.pdf | Bin 33294 -> 33134 bytes guide.tex | 108 +++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 epita.pdf diff --git a/epita.pdf b/epita.pdf new file mode 100644 index 0000000000000000000000000000000000000000..061a6f765afd1721b7ef81586efec02fd6435619 GIT binary patch literal 4982 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 S5kX)%D3no1NXJ;0@qYl*G+pul literal 0 HcmV?d00001 diff --git a/guide.pdf b/guide.pdf index 0e5f6ef285a597708b64b4dc7bad09d815a43735..207d669de3368b271a2d5c5fef5292f58f72632b 100644 GIT binary patch literal 33134 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 IQ4;q50`*GycmMzZ literal 33294 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 diff --git a/guide.tex b/guide.tex index a095ccd4..601df144 100644 --- a/guide.tex +++ b/guide.tex @@ -10,12 +10,12 @@ \setmonofont{Inconsolata} \title{Challenge FIC 2014 : Guide introductif} -\author{EPITA} +\author{\includegraphics[width=80pt]{epita}} \date{22 janvier 2014} \newcommand{\certClient}[1]{\texttt{client\_#1.p12}} -\newcommand{\certServeurWin}[0]{\texttt{serveur.der}} -\newcommand{\certServeurLinux}[0]{\texttt{serveur.pem}} +\newcommand{\certServeurWin}[0]{\texttt{ca.der}} +\newcommand{\certServeurLinux}[0]{\texttt{ca.pem}} \newcommand{\WindowsLogo}{\raisebox{-0.1em}{\includegraphics[height=0.75em]{windows_key}}} \newcommand{\WinKey}{\keystroke{\WindowsLogo}} @@ -24,9 +24,9 @@ \maketitle{} -\textbf{\textsc{Bienvenue}} à cette seconde épreuve du challenge +\textbf{\textsc{Bienvenue}} dans cette seconde épreuve du challenge \emph{forensics} ! Votre première activité consiste à accéder au site dédié à -cet événement ; ce guide est là pour vous aider à y parvenir. +cet événement ; ce guide est là pour vous y aider. \paragraph{Important :} La clef USB qui vous a été donnée contient des fichiers permettant votre authentification auprès de nos serveurs. Ne la @@ -38,12 +38,14 @@ laissez pas sans surveillance ! \vspace{\baselineskip} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Installation du certificat \emph{client}} +\section{Installation du certificat client} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Le certificat \emph{client} est envoyé à notre serveur pour vous identifier et -authentifier. Si votre numéro d'équipe était \emph{X}, il s'agirait du -fichier nommé \certClient{X} sur votre clef USB. +vous authentifier. +Si votre numéro d'équipe était \emph{X}, il s'agirait du fichier nommé +\certClient{X} sur votre clef USB. +Il est protégé avec le mot de passe qui vous a été fourni sur papier. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Mozilla Firefox} @@ -94,52 +96,100 @@ concernant \nameref{sec:clIE}. \subsection{Internet Explorer} \label{sec:clIE} -Sous Windows, un \textbf{double-clic} sur le fichier \certClient{X} devrait -suffire à faire surgir les instruction d'installation pour ce certificat. - -Vous pouvez \textbf{aussi} l'importer \emph{via} la console de gestion des -certificats : \begin{enumerate} - \item Pressez les touches \WinKey{} + \keystroke{R}. - \item Écrivez \texttt{\textbf{certmgr.msc}} et appuyez sur la touche - \emph{Entrée} \Return{}. - \item Cliquez sur le dossier \textbf{Personnel}. - \item Dans le menu \textbf{Action}, sous-menu \textbf{Toutes les tâches}, - choisissez \textbf{Importer…} - \item Cliquez sur \textbf{Suivant} et suivez les instructions. - \item Lorsqu'on vous le demande, placez le certificat dans le magasin - \textbf{Personnel}. + \item \textbf{Double-cliquez} sur le fichier \certClient{X}. + L'\emph{assistant d'importation du certificat} apparaît. + \item Cliquez sur \textbf{Suivant}. + \item Cliquez sur \textbf{Suivant}. + \item Entrez le mot de passe fourni sur papier puis cliquez sur \textbf{Suivant}. + \item Cliquez sur \textbf{Suivant} (le certificat sera automatiquement + placé dans le magasin \emph{Personnel}). + \item Cliquez sur \textbf{Terminer}. \end{enumerate} +Selon votre version de Windows, votre système peut ensuite vous demander de +définir un mot de passe pour protéger ce certificat. + \paragraph{Microsoft Internet Explorer :} Aucune version de \emph{Microsoft Internet Explorer} (nom d'« Internet Explorer » jusqu'à sa version 6 comprise) n'est supportée par notre serveur. La fin du support officiel étant prévue le 8 avril prochain, vous devriez déjà y être préparé ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Installation du certificat \emph{serveur}} +\section{Installation du certificat de l'autorité de certification du serveur} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Pour ne pas rencontrer d'avertissement lors de vos connexions au serveur, -c'est-à-dire être en mesure de vérifier la validité du certificat du serveur, -nous vous recommandons d'ajouter également à votre navigateur le certificat de -notre autorité de certification. +c'est-à-dire être en mesure de \textbf{vérifier la validité} du certificat du +serveur, nous vous \textbf{recommandons} d'ajouter également à votre +navigateur le certificat de notre autorité de certification. -Sur votre clef USB, ce certificat est nommé \certServeurWin{} (pour les -utilisateurs de Microsoft Windows) ou \certServeurLinux{} (pour les -utilisateurs de Linux). +Sur votre clef USB, ce certificat est nommé \certServeurWin{}. + +\paragraph{Note :} Ajouter un certificat d'autorité racine n'est pas anodin : +si un certificat était forgé par cette autorité pour un site tiers (comme +Twitter, Gmail, etc.), il serait considéré valide par votre navigateur, +permettant ainsi un espionnage \emph{man in the middle} de vos échanges avec +ce site. + +Pour cette raison, au cas où vous oublieriez de le supprimer après le +challenge, ce certificat n'est valide que jusqu'à 23 h 59 ce soir. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Mozilla Firefox} \label{sec:servFFox} +Suivez la même procédure que pour le certificat client +(cf. \autoref{sec:clFFox}) mais choisissez l'onglet \textbf{Autorités} (au +lieu de \emph{Vos certificats}) et, lorsqu'on vous demande pour quelles +actions faire confiance au certificat, sélectionnez \textbf{Confirmer cette AC +pour identifier des sites web}. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Chromium/Google Chrome} \label{sec:servChrome} +\subsubsection{Sous Microsoft Windows} + +Le navigateur utilise les paramètres du système ; suivez les instructions +concernant \nameref{sec:servIE}. + +\subsubsection{Sous Mac OS} + +\begin{enumerate} + \item Suivez la même procédure que pour le certificat client + (cf. \autoref{sec:clChrome}) mais sélectionnez cette fois-ci le + fichier \certServeurWin{}. + \item Cliquez sur \textbf{Toujours approuver}. +\end{enumerate} + +\subsubsection{Sous GNU/Linux, FreeBSD ou OpenBSD} + +\begin{enumerate} + \item Ouvrez le menu des préférences du navigateur. + \item Cliquez sur \textbf{Afficher les paramètres avancés}. + \item Dans la section \textbf{HTTPS/SSL}, cliquez sur \textbf{Gérer les + certificats}. + \item Sélectionnez l'onglet \textbf{Autorités}. + \item Cliquez sur \textbf{Importer…} et sélectionnez \certServeurWin{}. + \item Choisissez \textbf{Faire confiance à ce certificat pour identifier les sites web}. +\end{enumerate} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Internet Explorer} \label{sec:servIE} +\begin{enumerate} + \item \textbf{Double-cliquez} sur le fichier \certServeurWin{}. + \item Cliquez sur \textbf{Installer un certificat…} + \item Cliquez sur \textbf{Suivant}. + \item Sélectionnez \textbf{Placer tous les certificats dans le magasin + suivant} et choisissez le magasin \textbf{Autorités de certification + racines de confiance}. Cliquez enfin sur \textbf{Suivant}. + \item Cliquez sur \textbf{Terminer}. + \item Un avertissement de sécurité apparaît, reprenant notamment notre + avertissement de début de section. Cliquez sur \textbf{Oui}. +\end{enumerate} + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document} From 9461aea9fcdb100c840a1260ee96bb9d5eadaf9e Mon Sep 17 00:00:00 2001 From: Thibaut Le Page <`echo dGhpbHAuaXMK | base64 -d`@gmail.com> Date: Mon, 20 Jan 2014 11:28:05 +0100 Subject: [PATCH 0200/2585] nicer links: no more red borders --- guide.pdf | Bin 33134 -> 33351 bytes guide.tex | 8 ++++++++ 2 files changed, 8 insertions(+) diff --git a/guide.pdf b/guide.pdf index 207d669de3368b271a2d5c5fef5292f58f72632b..eb1b32f8a003e8cf7b797ca86c628c101b8a8054 100644 GIT binary patch delta 26407 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෗gAF~tkLPMQc8%VU_(wO6_dMWqrkOwd9hV(3yN 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 Date: Mon, 20 Jan 2014 15:50:00 +0100 Subject: [PATCH 0201/2585] Truncate exercice_tries --- onyx/include/admin/list_themes.php | 1 + 1 file changed, 1 insertion(+) diff --git a/onyx/include/admin/list_themes.php b/onyx/include/admin/list_themes.php index a52a60f1..54800012 100644 --- a/onyx/include/admin/list_themes.php +++ b/onyx/include/admin/list_themes.php @@ -36,6 +36,7 @@ else if (isset($_GET["drop"])) $db = new BDD(); $db->query("TRUNCATE exercice_files"); $db->query("TRUNCATE exercice_keys"); + $db->query("TRUNCATE exercice_tries"); $db->query("TRUNCATE exercices"); $db->query("TRUNCATE themes"); $db->query("TRUNCATE solved"); From ebb0cabf9aa8acafbd23c3b10272f43142ea2cb8 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 16:52:44 +0100 Subject: [PATCH 0202/2585] Change file path --- onyx/include/common/Exercice.class.php | 3 ++- onyx/tpl/bootstrap/teams/exercice.tpl | 2 +- synchro.sh | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/onyx/include/common/Exercice.class.php b/onyx/include/common/Exercice.class.php index 7fade8d4..ad6a8b24 100644 --- a/onyx/include/common/Exercice.class.php +++ b/onyx/include/common/Exercice.class.php @@ -37,8 +37,9 @@ class Exercice foreach($this->files as &$f) { $f["path_orig"] = $f["path"]; + $f["path_hash"] = hash("sha384", $f["path"])."/".basename($f["path"]); if (isset($VAR["files_dir"])) - $f["path"] = $VAR["files_dir"].$f["path"]; + $f["path"] = $VAR["files_dir"].$f["path_hash"]; $f["basename"] = basename($f["path"]); $f["sha1"] = strhex($f["sha1"]); } diff --git a/onyx/tpl/bootstrap/teams/exercice.tpl b/onyx/tpl/bootstrap/teams/exercice.tpl index 3574f047..48ae7f99 100644 --- a/onyx/tpl/bootstrap/teams/exercice.tpl +++ b/onyx/tpl/bootstrap/teams/exercice.tpl @@ -32,7 +32,7 @@ {if file_exists($file['path'])} - + diff --git a/synchro.sh b/synchro.sh index 989d2bca..7bff0c25 100755 --- a/synchro.sh +++ b/synchro.sh @@ -15,11 +15,11 @@ then OPTS="$OPTS --delete" fi -rsync -e ssh -av $OPTS out/errors phobos:~/ -rsync -e ssh -av $OPTS out/htdocs phobos:~/ -rsync -e ssh -av $OPTS out/teams phobos:~/ -rsync -e ssh -av $OPTS files phobos:~/ -rsync -e ssh -av $OPTS misc phobos:~/ +rsync -e ssh -av $OPTS out/errors phobos:~/ +rsync -e ssh -av $OPTS out/htdocs phobos:~/ +rsync -e ssh -av $OPTS out/teams phobos:~/ +rsync -e ssh -avL $OPTS files phobos:~/ +rsync -e ssh -av $OPTS misc phobos:~/ scp nginx.conf submission.php phobos:~/ rsync -e ssh -av phobos:~/submission/ submission/ From 6f260045fa10f16104bae1a9aa067288096b3722 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 18:23:02 +0100 Subject: [PATCH 0203/2585] CA.sh: Add a Master CA --- misc/CA.sh | 75 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index aa0f6212..16d07dfd 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -11,17 +11,21 @@ fi CAKEY=./cakey.key CAREQ=./careq.csr CACERT=./cacert.crt +MASTERKEY=./master.key +MASTEREQ=./master.csr +MASTERCERT=./master.crt + DAYS=365 -#GREEN="\033[1;32m" -#RED="\033[1;31m" -#COLOR_RST="\033[0m" +GREEN="\033[1;32m" +RED="\033[1;31m" +COLOR_RST="\033[0m" -GREEN="" -RED="" -COLOR_RST="" -BOLD="" -END_BOLD="" +#GREEN="" +#RED="" +#COLOR_RST="" +#BOLD="" +#END_BOLD="" usage() { @@ -61,7 +65,7 @@ case $1 in ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') echo -e "${GREEN}Making CA key and csr${COLOR_RST}" - sed -i 's/=.*#COMMONNAME/= FIC2014 CA #COMMONNAME/' $OPENSSL_CONF + sed -i 's/=.*#COMMONNAME/= FIC2014 MASTER #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= objsign #CERTTYPE/" $OPENSSL_CONF @@ -71,9 +75,37 @@ case $1 in exit 5 fi + # MASTER CA + sed -i 's/cacert\.crt/master\.crt/' $OPENSSL_CONF + sed -i 's/cakey\.key/master\.key/' $OPENSSL_CONF pass=`pwgen -n -B -y 12 1` + echo "Master pass: " $pass + openssl req -batch -new -keyout ${TOP_DIR}/private/${MASTERKEY} \ + -out ${TOP_DIR}/${MASTEREQ} -passout pass:$pass \ + -config $OPENSSL_CONF > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + cat $OUTPUT + clean "ca" + exit 4 + fi - openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ + echo -e "${GREEN}Self signes the MASTER certificate${COLOR_RST}" + openssl ca -batch -create_serial -out ${TOP_DIR}/${MASTERCERT} \ + -days ${DAYS} -keyfile ${TOP_DIR}/private/${MASTERKEY} \ + -selfsign -extensions v3_ca -config ${OPENSSL_CONF} \ + -infiles ${TOP_DIR}/${MASTEREQ} > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + cat $OUTPUT + clean "ca" + exit 4 + fi + + sed -i 's/=.*#COMMONNAME/= FIC2014 CA #COMMONNAME/' $OPENSSL_CONF + echo -e "${GREEN}Generate CA certificate${COLOR_RST}" + + pass=`pwgen -n -B -y 12 1` + echo "CA pass: " $pass + openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ -out ${TOP_DIR}/${CAREQ} -passout pass:$pass \ -config $OPENSSL_CONF > $OUTPUT 2>&1 if [ $? -ne 0 ]; then @@ -90,17 +122,20 @@ case $1 in clean "ca" exit 4 fi - - echo -e "${GREEN}Self signes the CA certificate${COLOR_RST}" - openssl ca -batch -create_serial -out ${TOP_DIR}/${CACERT} \ - -days ${DAYS} -keyfile ${TOP_DIR}/private/${CAKEY} \ - -selfsign -extensions v3_ca -config ${OPENSSL_CONF} \ - -infiles ${TOP_DIR}/${CAREQ} > $OUTPUT 2>&1 + echo -e "${GREEN}Signing CA crt by Master${COLOR_RST}" + openssl ca -policy policy_match -config ${OPENSSL_CONF} \ + -out ${TOP_DIR}/${CACERT} -infiles ${TOP_DIR}/${CAREQ} if [ $? -ne 0 ]; then + echo -e "${RED}Signing failed for CA${COLOR_RST}" + rm -rf ${TOP_DIR}/${CACERT} ${TOP_DIR}/${CAKEY} ${TOP_DIR}/${CAREQ} cat $OUTPUT - clean "ca" + sed -i 's/master\.crt/cacert\.crt/' $OPENSSL_CONF + sed -i 's/master\.key/cakey\.key/' $OPENSSL_CONF exit 4 - fi + fi + + sed -i 's/master\.crt/cacert\.crt/' $OPENSSL_CONF + sed -i 's/master\.key/cakey\.key/' $OPENSSL_CONF ;; "-newserver" ) echo -e "${GREEN}Making the Server key and cert${COLOR_RST}" @@ -108,7 +143,7 @@ case $1 in echo -e "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi - sed -i 's/=.*#COMMONNAME/= FIC2014 Server #COMMONNAME/' $OPENSSL_CONF + sed -i 's/=.*#COMMONNAME/= srs.epita.fr #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= server #CERTTYPE/" $OPENSSL_CONF openssl req -batch -new -keyout server.key -out server.csr \ -days ${DAYS} -config ${OPENSSL_CONF} > $OUTPUT 2>&1 @@ -118,7 +153,7 @@ case $1 in fi echo -e "${GREEN}Signing the Server crt${COLOR_RST}" openssl ca -policy policy_match -config ${OPENSSL_CONF} \ - -out server.crt -infiles server.csr > $OUTPUT 2>&1 + -out server.crt -infiles server.csr if [ $? -ne 0 ]; then echo -e "${RED}Signing failed for new server${COLOR_RST}" rm -rf server.key server.crt server.csr From 63d73bc601e4177236292fb2a7e444dbe4edd8d8 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 18:34:18 +0100 Subject: [PATCH 0204/2585] Fixed CA.sh path var --- misc/CA.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/CA.sh b/misc/CA.sh index 16d07dfd..9ba3878a 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -172,6 +172,9 @@ case $1 in echo "==============================================================" echo -e "${GREEN}Making the client key and csr of ${BOLD}${2}${END_BOLD}${COLOR_RST}" + ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') + sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF + if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then echo -e "${RED}Can not found the CA's key${COLOR_RST}" exit 2 From 83c61f6fe447ac8d0ea3372c95c23885f7516de7 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 18:44:46 +0100 Subject: [PATCH 0205/2585] misc/ --- synchro.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synchro.sh b/synchro.sh index 7bff0c25..07dea5ba 100755 --- a/synchro.sh +++ b/synchro.sh @@ -19,7 +19,7 @@ rsync -e ssh -av $OPTS out/errors phobos:~/ rsync -e ssh -av $OPTS out/htdocs phobos:~/ rsync -e ssh -av $OPTS out/teams phobos:~/ rsync -e ssh -avL $OPTS files phobos:~/ -rsync -e ssh -av $OPTS misc phobos:~/ +rsync -e ssh -av $OPTS misc/server.* misc/pki/cacert.crt misc/pki/crl.pem phobos:~/ scp nginx.conf submission.php phobos:~/ rsync -e ssh -av phobos:~/submission/ submission/ From 363ba3325a94f27473bc6a790062f47c07f4e16f Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 18:59:15 +0100 Subject: [PATCH 0206/2585] Make some changes on chrono --- htdocs/index.php | 2 +- onyx/include/admin/chrono.php | 2 +- onyx/tpl/bootstrap/admin/exercice.tpl | 2 +- onyx/tpl/bootstrap/admin/home.tpl | 26 +++++++++++++++++++------- onyx/tpl/bootstrap/public/home.tpl | 2 +- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/htdocs/index.php b/htdocs/index.php index 1ae3750c..ac03ea5d 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -131,7 +131,7 @@ else if ($n && $p[0] == SALT_USER) $page = "teams/list"; } - else if (empty($VAR["start_challenge"]) || $VAR["start_challenge"] < time()) + else if (empty($VAR["start_challenge"])) { $TEAM = new Team($p[1]); $template->assign("my_team", $TEAM); diff --git a/onyx/include/admin/chrono.php b/onyx/include/admin/chrono.php index d62bc9c3..99350ee0 100644 --- a/onyx/include/admin/chrono.php +++ b/onyx/include/admin/chrono.php @@ -9,7 +9,7 @@ if (count($p) > 2) switch($p[2]) { case "start": - file_put_contents($VAR["misc_dir"]."/challenge_started", time() + 42); + file_put_contents($VAR["misc_dir"]."/challenge_started", time() + (intval($_POST["time"]) - 240) * 60); break; case "init": diff --git a/onyx/tpl/bootstrap/admin/exercice.tpl b/onyx/tpl/bootstrap/admin/exercice.tpl index 01de1461..affd82af 100644 --- a/onyx/tpl/bootstrap/admin/exercice.tpl +++ b/onyx/tpl/bootstrap/admin/exercice.tpl @@ -70,7 +70,7 @@
- {if is_file($file.path)} Calculated from {$file.path}: {sha1_file($file.path)}{/if} + {if is_file($file.path)} Calculated from {$file.path}: {sha1_file($file.path)} pas bon{else}label-success">ok{/if}{/if}
diff --git a/onyx/tpl/bootstrap/admin/home.tpl b/onyx/tpl/bootstrap/admin/home.tpl index 25101ae8..885c26fe 100644 --- a/onyx/tpl/bootstrap/admin/home.tpl +++ b/onyx/tpl/bootstrap/admin/home.tpl @@ -15,24 +15,36 @@
  • [CN] : {$cert['subject']['CN']}
  • [emailAddress] : {$cert['subject']['emailAddress']}
  • - Supprimer + {elseif isset($cert_writable) && ! $cert_writable}
    Répertoire non accessible en écriture.
    - Nouveau + {else} - Nouveau + Pas de certificat + {/if}
    -

    Chrono

    +

    Chrono Lancé{else}danger">Arrêté{/if}

    - Start - Réinitialiser + +
    + +
    + + minutes +
    +
    +
    + + Réinitialiser +
    +
    {/block} diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index 6751cbcf..72f6efbe 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -1,7 +1,7 @@ {extends file="public/layout.tpl"} {block name=head2} - + {/block} {block name=main} From 9108124ca4ad3994dc762de4d4c6506e0c092973 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 18:59:49 +0100 Subject: [PATCH 0207/2585] Generate a directory for files --- gen_hash_link_files.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 gen_hash_link_files.sh diff --git a/gen_hash_link_files.sh b/gen_hash_link_files.sh new file mode 100755 index 00000000..2cb4873a --- /dev/null +++ b/gen_hash_link_files.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +FROM=`realpath $1`; shift +TO=`realpath $1`; shift + +if [ -z "$FROM" ] || [ -z "$TO" ] +then + echo "Usage: $0 from to" + exit 1 +elif ! [ -d "$FROM" ] +then + echo "$FROM not found" + exit 2 +fi + +mkdir -p "$TO" || exit 3 +rm -rf "$TO" || exit 3 + +for i in `find "$FROM" -mindepth 1 -type f` +do + FILE=`echo $i | sed "s!^$FROM/!!"` + HASH=`echo -n $FILE | sha384sum | cut -d " " -f 1` + + mkdir -p "$TO/$HASH/" + ln -s "$i" "$TO/$HASH/" +done From ac5aa1099e05c567ef8621d4ee4e4c013b8c24d8 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Mon, 20 Jan 2014 20:53:20 +0100 Subject: [PATCH 0208/2585] Revert "CA.sh: Add a Master CA" This reverts commit 6f260045fa10f16104bae1a9aa067288096b3722. --- misc/CA.sh | 79 +++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 57 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index 9ba3878a..3e7cc1cc 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -11,21 +11,17 @@ fi CAKEY=./cakey.key CAREQ=./careq.csr CACERT=./cacert.crt -MASTERKEY=./master.key -MASTEREQ=./master.csr -MASTERCERT=./master.crt - DAYS=365 -GREEN="\033[1;32m" -RED="\033[1;31m" -COLOR_RST="\033[0m" +#GREEN="\033[1;32m" +#RED="\033[1;31m" +#COLOR_RST="\033[0m" -#GREEN="" -#RED="" -#COLOR_RST="" -#BOLD="" -#END_BOLD="" +GREEN="" +RED="" +COLOR_RST="" +BOLD="" +END_BOLD="" usage() { @@ -65,7 +61,7 @@ case $1 in ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') echo -e "${GREEN}Making CA key and csr${COLOR_RST}" - sed -i 's/=.*#COMMONNAME/= FIC2014 MASTER #COMMONNAME/' $OPENSSL_CONF + sed -i 's/=.*#COMMONNAME/= FIC2014 CA #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= objsign #CERTTYPE/" $OPENSSL_CONF @@ -75,37 +71,9 @@ case $1 in exit 5 fi - # MASTER CA - sed -i 's/cacert\.crt/master\.crt/' $OPENSSL_CONF - sed -i 's/cakey\.key/master\.key/' $OPENSSL_CONF pass=`pwgen -n -B -y 12 1` - echo "Master pass: " $pass - openssl req -batch -new -keyout ${TOP_DIR}/private/${MASTERKEY} \ - -out ${TOP_DIR}/${MASTEREQ} -passout pass:$pass \ - -config $OPENSSL_CONF > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then - cat $OUTPUT - clean "ca" - exit 4 - fi - echo -e "${GREEN}Self signes the MASTER certificate${COLOR_RST}" - openssl ca -batch -create_serial -out ${TOP_DIR}/${MASTERCERT} \ - -days ${DAYS} -keyfile ${TOP_DIR}/private/${MASTERKEY} \ - -selfsign -extensions v3_ca -config ${OPENSSL_CONF} \ - -infiles ${TOP_DIR}/${MASTEREQ} > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then - cat $OUTPUT - clean "ca" - exit 4 - fi - - sed -i 's/=.*#COMMONNAME/= FIC2014 CA #COMMONNAME/' $OPENSSL_CONF - echo -e "${GREEN}Generate CA certificate${COLOR_RST}" - - pass=`pwgen -n -B -y 12 1` - echo "CA pass: " $pass - openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ + openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ -out ${TOP_DIR}/${CAREQ} -passout pass:$pass \ -config $OPENSSL_CONF > $OUTPUT 2>&1 if [ $? -ne 0 ]; then @@ -122,20 +90,17 @@ case $1 in clean "ca" exit 4 fi - echo -e "${GREEN}Signing CA crt by Master${COLOR_RST}" - openssl ca -policy policy_match -config ${OPENSSL_CONF} \ - -out ${TOP_DIR}/${CACERT} -infiles ${TOP_DIR}/${CAREQ} - if [ $? -ne 0 ]; then - echo -e "${RED}Signing failed for CA${COLOR_RST}" - rm -rf ${TOP_DIR}/${CACERT} ${TOP_DIR}/${CAKEY} ${TOP_DIR}/${CAREQ} - cat $OUTPUT - sed -i 's/master\.crt/cacert\.crt/' $OPENSSL_CONF - sed -i 's/master\.key/cakey\.key/' $OPENSSL_CONF - exit 4 - fi - sed -i 's/master\.crt/cacert\.crt/' $OPENSSL_CONF - sed -i 's/master\.key/cakey\.key/' $OPENSSL_CONF + echo -e "${GREEN}Self signes the CA certificate${COLOR_RST}" + openssl ca -batch -create_serial -out ${TOP_DIR}/${CACERT} \ + -days ${DAYS} -keyfile ${TOP_DIR}/private/${CAKEY} \ + -selfsign -extensions v3_ca -config ${OPENSSL_CONF} \ + -infiles ${TOP_DIR}/${CAREQ} > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + cat $OUTPUT + clean "ca" + exit 4 + fi ;; "-newserver" ) echo -e "${GREEN}Making the Server key and cert${COLOR_RST}" @@ -143,7 +108,7 @@ case $1 in echo -e "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi - sed -i 's/=.*#COMMONNAME/= srs.epita.fr #COMMONNAME/' $OPENSSL_CONF + sed -i 's/=.*#COMMONNAME/= FIC2014 Server #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#CERTTYPE/= server #CERTTYPE/" $OPENSSL_CONF openssl req -batch -new -keyout server.key -out server.csr \ -days ${DAYS} -config ${OPENSSL_CONF} > $OUTPUT 2>&1 @@ -153,7 +118,7 @@ case $1 in fi echo -e "${GREEN}Signing the Server crt${COLOR_RST}" openssl ca -policy policy_match -config ${OPENSSL_CONF} \ - -out server.crt -infiles server.csr + -out server.crt -infiles server.csr > $OUTPUT 2>&1 if [ $? -ne 0 ]; then echo -e "${RED}Signing failed for new server${COLOR_RST}" rm -rf server.key server.crt server.csr From cc588d51f9103f9890c0821b2b091d01ae3ab91c Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 21 Jan 2014 03:07:52 +0100 Subject: [PATCH 0209/2585] Ready to generate new certificates --- check.pl | 5 + misc/CA.sh | 21 ++- misc/openssl.cnf | 218 ++++----------------------- nginx.conf | 15 +- onyx/tpl/bootstrap/public/layout.tpl | 4 +- submission.php | 10 +- synchro.sh | 3 +- 7 files changed, 67 insertions(+), 209 deletions(-) diff --git a/check.pl b/check.pl index 095af269..5b2863f9 100755 --- a/check.pl +++ b/check.pl @@ -110,6 +110,11 @@ for my $f (readdir $dh) elsif ($type eq "sha512") { $tmp_solution = sha512_hex($solution); } + elsif ($type eq "whirlpool") { + my $hash = Digest->new( 'Whirlpool' ); + $hash->add( $solution ); + $tmp_solution = $hash->hexdigest; + } elsif ($type ne "raw") { warn "$type not implemented"; } diff --git a/misc/CA.sh b/misc/CA.sh index 3e7cc1cc..db4ba6c4 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -11,7 +11,8 @@ fi CAKEY=./cakey.key CAREQ=./careq.csr CACERT=./cacert.crt -DAYS=365 + +DAYS=2 #GREEN="\033[1;32m" #RED="\033[1;31m" @@ -63,7 +64,6 @@ case $1 in echo -e "${GREEN}Making CA key and csr${COLOR_RST}" sed -i 's/=.*#COMMONNAME/= FIC2014 CA #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF - sed -i "s/=.*#CERTTYPE/= objsign #CERTTYPE/" $OPENSSL_CONF type pwgen > /dev/null if [ $? -ne 0 ]; then @@ -72,10 +72,9 @@ case $1 in fi pass=`pwgen -n -B -y 12 1` - openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ -out ${TOP_DIR}/${CAREQ} -passout pass:$pass \ - -config $OPENSSL_CONF > $OUTPUT 2>&1 + -config $OPENSSL_CONF -extensions CORE_CA > $OUTPUT 2>&1 if [ $? -ne 0 ]; then cat $OUTPUT clean "ca" @@ -94,7 +93,7 @@ case $1 in echo -e "${GREEN}Self signes the CA certificate${COLOR_RST}" openssl ca -batch -create_serial -out ${TOP_DIR}/${CACERT} \ -days ${DAYS} -keyfile ${TOP_DIR}/private/${CAKEY} \ - -selfsign -extensions v3_ca -config ${OPENSSL_CONF} \ + -selfsign -extensions CORE_CA -config ${OPENSSL_CONF} \ -infiles ${TOP_DIR}/${CAREQ} > $OUTPUT 2>&1 if [ $? -ne 0 ]; then cat $OUTPUT @@ -108,17 +107,16 @@ case $1 in echo -e "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi - sed -i 's/=.*#COMMONNAME/= FIC2014 Server #COMMONNAME/' $OPENSSL_CONF - sed -i "s/=.*#CERTTYPE/= server #CERTTYPE/" $OPENSSL_CONF + sed -i 's/=.*#COMMONNAME/=10.226.3.70#COMMONNAME/' $OPENSSL_CONF openssl req -batch -new -keyout server.key -out server.csr \ - -days ${DAYS} -config ${OPENSSL_CONF} > $OUTPUT 2>&1 + -days ${DAYS} -config ${OPENSSL_CONF} -extensions SERVER_SSL > $OUTPUT 2>&1 if [ $? -ne 0 ]; then cat $OUTPUT exit 4 fi echo -e "${GREEN}Signing the Server crt${COLOR_RST}" openssl ca -policy policy_match -config ${OPENSSL_CONF} \ - -out server.crt -infiles server.csr > $OUTPUT 2>&1 + -out server.crt -extensions SERVER_SSL -infiles server.csr if [ $? -ne 0 ]; then echo -e "${RED}Signing failed for new server${COLOR_RST}" rm -rf server.key server.crt server.csr @@ -145,7 +143,6 @@ case $1 in exit 2 fi sed -i "s/=.*#COMMONNAME/= $2#COMMONNAME/" $OPENSSL_CONF - sed -i "s/=.*#CERTTYPE/= client #CERTTYPE/" $OPENSSL_CONF type pwgen > /dev/null if [ $? -ne 0 ]; then @@ -156,7 +153,7 @@ case $1 in pass=`pwgen -n -B -y 12 1` openssl req -batch -new -keyout ${TOP_DIR}/${2}.key -out ${TOP_DIR}/${2}.csr \ - -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} > $OUTPUT 2>&1 + -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} -extensions CLIENT_SSL > $OUTPUT 2>&1 if [ $? -ne 0 ]; then cat $OUTPUT clean "client" $2 @@ -165,7 +162,7 @@ case $1 in echo -e "${GREEN}Signing the Client crt${COLOR_RST}" openssl ca -batch -policy policy_match -out ${TOP_DIR}/${2}.crt \ - -config ${OPENSSL_CONF} -infiles ${TOP_DIR}/${2}.csr > $OUTPUT 2>&1 + -config ${OPENSSL_CONF} -extensions CLIENT_SSL -infiles ${TOP_DIR}/${2}.csr > $OUTPUT 2>&1 if [ $? -ne 0 ]; then echo -e "${RED}Signing failed for $2 ${COLOR_RST}" cat $OUTPUT diff --git a/misc/openssl.cnf b/misc/openssl.cnf index a0183194..2cb594f2 100644 --- a/misc/openssl.cnf +++ b/misc/openssl.cnf @@ -55,8 +55,6 @@ crl = $dir/crl.pem # The current CRL private_key = $dir/private/cakey.key # The private key RANDFILE = $dir/private/.rand # private random number file -x509_extensions = usr_cert # The extentions to add to the cert - # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options @@ -70,7 +68,7 @@ cert_opt = ca_default # Certificate field options # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext -default_days = 365 # how long to certify for +default_days = 2 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = default # use public key default MD preserve = no # keep passed DN ordering @@ -147,7 +145,7 @@ organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = SRS commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_default = Groupe_8#COMMONNAME +commonName_default =10.226.3.70#COMMONNAME commonName_max = 64 emailAddress = Email Address @@ -163,191 +161,37 @@ challengePassword_max = 20 unstructuredName = An optional company name -[ usr_cert ] - -# These extensions are added when 'ca' signs a request. - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -nsCertType = client #CERTTYPE - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "FIC 2014 generated certificates" - -# PKIX recommendations harmless if included in all certificates. +[CORE_CA] +nsComment = "FIC2014 CA" +basicConstraints = critical,CA:TRUE,pathlen:1 +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +issuerAltName = issuer:copy +keyUsage = keyCertSign, cRLSign +nsCertType = sslCA subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This is required for TSA certificates. -# extendedKeyUsage = critical,timeStamping - -[ v3_req ] - -# Extensions to add to a certificate request - -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v3_ca ] - - -# Extensions for a typical CA - - -# PKIX recommendation. - -subjectKeyIdentifier=hash - authorityKeyIdentifier=keyid:always,issuer -# This is what PKIX recommends but some broken software chokes on critical -# extensions. -#basicConstraints = critical,CA:true -# So we do this instead. -basicConstraints = CA:true - -# Key usage: this is typical for a CA certificate. However since it will -# prevent it being used as an test self-signed certificate it is best -# left out by default. -# keyUsage = cRLSign, keyCertSign - -# Some might want this also -# nsCertType = sslCA, emailCA - -# Include email address in subject alt name: another PKIX recommendation -# subjectAltName=email:copy -# Copy issuer details -# issuerAltName=issuer:copy - -# DER hex encoding of an extension: beware experts only! -# obj=DER:02:03 -# Where 'obj' is a standard or added object -# You can even override a supported extension: -# basicConstraints= critical, DER:30:03:01:01:FF - -[ crl_ext ] - -# CRL extensions. -# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. - -# issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - -[ proxy_cert_ext ] -# These extensions should be added when creating a proxy certificate - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. +[SERVER_SSL] +nsComment = "FIC2014 Server" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +issuerAltName = issuer:copy +basicConstraints = critical,CA:FALSE +keyUsage = digitalSignature, keyEncipherment +nsCertType = server +extendedKeyUsage = serverAuth subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer +authorityKeyIdentifier=keyid:always,issuer -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This really needs to be in place for it to be a proxy certificate. -proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo - -#################################################################### -[ tsa ] - -default_tsa = tsa_config1 # the default TSA section - -[ tsa_config1 ] - -# These are used by the TSA reply generation only. -dir = ./demoCA # TSA root directory -serial = $dir/tsaserial # The current serial number (mandatory) -crypto_device = builtin # OpenSSL engine to use for signing -signer_cert = $dir/tsacert.pem # The TSA signing certificate - # (optional) -certs = $dir/cacert.pem # Certificate chain to include in reply - # (optional) -signer_key = $dir/private/tsakey.pem # The TSA private key (optional) - -default_policy = tsa_policy1 # Policy if request did not specify it - # (optional) -other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) -digests = md5, sha1 # Acceptable message digests (mandatory) -accuracy = secs:1, millisecs:500, microsecs:100 # (optional) -clock_precision_digits = 0 # number of digits after dot. (optional) -ordering = yes # Is ordering defined for timestamps? - # (optional, default: no) -tsa_name = yes # Must the TSA name be included in the reply? - # (optional, default: no) -ess_cert_id_chain = no # Must the ESS cert id chain be included? - # (optional, default: no) +[CLIENT_SSL] +nsComment = "FIC2014 Client" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +issuerAltName = issuer:copy +basicConstraints = critical,CA:FALSE +keyUsage = digitalSignature, nonRepudiation +nsCertType = client +extendedKeyUsage = clientAuth +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer diff --git a/nginx.conf b/nginx.conf index e7440406..6959d22b 100644 --- a/nginx.conf +++ b/nginx.conf @@ -2,6 +2,13 @@ server_tokens off; client_header_buffer_size 512; client_max_body_size 512; +server { + listen 80 default; + listen [::]:80 ipv6only=on default; + + rewrite ^ https://$host$uri; +} + server { listen 443 ssl; listen [::]:443 ipv6only=on ssl; @@ -13,14 +20,14 @@ server { access_log /var/log/nginx/fic.access_log; error_log /var/log/nginx/fic.error_log; - ssl_certificate /var/www/fic2014-server/misc/server.crt; - ssl_certificate_key /var/www/fic2014-server/misc/server.key; + ssl_certificate /var/www/fic2014-server/server.crt; + ssl_certificate_key /var/www/fic2014-server/server.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; - ssl_client_certificate /var/www/fic2014-server/misc/pki/cacert.crt; + ssl_client_certificate /var/www/fic2014-server/cacert.crt; ssl_verify_client optional; - ssl_crl /var/www/fic2014-server/misc/pki/crl.pem; + ssl_crl /var/www/fic2014-server/crl.pem; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index 6056acc6..8538e0ca 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -22,13 +22,13 @@

    Top 10

    {foreach from=$top item=t key=k} -
    {$k+1}. {link href="{$t->id}-{$t->get_name_url()}" href_prefix="/" label=$t->get_name()} +
    {$k+1}. {link href="{$t->id}-{$t->get_name_url()}" href_prefix="/" label={$t->get_name()|replace:"_":" et "}} {$t->get_pts()}
    {/foreach} -
        {link href="classement" href_prefix="/" label="Classement general"}
    +
        {link href="classement" href_prefix="/" label="Classement général"}
    diff --git a/submission.php b/submission.php index 85bffa3f..02f65569 100644 --- a/submission.php +++ b/submission.php @@ -8,7 +8,8 @@ function show($file) header("HTTP/1.1 403 Forbidden"); } -$file = __DIR__."/submission/".intval($_GET["team"])."-".intval($_GET["theme"])."-".urlencode($_GET["exercice"]); +$filename = intval($_GET["team"])."-".intval($_GET["theme"])."-".urlencode($_GET["exercice"]); +$file = __DIR__."/submission/".$filename; if (file_exists($file)) @@ -16,7 +17,12 @@ if (file_exists($file)) else if (!empty($_POST["solution"]) && !empty($_GET["team"]) && !empty($_GET["theme"]) && !empty($_GET["exercice"])) { - file_put_contents($file, $_POST['solution'], LOCK_EX); + $algos = array("md5", "sha1", "sha256", "sha384", "sha512", "whirlpool"); + $content = ""; + foreach($algos as $algo) + $content .= mcrypt_encrypt(MCRYPT_SERPENT_256, hash($algo, $_POST["solution"]), hash($algo, $filename), MCRYPT_MODE_ECB)."\n"; + + file_put_contents($file, $content, LOCK_EX); show(__DIR__."/teams/".intval($_GET["team"])."/".urlencode($_GET["theme"])."/".urlencode($_GET["exercice"])."/submission/index.html"); } diff --git a/synchro.sh b/synchro.sh index 07dea5ba..5f69615a 100755 --- a/synchro.sh +++ b/synchro.sh @@ -19,8 +19,7 @@ rsync -e ssh -av $OPTS out/errors phobos:~/ rsync -e ssh -av $OPTS out/htdocs phobos:~/ rsync -e ssh -av $OPTS out/teams phobos:~/ rsync -e ssh -avL $OPTS files phobos:~/ -rsync -e ssh -av $OPTS misc/server.* misc/pki/cacert.crt misc/pki/crl.pem phobos:~/ -scp nginx.conf submission.php phobos:~/ +rsync -e ssh -av $OPTS nginx.conf submission.php misc/server.* misc/pki/cacert.crt misc/pki/crl.pem phobos:~/ rsync -e ssh -av phobos:~/submission/ submission/ ssh phobos "rm -fv ~/submission/*" From 8d7394b833e0442c638d15f4aa83bf5b49b584cb Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 21 Jan 2014 03:08:08 +0100 Subject: [PATCH 0210/2585] New script to generate nginx.conf part --- check.pl | 74 ++++++++++++++++++----- launch.sh | 5 ++ nginx.conf | 34 ++++++++--- nginx_gen_team.sh | 3 + onyx/tpl/bootstrap/admin/export_teams.tpl | 2 +- submission.php | 17 +++++- synchro.sh | 2 +- 7 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 nginx_gen_team.sh diff --git a/check.pl b/check.pl index 5b2863f9..92fd49ab 100755 --- a/check.pl +++ b/check.pl @@ -5,8 +5,40 @@ use strict; use warnings; use DBI; use File::Basename; -use Digest::MD5 qw(md5_hex); -use Digest::SHA qw(sha1_hex sha224_hex sha256_hex sha384_hex sha512_hex); +use Digest; +use Digest::MD5 qw(md5); +use Digest::SHA qw(sha1 sha224 sha256 sha384 sha512); +use Mcrypt qw(:ALGORITHMS :MODES :FUNCS); + +sub encrypt +{ + my ($algo, $key, $data, $mode) = @_; + + my $td = mcrypt_load( $algo, "", $mode, '' ); + mcrypt_init($td, $key, ""); + + my $encrypted = mcrypt_encrypt($td, $data); + + mcrypt_end($td); + + return $encrypted; +} + +sub my_crypt +{ + my ($key, $content) = @_; + + my $kfirst = pack('H*', substr($key, 0, 64)); + $content = encrypt(SERPENT, $kfirst, $content, ECB); + + if (length $key > 64) + { + my $ksec = pack('H*', substr($key, 64, 64)); + $content = encrypt(SERPENT, $ksec, $content, ECB); + } + + return unpack('H*', $content); +} #Return number of good solutions my $exit = 0; @@ -70,9 +102,18 @@ for my $f (readdir $dh) my $exercice = $3; open my $fh, "<", "$submission_dir/$f"; - my $solution = <$fh>; + my %solution; + $solution{md5} = <$fh>; chomp( $solution{md5} ); + $solution{sha1} = <$fh>; chomp( $solution{sha1} ); + $solution{sha256} = <$fh>; chomp( $solution{sha256} ); + $solution{sha384} = <$fh>; chomp( $solution{sha384} ); + $solution{sha512} = <$fh>; chomp( $solution{sha512} ); + $solution{whirlpool} = <$fh>; chomp( $solution{whirlpool} ); close $fh; + use Data::Dumper; + print STDERR Dumper(\%solution); + $dbh = DBI->connect("DBI:mysql:database=$db_settings{db};host=$db_settings{host};port=3306", $db_settings{user}, $db_settings{pass}, {'RaiseError' => 1, 'PrintError' => 1}) @@ -89,39 +130,40 @@ for my $f (readdir $dh) my $type = @$row[0]; my $sol = @$row[1]; - - my $tmp_solution = $solution; + my $filh; my $tmp_solution; if ($type eq "md5") { - $tmp_solution = md5_hex($solution); + $filh = md5($f); } elsif ($type eq "sha1") { - $tmp_solution = sha1_hex($solution); + $filh = sha1($f); } elsif ($type eq "sha224") { - $tmp_solution = sha224_hex($solution); + $filh = sha224($f); } elsif ($type eq "sha256") { - $tmp_solution = sha256_hex($solution); + $filh = sha256($f); } elsif ($type eq "sha384") { - $tmp_solution = sha384_hex($solution); + $filh = sha384($f); } elsif ($type eq "sha512") { - $tmp_solution = sha512_hex($solution); + $filh = sha512($f); } elsif ($type eq "whirlpool") { my $hash = Digest->new( 'Whirlpool' ); - $hash->add( $solution ); - $tmp_solution = $hash->hexdigest; + $hash->add( $f ); + $filh = $hash->digest; } - elsif ($type ne "raw") { + else { warn "$type not implemented"; } - say STDERR "check: $sol vs $tmp_solution"; + $tmp_solution = my_crypt($sol, $filh) if ($filh); - if ($sol ne $tmp_solution) + say STDERR "check $type: $solution{$type} vs $tmp_solution"; + + if ($solution{$type} ne $tmp_solution) { $good = 0; last; diff --git a/launch.sh b/launch.sh index eb2ee30a..eee62513 100755 --- a/launch.sh +++ b/launch.sh @@ -12,10 +12,12 @@ fi touch ./logs/checks.log tail -f ./logs/checks.log & +KP1=$! TMPF=`mktemp` tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -o ./out & +KP2=$! while ! [ -f /tmp/stop ]; do @@ -23,6 +25,7 @@ do if [ `ls submission | wc -l` -gt 1 ] then + ./clear_cache.sh top ./check.pl 2>> ./logs/checks.log >> "$TMPF" else @@ -30,4 +33,6 @@ do fi done +kill -9 $KP1 $KP2 + rm -rf "$TMPF" diff --git a/nginx.conf b/nginx.conf index 6959d22b..da0b2a10 100644 --- a/nginx.conf +++ b/nginx.conf @@ -45,15 +45,29 @@ server { set $team 0; - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=bombal_s/") { set $team 161; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_1/") { set $team 166; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_2/") { set $team 167; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_3/") { set $team 168; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_4/") { set $team 169; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_5/") { set $team 170; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_6/") { set $team 171; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_7/") { set $team 172; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Groupe_8/") { set $team 173; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Amin_Martin/") { set $team 343; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Bernard_Angoustures/") { set $team 344; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Cacace_Diallo/") { set $team 345; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Delaporte_Notebaert/") { set $team 346; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Dibe/") { set $team 347; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Dubief_Roccia/") { set $team 348; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Ezzahoui/") { set $team 349; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Fall/") { set $team 350; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Guerin_Chapiron/") { set $team 351; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Hugot_Hincelin/") { set $team 352; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Jawor_Giraud/") { set $team 353; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Konan/") { set $team 354; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Le_Mignan_Yadaba/") { set $team 355; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Michel-villaz_Gzenayi/") { set $team 356; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Muller_Perrin/") { set $team 357; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Pourcelot/") { set $team 358; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Quint_Kaczmarek/") { set $team 359; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Ruff_Czarny/") { set $team 360; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Sinet_Girault/") { set $team 361; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Therrode/") { set $team 362; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Sabono_Calmeji/") { set $team 363; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Renaud_Vandemeulebroucke/") { set $team 364; } + if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=De_Priest_Tjonck/") { set $team 365; } if ($team) { root /var/www/fic2014-server/teams/$team$1; @@ -105,7 +119,7 @@ server { { root /var/www/fic2014-server/; - limit_rate 1k; + limit_rate 4k; include /etc/nginx/fastcgi.conf; fastcgi_pass unix:/var/run/php-fpm.sock; diff --git a/nginx_gen_team.sh b/nginx_gen_team.sh new file mode 100644 index 00000000..ebf28572 --- /dev/null +++ b/nginx_gen_team.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +curl http://localhost/admin/teams/export 2> /dev/null | grep "(.*)<.*$@ if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=\2/") { set $team \1; }@' diff --git a/onyx/tpl/bootstrap/admin/export_teams.tpl b/onyx/tpl/bootstrap/admin/export_teams.tpl index f9b47af1..7dc7767d 100644 --- a/onyx/tpl/bootstrap/admin/export_teams.tpl +++ b/onyx/tpl/bootstrap/admin/export_teams.tpl @@ -2,7 +2,7 @@ {foreach from=$teams item=t} - {$t->team_name} + {$t->team_name} {if $t->slogan}{$t->slogan}{/if} {if $t->get_members()} {foreach from=$t->get_members() item=m} diff --git a/submission.php b/submission.php index 02f65569..e9cf71fe 100644 --- a/submission.php +++ b/submission.php @@ -20,7 +20,22 @@ else if (!empty($_POST["solution"]) && !empty($_GET["team"]) && !empty($_GET["th $algos = array("md5", "sha1", "sha256", "sha384", "sha512", "whirlpool"); $content = ""; foreach($algos as $algo) - $content .= mcrypt_encrypt(MCRYPT_SERPENT_256, hash($algo, $_POST["solution"]), hash($algo, $filename), MCRYPT_MODE_ECB)."\n"; + { + $cnt = hash($algo, $filename, true); + // Encrypt twice on long key + $key = hash($algo, $_POST["solution"]); + + $kfirst = pack('H*', substr($key, 0, 64)); + $cnt = mcrypt_encrypt(MCRYPT_SERPENT, $kfirst, $cnt, MCRYPT_MODE_ECB); + + if (strlen($key) > 64) + { + $ksec = pack('H*', substr($key, 64, 64)); + $cnt = mcrypt_encrypt(MCRYPT_SERPENT, $ksec, $cnt, MCRYPT_MODE_ECB); + } + + $content .= bin2hex($cnt)."\n"; + } file_put_contents($file, $content, LOCK_EX); diff --git a/synchro.sh b/synchro.sh index 5f69615a..9406d1cd 100755 --- a/synchro.sh +++ b/synchro.sh @@ -19,7 +19,7 @@ rsync -e ssh -av $OPTS out/errors phobos:~/ rsync -e ssh -av $OPTS out/htdocs phobos:~/ rsync -e ssh -av $OPTS out/teams phobos:~/ rsync -e ssh -avL $OPTS files phobos:~/ -rsync -e ssh -av $OPTS nginx.conf submission.php misc/server.* misc/pki/cacert.crt misc/pki/crl.pem phobos:~/ +rsync -e ssh -av $OPTS nginx.conf submission.php misc/server.crt misc/server.key misc/pki/cacert.crt misc/pki/crl.pem phobos:~/ rsync -e ssh -av phobos:~/submission/ submission/ ssh phobos "rm -fv ~/submission/*" From 15a0c26b912ef5767e245b522b858333f7c1474c Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 21 Jan 2014 03:42:01 +0100 Subject: [PATCH 0211/2585] Add backup script --- backup.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 backup.sh diff --git a/backup.sh b/backup.sh new file mode 100755 index 00000000..120f5424 --- /dev/null +++ b/backup.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +cd `dirname "$0"` +TO_BCKP="/mnt/backup" + +chown synchro "$TO_BCKP" + +if [ "$UID" = "0" ] +then + SCRIPT=`pwd`/`basename "$0"` + su -c "sh $SCRIPT $@" synchro + exit $? +fi + +if mount | grep "$TO_BCKP" > /dev/null +then + + mysqldump -u backup --password="Riuy6of sae^W0Sh" fic2014 > "$TO_BCKP"/db-`date +%Y%m%d-%H%M`.sql + + rsync -avL true_files/ "$TO_BCKP" + rsync -avL logs/ "$TO_BCKP" + rsync -avL misc/ "$TO_BCKP" + rsync -avL .git "$TO_BCKP" + +else + echo No volume mount on $TO_BCKP +fi From d26e7826bd0f538d419e5ac13e52dfa982d95797 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 21 Jan 2014 03:56:17 +0100 Subject: [PATCH 0212/2585] Better backups --- backup.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backup.sh b/backup.sh index 120f5424..84852fca 100755 --- a/backup.sh +++ b/backup.sh @@ -15,12 +15,13 @@ fi if mount | grep "$TO_BCKP" > /dev/null then - mysqldump -u backup --password="Riuy6of sae^W0Sh" fic2014 > "$TO_BCKP"/db-`date +%Y%m%d-%H%M`.sql + mysqldump -u backup --password="Riuy6of sae^W0Sh" fic2014 > "$TO_BCKP"/db/`date +%Y%m%d-%H%M`.sql - rsync -avL true_files/ "$TO_BCKP" - rsync -avL logs/ "$TO_BCKP" - rsync -avL misc/ "$TO_BCKP" + rsync -avL misc "$TO_BCKP" rsync -avL .git "$TO_BCKP" + rsync -avL logs "$TO_BCKP" + rsync -avL /var/log "$TO_BCKP" + rsync -avL true_files "$TO_BCKP" else echo No volume mount on $TO_BCKP From 0c33d83131dfba13f167f20e6ef2d385f082bf9c Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 21 Jan 2014 17:45:46 +0100 Subject: [PATCH 0213/2585] Fixed carousel --- onyx/tpl/bootstrap/public/home.tpl | 79 +++++++++++++--------------- onyx/tpl/bootstrap/public/layout.tpl | 6 ++- onyx/tpl/bootstrap/summary.tpl | 2 +- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/onyx/tpl/bootstrap/public/home.tpl b/onyx/tpl/bootstrap/public/home.tpl index 72f6efbe..395aebdd 100644 --- a/onyx/tpl/bootstrap/public/home.tpl +++ b/onyx/tpl/bootstrap/public/home.tpl @@ -5,56 +5,51 @@ {/block} {block name=main} - {if isset($teams)} +{if isset($teams)} {/if} - - - {/block} diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index 8538e0ca..e8aeb0e0 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -22,7 +22,7 @@

    Top 10

    {foreach from=$top item=t key=k} -
    {$k+1}. {link href="{$t->id}-{$t->get_name_url()}" href_prefix="/" label={$t->get_name()|replace:"_":" et "}} +
    {$k+1}. {link href="{$t->id}-{$t->get_name_url()}" href_prefix="/" label={$t->get_name()|replace:"_":" "}} {$t->get_pts()} @@ -46,5 +46,9 @@ var end_challenge = new Date({$END * 1000}); {/if} update_end(); + $(document).ready(function() { + $('#carousel-team').carousel({ + interval: 2000 }); + }); {/block} diff --git a/onyx/tpl/bootstrap/summary.tpl b/onyx/tpl/bootstrap/summary.tpl index 1eed15df..c7435bcf 100644 --- a/onyx/tpl/bootstrap/summary.tpl +++ b/onyx/tpl/bootstrap/summary.tpl @@ -1,7 +1,7 @@ - + {for $i=1 to $nbExoMax} {/for} From 939e6d994d323f6308bbcfb4e2346c0f5ad812f8 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 21 Jan 2014 17:49:17 +0100 Subject: [PATCH 0214/2585] Increase the time of each carousel item to 10000 --- onyx/tpl/bootstrap/public/layout.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index e8aeb0e0..98f98070 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -48,7 +48,7 @@ update_end(); $(document).ready(function() { $('#carousel-team').carousel({ - interval: 2000 }); + interval: 10000 }); }); {/block} From ad5185dbc1e5cdb1b62893199954524fe6f80246 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 27 Aug 2014 12:25:23 +0200 Subject: [PATCH 0215/2585] Fix default config --- nginx-server-common.conf | 2 +- onyx/config/sample.root.xml | 2 +- onyx/db/sample.profile.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nginx-server-common.conf b/nginx-server-common.conf index d93c6113..13e887a0 100644 --- a/nginx-server-common.conf +++ b/nginx-server-common.conf @@ -41,7 +41,7 @@ location ~ .*.php$ { if (!-e $document_root$document_uri) { return 404; } - include /etc/nginx/fastcgi.conf; + include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/run/php-fpm.sock; fastcgi_index index.php; break; diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index 4d05ed20..86666818 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -38,7 +38,7 @@ - + diff --git a/onyx/db/sample.profile.php b/onyx/db/sample.profile.php index 1ad73643..f3c4e489 100644 --- a/onyx/db/sample.profile.php +++ b/onyx/db/sample.profile.php @@ -2,7 +2,7 @@ if(!defined('ONYX')) exit; -$___profile['db'] = 'kohler_palettes'; +$___profile['db'] = 'fic2014'; $___profile['host'] = 'localhost'; $___profile['user'] = 'root'; $___profile['pass'] = ''; From 30dc4612706c5503a127e292c9702d7eac96fd99 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 27 Aug 2014 12:26:13 +0200 Subject: [PATCH 0216/2585] Salt for CDN is not the same as PUBLIC --- htdocs/index.php | 2 +- onyx/tpl/bootstrap/layout.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/index.php b/htdocs/index.php index ac03ea5d..c0ed32bb 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -14,7 +14,7 @@ define("SALT_ADMIN", $VAR["prefix_admin"]); //Chargement de tout le nécessaire pour le site require_once("common.php"); -$template->assign("SALT_CDN",SALT_PUBLIC); +$template->assign("SALT_CDN",""); $template->assign("SALT_PUBLIC",SALT_PUBLIC); $template->assign("SALT_USER",SALT_USER); $template->assign("SALT_ADMIN",SALT_ADMIN); diff --git a/onyx/tpl/bootstrap/layout.tpl b/onyx/tpl/bootstrap/layout.tpl index 62f5cb44..ab292ff5 100644 --- a/onyx/tpl/bootstrap/layout.tpl +++ b/onyx/tpl/bootstrap/layout.tpl @@ -41,7 +41,7 @@ --> - + {block name=end}{/block} From 4ca3e568568a1a5f99266541b080d51417d48678 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 27 Aug 2014 12:26:49 +0200 Subject: [PATCH 0217/2585] Add a Dockerfile for development purpose --- Dockerfile | 45 +++++++++++++++++++++++++++++ php-fpm.conf | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 Dockerfile create mode 100644 php-fpm.conf diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..1b6e7725 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +# DOCKER-VERSION 1.1.0 + +# /!\ WARNING: the container generated through this Dockerfile is made only for development purpose; it is NOT SAFE or production ready. + +FROM debian:wheezy +MAINTAINER Pierre-Olivier Mercier + +# Install packages #################################################### + +RUN apt-get -y update +RUN apt-get install -y nginx-light php5-fpm mysql-server php5-mysql pwgen openssl + +# Copying files ####################################################### + +ADD . /var/www/fic2014-server/ + +# Configure softwares ################################################# + +RUN ln -sf /var/www/fic2014-server/nginx-server.conf /etc/nginx/sites-enabled/default +RUN ln -sf /var/www/fic2014-server/php-fpm.conf /etc/php5/fpm/pool.d/www.conf + +# Generate test certificates ########################################## + +RUN cd /var/www/fic2014-server/misc; bash ./CA.sh -newca + +# Import DB ########################################################### + +RUN service mysql start && echo "CREATE DATABASE fic2014;" | mysql -u root && cat /var/www/fic2014-server/db/fic2014.sql | mysql -u root fic2014 + +# Uncomment the following line to fill with random values +#RUN cat /var/www/fic2014-server/db/feed.sql | mysql -u root fic2014 + +# Configure site ###################################################### + +RUN ln -sf /var/www/fic2014-server/onyx/config/sample.root.xml /var/www/fic2014-server/onyx/config/root.xml +RUN sed -i "s/1386827772/`date -d 'now + 4 hours' +%s`/" /var/www/fic2014-server/onyx/config/root.xml +RUN sed -i "s/challenge-public//" /var/www/fic2014-server/onyx/config/root.xml + +RUN chmod 777 /var/www/fic2014-server/onyx/cache/ /var/www/fic2014-server/onyx/cache/templates/cache/ /var/www/fic2014-server/onyx/cache/templates/compile/ + +# ENVIRONNEMENT ####################################################### + +RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +EXPOSE 80/tcp 443/tcp +CMD ["sh", "-c", "cd /var/www/fic2014-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && /bin/bash"] diff --git a/php-fpm.conf b/php-fpm.conf new file mode 100644 index 00000000..e972ebe8 --- /dev/null +++ b/php-fpm.conf @@ -0,0 +1,81 @@ +; Start a new pool named 'www'. +; the variable $pool can we used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = www-data +group = www-data + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses on a +; specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /var/run/php-fpm.sock + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0666 +listen.owner = www-data +listen.group = www-data +listen.mode = 0640 + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 200 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 10 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 5 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 10 From 05c51d8f68ce93285aeafa338caf9777afe1cec8 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 27 Aug 2014 12:42:06 +0200 Subject: [PATCH 0218/2585] Add TODO --- TODO | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 00000000..f2d42400 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +- Départager les ex-æquo dans le classement +- Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe From 99d0152c3234c384f1d486efdd06d3b82b93c34c Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 9 Sep 2014 10:05:08 +0200 Subject: [PATCH 0219/2585] Prepare merge with server code --- Makefile => docs/guide/Makefile | 0 epita.pdf => docs/guide/epita.pdf | Bin guide.pdf => docs/guide/guide.pdf | Bin guide.tex => docs/guide/guide.tex | 0 windows_key.pdf => docs/guide/windows_key.pdf | Bin 5 files changed, 0 insertions(+), 0 deletions(-) rename Makefile => docs/guide/Makefile (100%) rename epita.pdf => docs/guide/epita.pdf (100%) rename guide.pdf => docs/guide/guide.pdf (100%) rename guide.tex => docs/guide/guide.tex (100%) rename windows_key.pdf => docs/guide/windows_key.pdf (100%) diff --git a/Makefile b/docs/guide/Makefile similarity index 100% rename from Makefile rename to docs/guide/Makefile diff --git a/epita.pdf b/docs/guide/epita.pdf similarity index 100% rename from epita.pdf rename to docs/guide/epita.pdf diff --git a/guide.pdf b/docs/guide/guide.pdf similarity index 100% rename from guide.pdf rename to docs/guide/guide.pdf diff --git a/guide.tex b/docs/guide/guide.tex similarity index 100% rename from guide.tex rename to docs/guide/guide.tex diff --git a/windows_key.pdf b/docs/guide/windows_key.pdf similarity index 100% rename from windows_key.pdf rename to docs/guide/windows_key.pdf From 7e4711ba5cf1c6ad6faeeb911a3a59a2f06fe29e Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 9 Sep 2014 10:38:46 +0200 Subject: [PATCH 0220/2585] Add README file --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..606e81bf --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# FIC forensic challenge validation server + +This is a CTF server for distributing and validating exercices. It is design to +be robust, so it uses some uncommon technologies like client certificate for +authentication, cryptographic functions and DMZ network architecture. + +## Development and testing + +The easiest way to have a working server is to build a Docker container. + +### Docker + +First, build the container with the following command: +``` +docker build -t fic2014 . +``` + +Then, run it with: +``` +docker run -t -i -P fic2014 +``` +It will ask you for a passphrase, you must provide one with at least 4 +characters. This key is used to generate the server certificate. + +When you see: +``` +root@xxxxxxxxxxxx:/var/www/fic2014-server/misc# +``` +congratulations, the container is running! + +Use `docker ps` to view to which local ports was assigned the contained +webserver. + + +## Production environnement + +### Setup + +#### Frontend + +FIXME + +#### Backend + +FIXME + + +### History + +#### FIC2014 + +Two machines were used : one for backend (Phobos) and one for frontend +(Deimos). They ran a GNU/Linux Gentoo Hardened with custom 3.2 kernel without +module loading, unused and unecessary components and with all GrSecurity +features activated. + +Each machine was two network interfaces: one was used to permit to the backend +machine to connect to the frontend (over IPv6). The second interface on the +backend was used for administration purpose (with a laptop not connected to +Internet). The second interface on the frontend was used to provide network +connectivity to participants. From 832e9cd221ebe540750d5219be0377d78422be5a Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 16:38:47 +0100 Subject: [PATCH 0221/2585] Add forgotten dependency --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1b6e7725..c52741bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ MAINTAINER Pierre-Olivier Mercier # Install packages #################################################### RUN apt-get -y update -RUN apt-get install -y nginx-light php5-fpm mysql-server php5-mysql pwgen openssl +RUN apt-get install -y nginx-light php5-fpm mysql-server php5-mysql php5-mcrypt pwgen openssl # Copying files ####################################################### From b135e7f6f687d7176d945b3e1ed7d14f9bb91221 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 16:38:54 +0100 Subject: [PATCH 0222/2585] Update TODO --- TODO | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TODO b/TODO index f2d42400..7ebe286b 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,5 @@ - Départager les ex-æquo dans le classement - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe +- Retrouver toutes les dépendances +- Vérifier la liste des ciphers dans la conf de nginx +- Dans la conf de nginx, vérifier que le contenu statique soit mis en cache côté navigateur From 27f9e7e37240bac7d70073fa749389cd61e6b041 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 16:39:05 +0100 Subject: [PATCH 0223/2585] Add setup instructions --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 606e81bf..fe82b807 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# FIC forensic challenge validation server +FIC forensic challenge validation server +======================================== This is a CTF server for distributing and validating exercices. It is design to be robust, so it uses some uncommon technologies like client certificate for authentication, cryptographic functions and DMZ network architecture. -## Development and testing +Development and testing +----------------------- The easiest way to have a working server is to build a Docker container. @@ -32,17 +34,53 @@ Use `docker ps` to view to which local ports was assigned the contained webserver. -## Production environnement +Production environnement +------------------------ ### Setup +You should compile/install hardened kernel (with latest stable GrSec patch) on +each machine. + +Prefer GNU/Linux distributions where most packages are compiled with `-fPIC` +and `-fstack-protector`, like Ubuntu or +[Gentoo Hardened](http://www.gentoo.org/proj/en/hardened/). + #### Frontend -FIXME +Keep in mind that this is the machine exposed to participant. + +##### Requirements + +* `nginx` with those modules: `aio` (for fast delivery of huge + content), `fastcgi`, `rewrite`, `ssl`; +* `php-fpm` with `mcrypt` module (for submission encryption); + +##### Firewall rules + +Expose to participants only 80 and 443 ports. + +Expose on synchronization interface the 22 port, used for synchronization and +administration purpose from backend. + +DROP **has to be** the default rule for INPUT, FORWARD and OUTPUT chains; use +CONNTRACK states. + #### Backend -FIXME +##### Requirements + +* `mysql`; +* `nginx` with `fastcgi` module; +* `php-fpm` with `mysql` module; +* `openssl` and `pwgen` for client certificat generation; +* `Mcrypt` from CPAN (`cpan -i Mcrypt`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); + +##### Firewall rules + +This machine shouldn't have any network connection, except outgoing one to the +frontend for synchronization. ### History From 76269a821d82a13599af712962eb6c079dad8d64 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 17:00:37 +0100 Subject: [PATCH 0224/2585] Don't forget to crypt disks --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fe82b807..3511bdf4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This is a CTF server for distributing and validating exercices. It is design to be robust, so it uses some uncommon technologies like client certificate for authentication, cryptographic functions and DMZ network architecture. -Development and testing +Development And Testing ----------------------- The easiest way to have a working server is to build a Docker container. @@ -34,7 +34,7 @@ Use `docker ps` to view to which local ports was assigned the contained webserver. -Production environnement +Production Environnement ------------------------ ### Setup @@ -46,6 +46,11 @@ Prefer GNU/Linux distributions where most packages are compiled with `-fPIC` and `-fstack-protector`, like Ubuntu or [Gentoo Hardened](http://www.gentoo.org/proj/en/hardened/). +As machines aren't always in safe place (transportation, night before CTF, +...), disks should be encrypted. + +**Always set strong password when it is possible** eg. SSL certificats, ... + #### Frontend Keep in mind that this is the machine exposed to participant. @@ -75,6 +80,7 @@ CONNTRACK states. * `nginx` with `fastcgi` module; * `php-fpm` with `mysql` module; * `openssl` and `pwgen` for client certificat generation; +* `mcrypt`; * `Mcrypt` from CPAN (`cpan -i Mcrypt`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); ##### Firewall rules @@ -97,3 +103,9 @@ machine to connect to the frontend (over IPv6). The second interface on the backend was used for administration purpose (with a laptop not connected to Internet). The second interface on the frontend was used to provide network connectivity to participants. + + +The D Day +--------- + +TODO From ca7570d90850fa6c95002d8fb6499aee5d2fd023 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 17:18:07 +0100 Subject: [PATCH 0225/2585] Fix template paths --- onyx/include/admin/exercice.php | 2 +- onyx/include/admin/list_users.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/onyx/include/admin/exercice.php b/onyx/include/admin/exercice.php index e4507cc8..b007d591 100644 --- a/onyx/include/admin/exercice.php +++ b/onyx/include/admin/exercice.php @@ -65,4 +65,4 @@ catch(ExerciceNotFoundException $e) return "404"; } -return SALT_ADMIN."/exercice"; +return "admin/exercice"; diff --git a/onyx/include/admin/list_users.php b/onyx/include/admin/list_users.php index 3ac2871f..8f57ccea 100644 --- a/onyx/include/admin/list_users.php +++ b/onyx/include/admin/list_users.php @@ -11,7 +11,7 @@ if (!empty($_GET["delete"])) else { erreur("Merci d'ajouter la variable misc_dir dans root.xml"); - return SALT_ADMIN."/users"; + return "admin/users"; } $id_team = intval($_GET["delete"]); @@ -28,7 +28,7 @@ else if (isset($_GET["drop"])) else { erreur("Merci d'ajouter la variable misc_dir dans root.xml"); - return SALT_ADMIN."/users"; + return "admin/users"; } foreach(Team::get_teams() as $team) @@ -44,4 +44,4 @@ else if (isset($_GET["drop"])) $template->assign("teams", Team::get_teams()); -return SALT_ADMIN."/users"; +return "admin/users"; From dbc97fda8a522cee370a197decb948b3c4ed9c66 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 17:36:28 +0100 Subject: [PATCH 0226/2585] Update TODO --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 7ebe286b..2bcccf76 100644 --- a/TODO +++ b/TODO @@ -3,3 +3,4 @@ - Retrouver toutes les dépendances - Vérifier la liste des ciphers dans la conf de nginx - Dans la conf de nginx, vérifier que le contenu statique soit mis en cache côté navigateur +- Mettre à jour Smarty (et passer en « secure mode » ?) From 4a67552a298845bfa803c6603ea11e0941b1d6ae Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 17:37:44 +0100 Subject: [PATCH 0227/2585] Can send solutions on the backend (using the same file as frontend) --- onyx/include/team/exercice.php | 22 +++++++++++++--------- submission.php | 20 ++++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/onyx/include/team/exercice.php b/onyx/include/team/exercice.php index 7e2e5eb5..fa6af0d0 100644 --- a/onyx/include/team/exercice.php +++ b/onyx/include/team/exercice.php @@ -41,18 +41,22 @@ if (isset($VAR['submission_dir'])) { if (is_writable("$submission_dir/")) { - $file = $submission_dir.'/'.$p[1].'-'.$p[2].'-'.$p[3]; + function show_submission_result($path) + { + header("Location: /".SALT_USER."/".$path); + exit; + } - file_put_contents($file, $_POST['solution'], LOCK_EX); + $_GET["team"] = $p[1]; + $_GET["theme"] = $p[2]; + $_GET["exercice"] = $p[3]; - header("Location: /".implode("/", $p)); - exit; - } - else - { - header("Location: /".implode("/", $p)."/werr"); - exit; + require("../submission.php"); } + + // Fallback error + header("Location: /".implode("/", $p)."/werr"); + exit; } } } diff --git a/submission.php b/submission.php index e9cf71fe..f99d2386 100644 --- a/submission.php +++ b/submission.php @@ -1,11 +1,15 @@ Date: Wed, 5 Nov 2014 17:46:18 +0100 Subject: [PATCH 0228/2585] Change fic2014 to fic --- Dockerfile | 22 +++++++++++----------- README.md | 6 +++--- backup.sh | 2 +- misc/CA.sh | 2 +- misc/openssl.cnf | 12 ++++++------ nginx-server-common.conf | 4 ++-- nginx-server.conf | 8 ++++---- nginx.conf | 24 ++++++++++++------------ onyx/config/sample.root.xml | 8 ++++---- onyx/db/sample.profile.php | 2 +- onyx/tpl/bootstrap/layout.tpl | 4 ++-- 11 files changed, 47 insertions(+), 47 deletions(-) diff --git a/Dockerfile b/Dockerfile index c52741bf..75aba18f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,34 +12,34 @@ RUN apt-get install -y nginx-light php5-fpm mysql-server php5-mysql php5-mcrypt # Copying files ####################################################### -ADD . /var/www/fic2014-server/ +ADD . /var/www/fic-server/ # Configure softwares ################################################# -RUN ln -sf /var/www/fic2014-server/nginx-server.conf /etc/nginx/sites-enabled/default -RUN ln -sf /var/www/fic2014-server/php-fpm.conf /etc/php5/fpm/pool.d/www.conf +RUN ln -sf /var/www/fic-server/nginx-server.conf /etc/nginx/sites-enabled/default +RUN ln -sf /var/www/fic-server/php-fpm.conf /etc/php5/fpm/pool.d/www.conf # Generate test certificates ########################################## -RUN cd /var/www/fic2014-server/misc; bash ./CA.sh -newca +RUN cd /var/www/fic-server/misc; bash ./CA.sh -newca # Import DB ########################################################### -RUN service mysql start && echo "CREATE DATABASE fic2014;" | mysql -u root && cat /var/www/fic2014-server/db/fic2014.sql | mysql -u root fic2014 +RUN service mysql start && echo "CREATE DATABASE fic;" | mysql -u root && cat /var/www/fic-server/db/fic2014.sql | mysql -u root fic # Uncomment the following line to fill with random values -#RUN cat /var/www/fic2014-server/db/feed.sql | mysql -u root fic2014 +#RUN cat /var/www/fic-server/db/feed.sql | mysql -u root fic # Configure site ###################################################### -RUN ln -sf /var/www/fic2014-server/onyx/config/sample.root.xml /var/www/fic2014-server/onyx/config/root.xml -RUN sed -i "s/1386827772/`date -d 'now + 4 hours' +%s`/" /var/www/fic2014-server/onyx/config/root.xml -RUN sed -i "s/challenge-public//" /var/www/fic2014-server/onyx/config/root.xml +RUN ln -sf /var/www/fic-server/onyx/config/sample.root.xml /var/www/fic-server/onyx/config/root.xml +RUN sed -i "s/1386827772/`date -d 'now + 4 hours' +%s`/" /var/www/fic-server/onyx/config/root.xml +RUN sed -i "s/challenge-public//" /var/www/fic-server/onyx/config/root.xml -RUN chmod 777 /var/www/fic2014-server/onyx/cache/ /var/www/fic2014-server/onyx/cache/templates/cache/ /var/www/fic2014-server/onyx/cache/templates/compile/ +RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/templates/cache/ /var/www/fic-server/onyx/cache/templates/compile/ # ENVIRONNEMENT ####################################################### RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* EXPOSE 80/tcp 443/tcp -CMD ["sh", "-c", "cd /var/www/fic2014-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && /bin/bash"] +CMD ["sh", "-c", "cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && /bin/bash"] diff --git a/README.md b/README.md index 3511bdf4..ea77dd1c 100644 --- a/README.md +++ b/README.md @@ -14,19 +14,19 @@ The easiest way to have a working server is to build a Docker container. First, build the container with the following command: ``` -docker build -t fic2014 . +docker build -t fic . ``` Then, run it with: ``` -docker run -t -i -P fic2014 +docker run -t -i -P fic ``` It will ask you for a passphrase, you must provide one with at least 4 characters. This key is used to generate the server certificate. When you see: ``` -root@xxxxxxxxxxxx:/var/www/fic2014-server/misc# +root@xxxxxxxxxxxx:/var/www/fic-server/misc# ``` congratulations, the container is running! diff --git a/backup.sh b/backup.sh index 84852fca..2a0f9d0e 100755 --- a/backup.sh +++ b/backup.sh @@ -15,7 +15,7 @@ fi if mount | grep "$TO_BCKP" > /dev/null then - mysqldump -u backup --password="Riuy6of sae^W0Sh" fic2014 > "$TO_BCKP"/db/`date +%Y%m%d-%H%M`.sql + mysqldump -u backup --password="Riuy6of sae^W0Sh" fic > "$TO_BCKP"/db/`date +%Y%m%d-%H%M`.sql rsync -avL misc "$TO_BCKP" rsync -avL .git "$TO_BCKP" diff --git a/misc/CA.sh b/misc/CA.sh index db4ba6c4..bfc99b5e 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -62,7 +62,7 @@ case $1 in ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') echo -e "${GREEN}Making CA key and csr${COLOR_RST}" - sed -i 's/=.*#COMMONNAME/= FIC2014 CA #COMMONNAME/' $OPENSSL_CONF + sed -i 's/=.*#COMMONNAME/= FIC CA #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF type pwgen > /dev/null diff --git a/misc/openssl.cnf b/misc/openssl.cnf index 2cb594f2..1fc532fd 100644 --- a/misc/openssl.cnf +++ b/misc/openssl.cnf @@ -15,7 +15,7 @@ oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: -# extensions = +# extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) @@ -39,7 +39,7 @@ default_ca = CA_default # The default ca section #################################################################### [ CA_default ] -dir = /var/www/fic2014-server/misc//pki #DIR # Where everything is kept +dir = /var/www/fic-server/misc//pki #DIR # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. @@ -111,7 +111,7 @@ x509_extensions = v3_ca # The extentions to add to the self signed cert # input_password = secret # output_password = secret -# This sets a mask for permitted string types. There are several options. +# This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString (PKIX recommendation before 2004) # utf8only: only UTF8Strings (PKIX recommendation after 2004). @@ -162,7 +162,7 @@ challengePassword_max = 20 unstructuredName = An optional company name [CORE_CA] -nsComment = "FIC2014 CA" +nsComment = "FIC CA" basicConstraints = critical,CA:TRUE,pathlen:1 subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always @@ -173,7 +173,7 @@ subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer [SERVER_SSL] -nsComment = "FIC2014 Server" +nsComment = "FIC Server" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy @@ -185,7 +185,7 @@ subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer [CLIENT_SSL] -nsComment = "FIC2014 Client" +nsComment = "FIC Client" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy diff --git a/nginx-server-common.conf b/nginx-server-common.conf index 13e887a0..5df0e129 100644 --- a/nginx-server-common.conf +++ b/nginx-server-common.conf @@ -1,7 +1,7 @@ access_log /var/log/nginx/fic.access_log; error_log /var/log/nginx/fic.error_log; - root /var/www/fic2014-server/htdocs; + root /var/www/fic-server/htdocs; index index.php; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; @@ -19,7 +19,7 @@ location /files { - root /var/www/fic2014-server/; + root /var/www/fic-server/; } location ~* \favicon.ico$ { diff --git a/nginx-server.conf b/nginx-server.conf index 64c4eed6..3e8e0cc3 100644 --- a/nginx-server.conf +++ b/nginx-server.conf @@ -2,17 +2,17 @@ server { listen 443 ssl; listen [::]:443 ipv6only=on ssl; - ssl_certificate /var/www/fic2014-server/misc/server.crt; - ssl_certificate_key /var/www/fic2014-server/misc/server.key; + ssl_certificate /var/www/fic-server/misc/server.crt; + ssl_certificate_key /var/www/fic-server/misc/server.key; # ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # ssl_prefer_server_ciphers on; # ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; - include /var/www/fic2014-server/nginx-server-common.conf; + include /var/www/fic-server/nginx-server-common.conf; } server { listen 80; - include /var/www/fic2014-server/nginx-server-common.conf; + include /var/www/fic-server/nginx-server-common.conf; } diff --git a/nginx.conf b/nginx.conf index da0b2a10..a9d69b23 100644 --- a/nginx.conf +++ b/nginx.conf @@ -13,21 +13,21 @@ server { listen 443 ssl; listen [::]:443 ipv6only=on ssl; - root /var/www/fic2014-server/htdocs/; + root /var/www/fic-server/htdocs/; server_tokens off; access_log /var/log/nginx/fic.access_log; error_log /var/log/nginx/fic.error_log; - ssl_certificate /var/www/fic2014-server/server.crt; - ssl_certificate_key /var/www/fic2014-server/server.key; + ssl_certificate /var/www/fic-server/server.crt; + ssl_certificate_key /var/www/fic-server/server.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; - ssl_client_certificate /var/www/fic2014-server/cacert.crt; + ssl_client_certificate /var/www/fic-server/cacert.crt; ssl_verify_client optional; - ssl_crl /var/www/fic2014-server/crl.pem; + ssl_crl /var/www/fic-server/crl.pem; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; @@ -70,17 +70,17 @@ server { if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=De_Priest_Tjonck/") { set $team 365; } if ($team) { - root /var/www/fic2014-server/teams/$team$1; + root /var/www/fic-server/teams/$team$1; rewrite ^/([0-9]+-?[a-zA-Z0-9_-]*)/([a-zA-Z0-9_]+)/submission$ /submission.php?team=$team&theme=$1&exercice=$2 last; } if ($team = 0) { - root /var/www/fic2014-server/htdocs/; + root /var/www/fic-server/htdocs/; } } location /errors { - root /var/www/fic2014-server/; + root /var/www/fic-server/; } location /connected @@ -90,7 +90,7 @@ server { location /files { - root /var/www/fic2014-server/; + root /var/www/fic-server/; aio on; directio 512; @@ -98,14 +98,14 @@ server { } location ~* \favicon.ico$ { - root /var/www/fic2014-server/htdocs/; + root /var/www/fic-server/htdocs/; access_log off; expires 1d; add_header Cache-Control public; } location ~ ^/(assets|img|js|css|fonts)/ { - root /var/www/fic2014-server/htdocs/; + root /var/www/fic-server/htdocs/; access_log off; expires 7d; add_header Cache-Control public; @@ -117,7 +117,7 @@ server { location /submission.php { - root /var/www/fic2014-server/; + root /var/www/fic-server/; limit_rate 4k; diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index 86666818..748b5433 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -1,10 +1,10 @@ - + 1386827772 - /var/www/fic2014-server/files/ - /var/www/fic2014-server/misc/ - /var/www/fic2014-server/submission/ + /var/www/fic-server/files/ + /var/www/fic-server/misc/ + /var/www/fic-server/submission/ challenge-public challenge challenge-admin diff --git a/onyx/db/sample.profile.php b/onyx/db/sample.profile.php index f3c4e489..670c80b0 100644 --- a/onyx/db/sample.profile.php +++ b/onyx/db/sample.profile.php @@ -2,7 +2,7 @@ if(!defined('ONYX')) exit; -$___profile['db'] = 'fic2014'; +$___profile['db'] = 'fic'; $___profile['host'] = 'localhost'; $___profile['user'] = 'root'; $___profile['pass'] = ''; diff --git a/onyx/tpl/bootstrap/layout.tpl b/onyx/tpl/bootstrap/layout.tpl index ab292ff5..9f812352 100644 --- a/onyx/tpl/bootstrap/layout.tpl +++ b/onyx/tpl/bootstrap/layout.tpl @@ -2,7 +2,7 @@ - {block name=title}Challenge FIC2014{/block} + {block name=title}Challenge FIC2015{/block} @@ -35,7 +35,7 @@

    From 17a05b0d26634340f109457650bf53235e6ab16c Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 5 Nov 2014 18:02:55 +0100 Subject: [PATCH 0229/2585] Display an error on admin home page if misc/ is not writable --- TODO | 1 + onyx/include/admin/home.php | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/TODO b/TODO index 2bcccf76..f289df09 100644 --- a/TODO +++ b/TODO @@ -4,3 +4,4 @@ - Vérifier la liste des ciphers dans la conf de nginx - Dans la conf de nginx, vérifier que le contenu statique soit mis en cache côté navigateur - Mettre à jour Smarty (et passer en « secure mode » ?) +- Admin, exercice: pas normal qu'il y ait des réponses RAW dans les data de tests diff --git a/onyx/include/admin/home.php b/onyx/include/admin/home.php index 79bcbfcc..6268084f 100644 --- a/onyx/include/admin/home.php +++ b/onyx/include/admin/home.php @@ -3,7 +3,14 @@ if(!defined('ONYX')) exit; if (isset($VAR['misc_dir'])) +{ $misc_dir = $VAR['misc_dir']; + if (!is_writable($misc_dir)) + { + erreur("Dossier misc/ non accessible en écriture. ($misc_dir)"); + return "admin/home"; + } +} else { erreur("Merci d'ajouter la variable misc_dir dans root.xml"); From ec2604142f47b119b6e9ec8391b1e8a9c27c91ca Mon Sep 17 00:00:00 2001 From: nemunaire Date: Mon, 10 Nov 2014 17:21:29 +0100 Subject: [PATCH 0230/2585] Stronger SSL config --- TODO | 1 - nginx-server-common.conf | 2 ++ nginx.conf | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index f289df09..ba8dafcc 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ - Départager les ex-æquo dans le classement - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe - Retrouver toutes les dépendances -- Vérifier la liste des ciphers dans la conf de nginx - Dans la conf de nginx, vérifier que le contenu statique soit mis en cache côté navigateur - Mettre à jour Smarty (et passer en « secure mode » ?) - Admin, exercice: pas normal qu'il y ait des réponses RAW dans les data de tests diff --git a/nginx-server-common.conf b/nginx-server-common.conf index 5df0e129..e33e72cf 100644 --- a/nginx-server-common.conf +++ b/nginx-server-common.conf @@ -5,6 +5,8 @@ index index.php; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; location / { if (-f $request_filename) { diff --git a/nginx.conf b/nginx.conf index a9d69b23..170fd8f3 100644 --- a/nginx.conf +++ b/nginx.conf @@ -24,12 +24,15 @@ server { ssl_certificate_key /var/www/fic-server/server.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; - ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; +# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + ssl_ciphers AES256+EECDH:AES256+EDH; ssl_client_certificate /var/www/fic-server/cacert.crt; ssl_verify_client optional; ssl_crl /var/www/fic-server/crl.pem; add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; error_page 400 /errors/400/index.html; error_page 403 /errors/403/index.html; From 0c22173def65cdbcca8f0606c403432a9b7f1f93 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Mon, 10 Nov 2014 17:24:19 +0100 Subject: [PATCH 0231/2585] Remember to add ssl_dhparam --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index ba8dafcc..1e48acdb 100644 --- a/TODO +++ b/TODO @@ -2,5 +2,6 @@ - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe - Retrouver toutes les dépendances - Dans la conf de nginx, vérifier que le contenu statique soit mis en cache côté navigateur +- Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) - Admin, exercice: pas normal qu'il y ait des réponses RAW dans les data de tests From 5196487b0c6d8802d6e6c9361b1b8d938494c348 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Mon, 10 Nov 2014 17:26:16 +0100 Subject: [PATCH 0232/2585] Update TODO --- TODO | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO b/TODO index 1e48acdb..c19e8c63 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ - Départager les ex-æquo dans le classement - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe - Retrouver toutes les dépendances -- Dans la conf de nginx, vérifier que le contenu statique soit mis en cache côté navigateur - Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) - Admin, exercice: pas normal qu'il y ait des réponses RAW dans les data de tests From cf4f70e7a5c6cbd7f35a2adf318950e6824eddf6 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Mon, 10 Nov 2014 18:00:57 +0100 Subject: [PATCH 0233/2585] Update Dockerfile (best-practices, misc dir rights, ...) --- Dockerfile | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 75aba18f..16415623 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,8 +7,17 @@ MAINTAINER Pierre-Olivier Mercier # Install packages #################################################### -RUN apt-get -y update -RUN apt-get install -y nginx-light php5-fpm mysql-server php5-mysql php5-mcrypt pwgen openssl +RUN apt-get -y update && \ + apt-get install -y \ + nginx-light \ + php5-fpm \ + mysql-server \ + php5-mysql \ + php5-mcrypt \ + pwgen \ + openssl \ + && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Copying files ####################################################### @@ -40,6 +49,5 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem # ENVIRONNEMENT ####################################################### -RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* EXPOSE 80/tcp 443/tcp -CMD ["sh", "-c", "cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && /bin/bash"] +CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && /bin/bash"] From e1e9050522ede1b6b7efad67d7b29255a7b083d1 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Mon, 10 Nov 2014 18:14:51 +0100 Subject: [PATCH 0234/2585] Fix DB schema by adding missing hash algorithms --- TODO | 1 - db/fic2014.sql | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/TODO b/TODO index c19e8c63..c755440e 100644 --- a/TODO +++ b/TODO @@ -3,4 +3,3 @@ - Retrouver toutes les dépendances - Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) -- Admin, exercice: pas normal qu'il y ait des réponses RAW dans les data de tests diff --git a/db/fic2014.sql b/db/fic2014.sql index 0b8f5e2c..ea48d5c5 100644 --- a/db/fic2014.sql +++ b/db/fic2014.sql @@ -68,7 +68,7 @@ CREATE TABLE IF NOT EXISTS `exercice_tries` ( CREATE TABLE IF NOT EXISTS `exercice_keys` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id_exercice` varchar(100) COLLATE utf8_unicode_ci NOT NULL, - `format` enum('raw','md5','sha1','sha256','sha512') COLLATE utf8_unicode_ci NOT NULL, + `format` enum('raw','md5','sha1','sha224','sha256','sha384','sha512','whirlpool') COLLATE utf8_unicode_ci NOT NULL, `value` varbinary(150) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; From 7f90fc8c07b0c4ba3b3ff14a8f2acebf9e350597 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 19 Nov 2014 18:01:04 +0100 Subject: [PATCH 0235/2585] Add .dockerignore --- .dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..6b8710a7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git From 9a576420294be0f080719bede3e6c91661d386b5 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 19 Nov 2014 18:11:43 +0100 Subject: [PATCH 0236/2585] All dependencies should have been listed in README --- Dockerfile | 1 + README.md | 12 +++++++++--- TODO | 1 - 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 16415623..f4899490 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ RUN apt-get -y update && \ mysql-server \ php5-mysql \ php5-mcrypt \ + libmcrypt-dev \ pwgen \ openssl \ && \ diff --git a/README.md b/README.md index ea77dd1c..9bb814e8 100644 --- a/README.md +++ b/README.md @@ -81,20 +81,26 @@ CONNTRACK states. * `php-fpm` with `mysql` module; * `openssl` and `pwgen` for client certificat generation; * `mcrypt`; -* `Mcrypt` from CPAN (`cpan -i Mcrypt`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); +* `Mcrypt` from CPAN (`cpan -i Mcrypt`, on Debian, it requires `libtool` and + `build-essential`) to decrypt submissions (see + https://metacpan.org/pod/Mcrypt); ##### Firewall rules This machine shouldn't have any network connection, except outgoing one to the frontend for synchronization. +##### Others setups + +Indicate in `/etc/hosts.conf` IP(s) of the frontend. + ### History #### FIC2014 -Two machines were used : one for backend (Phobos) and one for frontend -(Deimos). They ran a GNU/Linux Gentoo Hardened with custom 3.2 kernel without +Two machines were used : one for backend (Deimos) and one for frontend +(Phobos). They ran a GNU/Linux Gentoo Hardened with custom 3.2 kernel without module loading, unused and unecessary components and with all GrSecurity features activated. diff --git a/TODO b/TODO index c755440e..580765a5 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ - Départager les ex-æquo dans le classement - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe -- Retrouver toutes les dépendances - Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) From 96805a5e1bb993b9b6a6c69396f85f8a28e690c1 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 19 Nov 2014 18:29:46 +0100 Subject: [PATCH 0237/2585] Document some script + centralize script configuration --- backup.sh | 15 +++++++++------ clear_cache.sh | 4 ++++ config.sh | 11 +++++++++++ launch.sh | 6 +++++- nginx_gen_team.sh | 3 +++ stop.sh | 2 ++ synchro.sh | 23 +++++++++++++++-------- 7 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 config.sh diff --git a/backup.sh b/backup.sh index 2a0f9d0e..6b23f068 100755 --- a/backup.sh +++ b/backup.sh @@ -1,21 +1,24 @@ #!/bin/sh -cd `dirname "$0"` -TO_BCKP="/mnt/backup" +# This script mades backup of important things -chown synchro "$TO_BCKP" +cd `dirname "$0"` + +source config.sh + +chown "$SYNCHRO_USER" "$TO_BCKP" if [ "$UID" = "0" ] then SCRIPT=`pwd`/`basename "$0"` - su -c "sh $SCRIPT $@" synchro + su -c "sh $SCRIPT $@" "$SYNCHRO_USER" exit $? fi if mount | grep "$TO_BCKP" > /dev/null then - mysqldump -u backup --password="Riuy6of sae^W0Sh" fic > "$TO_BCKP"/db/`date +%Y%m%d-%H%M`.sql + mysqldump -u backup --password="$BCKP_PASS" fic > "$TO_BCKP"/db/`date +%Y%m%d-%H%M`.sql rsync -avL misc "$TO_BCKP" rsync -avL .git "$TO_BCKP" @@ -24,5 +27,5 @@ then rsync -avL true_files "$TO_BCKP" else - echo No volume mount on $TO_BCKP + echo No volume mounted on $TO_BCKP fi diff --git a/clear_cache.sh b/clear_cache.sh index cb528dd4..5d3d5c2f 100755 --- a/clear_cache.sh +++ b/clear_cache.sh @@ -1,7 +1,11 @@ #!/bin/sh +# This script deletes Onyx framework cache + cd `dirname "$0"` +source config.sh + for n in "$@" do MD5=`echo -n $n | md5sum | cut -d " " -f 1` diff --git a/config.sh b/config.sh new file mode 100644 index 00000000..bc07a615 --- /dev/null +++ b/config.sh @@ -0,0 +1,11 @@ +# The name of the frontend, like indicated in /etc/hosts +FRONTEND_HOSTNAME="phobos" + +# Username of the unpriviledge user that runs scripts +SYNCHRO_USER="synchro" + +# Directory where backup should be made +TO_BCKP="/mnt/backup" + +# Password of the MySQL user backup (with RO rights) +BCKP_PASS="Riuy6of sae^W0Sh" diff --git a/launch.sh b/launch.sh index eee62513..ed33db08 100755 --- a/launch.sh +++ b/launch.sh @@ -1,12 +1,16 @@ #!/bin/sh +# This script does all actions in backend production environment + rm -f /tmp/stop cd `dirname "$0"` +source config.sh + if [ "$UID" = "0" ] then SCRIPT=`pwd`/`basename "$0"` - su -c "sh $SCRIPT" synchro + su -c "sh $SCRIPT" "$SYNCHRO_USER" exit $? fi diff --git a/nginx_gen_team.sh b/nginx_gen_team.sh index ebf28572..6347421c 100644 --- a/nginx_gen_team.sh +++ b/nginx_gen_team.sh @@ -1,3 +1,6 @@ #!/bin/sh +# Generate from database (exported XML from the website) the part of nginx +# configuration file authenticating teams + curl http://localhost/admin/teams/export 2> /dev/null | grep "(.*)<.*$@ if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=\2/") { set $team \1; }@' diff --git a/stop.sh b/stop.sh index 5bd241cc..71f6776f 100755 --- a/stop.sh +++ b/stop.sh @@ -1,3 +1,5 @@ #!/bin/sh +# Best way to stop the launch.sh script + touch /tmp/stop diff --git a/synchro.sh b/synchro.sh index 9406d1cd..e6f81ce7 100755 --- a/synchro.sh +++ b/synchro.sh @@ -1,11 +1,16 @@ #!/bin/sh +# This script synchronizes first, the generated frontend and then +# retrieves submissions + cd `dirname "$0"` +source config.sh + if [ "$UID" = "0" ] then SCRIPT=`pwd`/`basename "$0"` - su -c "sh $SCRIPT $@" synchro + su -c "sh $SCRIPT $@" "$SYNCHRO_USER" exit $? fi @@ -15,13 +20,15 @@ then OPTS="$OPTS --delete" fi -rsync -e ssh -av $OPTS out/errors phobos:~/ -rsync -e ssh -av $OPTS out/htdocs phobos:~/ -rsync -e ssh -av $OPTS out/teams phobos:~/ -rsync -e ssh -avL $OPTS files phobos:~/ -rsync -e ssh -av $OPTS nginx.conf submission.php misc/server.crt misc/server.key misc/pki/cacert.crt misc/pki/crl.pem phobos:~/ +# Synchronize HTML pages +rsync -e ssh -av $OPTS out/errors "$FRONTEND_HOSTNAME":~/ +rsync -e ssh -av $OPTS out/htdocs "$FRONTEND_HOSTNAME":~/ +rsync -e ssh -av $OPTS out/teams "$FRONTEND_HOSTNAME":~/ +rsync -e ssh -avL $OPTS files "$FRONTEND_HOSTNAME":~/ +rsync -e ssh -av $OPTS nginx.conf submission.php misc/server.crt misc/server.key misc/pki/cacert.crt misc/pki/crl.pem "$FRONTEND_HOSTNAME":~/ -rsync -e ssh -av phobos:~/submission/ submission/ -ssh phobos "rm -fv ~/submission/*" +# Synchronize submissions +rsync -e ssh -av "$FRONTEND_HOSTNAME":~/submission/ submission/ +ssh "$FRONTEND_HOSTNAME" "rm -fv ~/submission/*" exit $? From 2d4e7400cb4b200c6dcca4a1194e48dd95d13fbb Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 19 Nov 2014 18:30:07 +0100 Subject: [PATCH 0238/2585] Add themes DTD --- docs/dtd/themes.dtd | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/dtd/themes.dtd diff --git a/docs/dtd/themes.dtd b/docs/dtd/themes.dtd new file mode 100644 index 00000000..98510773 --- /dev/null +++ b/docs/dtd/themes.dtd @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From d368f0862b2d26247f655b40a8db064b349399c4 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 11:17:45 +0100 Subject: [PATCH 0239/2585] Merge CSS files and introduce dev theme --- TODO | 1 + htdocs/css/dev.css | 3 ++ htdocs/css/home.css | 19 ------------ htdocs/css/{score.css => main.css} | 43 ++++++++++++++++++---------- onyx/tpl/bootstrap/layout.tpl | 8 ++++-- onyx/tpl/bootstrap/public/layout.tpl | 3 +- onyx/tpl/bootstrap/teams/layout.tpl | 3 +- onyx/tpl/bootstrap/teams/lobby.tpl | 3 +- 8 files changed, 40 insertions(+), 43 deletions(-) create mode 100644 htdocs/css/dev.css delete mode 100644 htdocs/css/home.css rename htdocs/css/{score.css => main.css} (61%) diff --git a/TODO b/TODO index 580765a5..2d55d580 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,4 @@ - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe - Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) +- Mettre à jour les logos diff --git a/htdocs/css/dev.css b/htdocs/css/dev.css new file mode 100644 index 00000000..68f4b0ad --- /dev/null +++ b/htdocs/css/dev.css @@ -0,0 +1,3 @@ +.clock { + display: none; +} diff --git a/htdocs/css/home.css b/htdocs/css/home.css deleted file mode 100644 index 343be509..00000000 --- a/htdocs/css/home.css +++ /dev/null @@ -1,19 +0,0 @@ -.clock #ficlogo { - float: left; - height: 100px; - margin-left: 25px; - width: 12%; -} -.clock #epitalogo { - float: right; - height: 100px; - width: 14%; -} -.clock #ficlogo img { - max-height: 170px; - max-width: 100%; -} -.clock #epitalogo img { - max-height: 170px; - max-width: 100%; -} \ No newline at end of file diff --git a/htdocs/css/score.css b/htdocs/css/main.css similarity index 61% rename from htdocs/css/score.css rename to htdocs/css/main.css index 4b45726a..084763cc 100644 --- a/htdocs/css/score.css +++ b/htdocs/css/main.css @@ -1,4 +1,3 @@ - .clock { background:#202020; margin: 0 auto; @@ -6,14 +5,32 @@ border: 1px solid #333; color: #fff; } - -#Date { - background:#202020; - font-family: bold, sans-serif; - text-align:center; - text-shadow:0 0 5px #00c6ff; +.clock #ficlogo { + float: left; + height: 100px; + margin-left: 25px; + width: 12%; +} +.clock #epitalogo { + float: right; + height: 100px; + width: 14%; +} +.clock #ficlogo img { + max-height: 170px; + max-width: 100%; +} +.clock #epitalogo img { + max-height: 170px; + max-width: 100%; } +#Date { + background:#202020; + font-family: bold, sans-serif; + text-align:center; + text-shadow:0 0 5px #00c6ff; +} #Date + ul { width: 800px; margin: 0 auto; @@ -21,7 +38,6 @@ list-style: none; text-align: center; } - #Date + ul li { display: inline; font-size: 5em; @@ -32,14 +48,12 @@ .point { position: relative; - -moz-animation: mymove 1s ease infinite; - -webkit-animation: mymove 1s ease infinite; + -moz-animation: clockanim 1s ease infinite; + -webkit-animation: clockanim 1s ease infinite; padding-left: 10px; padding-right: 10px; } - -/* Simple Animation */ -@-webkit-keyframes mymove { +@-webkit-keyframes clockanim { 0% { opacity: 1.0; text-shadow: 0 0 20px #00c6ff; @@ -55,8 +69,7 @@ text-shadow: 0 0 20px #00c6ff; } } - -@-moz-keyframes mymove { +@-moz-keyframes clockanim { 0% { opacity: 1.0; text-shadow: 0 0 20px #00c6ff; diff --git a/onyx/tpl/bootstrap/layout.tpl b/onyx/tpl/bootstrap/layout.tpl index 9f812352..2c35d348 100644 --- a/onyx/tpl/bootstrap/layout.tpl +++ b/onyx/tpl/bootstrap/layout.tpl @@ -3,9 +3,10 @@ {block name=title}Challenge FIC2015{/block} - - - + + + + diff --git a/onyx/tpl/bootstrap/public/layout.tpl b/onyx/tpl/bootstrap/public/layout.tpl index cccedb88..062e1dc2 100644 --- a/onyx/tpl/bootstrap/public/layout.tpl +++ b/onyx/tpl/bootstrap/public/layout.tpl @@ -39,7 +39,7 @@ {/block} {block name=end} - + + + From ec69cea4f6447876ffe105b2688a0da23e1a0a84 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 15:33:28 +0100 Subject: [PATCH 0244/2585] Forget one dependancy --- Dockerfile | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index f4899490..00fe2e20 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get -y update && \ php5-mysql \ php5-mcrypt \ libmcrypt-dev \ + libwww-perl \ pwgen \ openssl \ && \ diff --git a/README.md b/README.md index 9bb814e8..821cd00b 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ CONNTRACK states. * `php-fpm` with `mysql` module; * `openssl` and `pwgen` for client certificat generation; * `mcrypt`; +* `HTTP::Request::Common` perl module; * `Mcrypt` from CPAN (`cpan -i Mcrypt`, on Debian, it requires `libtool` and `build-essential`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); From 4fe56db0d62ef2aadd6b8fc195497054fc5c3e0d Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 15:39:54 +0100 Subject: [PATCH 0245/2585] Document gen_site.pl --- gen_site.pl | 258 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 226 insertions(+), 32 deletions(-) diff --git a/gen_site.pl b/gen_site.pl index 5f980509..17928f21 100755 --- a/gen_site.pl +++ b/gen_site.pl @@ -1,4 +1,14 @@ #!/usr/bin/env perl +#============================================================================= +# +# USAGE: ./gen_site.pl [options] [commands] +# +# DESCRIPTION: More efficient wget -m +# +# AUTHOR: Pierre-Olivier Mercier +# ORGANIZATION: EPITA SRS +# +#============================================================================= use v5.10.1; use strict; @@ -16,6 +26,8 @@ use Getopt::Long; use IO::Socket; use Thread::Queue; +### GLOBALS ########################################################### + our $outdir = "outest"; our $outteams = "/teams/"; our $outerrors = "/errors/"; @@ -29,6 +41,16 @@ our $baseerrors = "/errors/"; our $baseteams = "/connected/"; our $threads = 6; +my $deamon; +my $socket; + +my $queue :shared = Thread::Queue->new(); +my $main_thread; + + +### GENERATORS ######################################################## + +# Enqueue error pages in the mirror sub genErrors(;$) { my $m = shift // Mirror->new(); @@ -43,6 +65,7 @@ sub genErrors(;$) return $m; } +# Enqueue public pages in the mirror sub genHome(;$) { my $m = shift // Mirror->new(); @@ -54,6 +77,7 @@ sub genHome(;$) return $m; } +# Enqueue all teams in the mirror sub genFull(;$) { my $m = shift // Mirror->new(); @@ -62,6 +86,7 @@ sub genFull(;$) return $m; } +# Enqueue a team in the mirror sub genTeam($;$) { my $team_id = shift; @@ -72,6 +97,7 @@ sub genTeam($;$) return $m; } +# Enqueue theme pages for a given team in the mirror sub genTeamTheme($$;$) { my $team_id = shift; @@ -84,9 +110,9 @@ sub genTeamTheme($$;$) } -my $queue :shared = Thread::Queue->new(); -my $main_thread; +### TOOLS ############################################################# +# Manage the mirror sub manage { my $m = shift // Mirror->new(); @@ -187,6 +213,7 @@ sub manage } } +# Perform a synchronization of the temporary mirrored directory sub sync { if (shift) @@ -261,6 +288,7 @@ sub sync } } +# Parse input command and enqueue them sub parse($$;$) { my $m = shift; @@ -298,19 +326,9 @@ sub parse($$;$) } -# Parse arguments -my $help; my $deamon; my $socket; -GetOptions ("threads|thread|t=i" => \$threads, - "baseadmin|ba=s" => \$baseadmin, - "basehome|bh=s" => \$basehome, - "baseteams|bt=s" => \$baseteams, - "outdir|out|o=s" => \$outdir, - "deamon|d" => \$deamon, - "socket|s=s" => \$socket, - "help|h|?" => \$help); - -$outdir = abs_path($outdir); +### SOCKETS ########################################################### +# Create the socket and wait for connection sub create_socket { my $m = shift; @@ -332,6 +350,7 @@ sub create_socket } } +# Manage the socket connection sub socket_run { my $m = shift; @@ -348,6 +367,24 @@ sub socket_run close $connection; } + +### MAIN ################################################################ + +# Parse arguments +my $help; +GetOptions ("threads|thread|t=i" => \$threads, + "baseadmin|ba=s" => \$baseadmin, + "basehome|bh=s" => \$basehome, + "baseerrors|be=s" => \$baseerrors, + "baseteams|bt=s" => \$baseteams, + "outdir|out|o=s" => \$outdir, + "deamon|d" => \$deamon, + "socket|s=s" => \$socket, + "help|h|?" => \$help); + +$outdir = abs_path($outdir); + +# Daemon mode: run forever until stdin is open if ($deamon) { my $m :shared = Mirror->new(); @@ -365,6 +402,8 @@ if ($deamon) parse($m, "J"); $main_thread->join(); } + +# Run given commands elsif (@ARGV) { my $m :shared = Mirror->new(); @@ -380,6 +419,8 @@ elsif (@ARGV) parse($m, "J"); $main_thread->join(); } + +# Just performs a full generation else { my $m = genFull(); @@ -390,11 +431,14 @@ else sync(1); } +# Clean tmp remove_tree($main::tmpdir); package Mirror; +# Structure to store a mirror state of a website + use v5.10.1; use strict; use warnings; @@ -403,6 +447,7 @@ use threads::shared; use Thread::Queue; +# Initialize the class sub new($) { my $class = shift; @@ -418,6 +463,7 @@ sub new($) return $self; } +# Launch threads and do more initialization sub start($) { my $self = shift; @@ -434,6 +480,7 @@ sub start($) } } +# Enqueue a RESET sub reset($) { my $self = shift; @@ -441,6 +488,7 @@ sub reset($) $self->{add}->enqueue("#RESET"); } +# Clean queues and wait for stop threads sub end($) { my $self = shift; @@ -470,6 +518,7 @@ sub stop($) return $self->end(); } +# Enqueue URLs sub add_url($@) { my $self = shift; @@ -480,6 +529,7 @@ sub add_url($@) } } +# Function executed to prepare URL to fetch sub run_add { my $self = shift; @@ -520,6 +570,7 @@ sub run_add } } +# Main function to fetch pages sub run { my $self = shift; @@ -563,6 +614,7 @@ sub run } } +# Join sub join($) { my $self = shift; @@ -582,6 +634,8 @@ sub join($) package FicPage; +# Represent a web page in order to perform some treatment on it + use v5.10.1; use strict; use warnings; @@ -591,6 +645,7 @@ use File::Path qw(make_path); use HTTP::Request::Common qw(GET POST); use LWP::UserAgent; +# Initialize the class sub new { my $class = shift; @@ -603,6 +658,18 @@ sub new return $self; } +# Fetch the page content +sub fetch($) +{ + my $self = shift; + my $ua = LWP::UserAgent->new; + + my $res = $ua->request(GET $self->{url}); + + $self->{content} = $res->content; +} + +# If the URL store is a short one, try to expand it by looking to correct URL sub toRightURL($) { my $self = shift; @@ -625,6 +692,7 @@ sub toRightURL($) return $self->{url}; } +# Retrieve all links in the page content sub getLinks($) { my $self = shift; @@ -632,6 +700,7 @@ sub getLinks($) return $self->{content} =~ /(?:src|href|action)="([^"]+)"/g; } +# Search relative (and absolute linking to the site part) links sub getNearLinks($) { my $self = shift; @@ -655,6 +724,7 @@ sub getNearLinks($) } } +# Remove SALT base from URL contained in the page sub treatLinks($) { my $self = shift; @@ -662,24 +732,7 @@ sub treatLinks($) $self->{content} =~ s!(src|href|action)="( \Q$baseteams\E[^/]+/ | \Q$baseadmin\E | \Q$basehome\E)([^"]*)"!$1="/$3"!gx; } -sub fetch($) -{ - my $self = shift; - my $ua = LWP::UserAgent->new; - - my $res = $ua->request(GET $self->{url}); - - $self->{content} = $res->content; -} - -sub alreadySaved($;$) -{ - my $self = shift; - - my $path = $self->getSavePath(@_); - return -f $path || ( -d $path && -f "$path/index.html" ); -} - +# Generate the path where saved the page content sub getSavePath($;$) { my $self = shift; @@ -692,6 +745,16 @@ sub getSavePath($;$) return "$basedir$path"; } +# Is the page already saved? +sub alreadySaved($;$) +{ + my $self = shift; + + my $path = $self->getSavePath(@_); + return -f $path || ( -d $path && -f "$path/index.html" ); +} + +# Really save the page content sub save($;$) { my $self = shift; @@ -724,3 +787,134 @@ sub save($;$) }; print $@ if ($@); } + +__END__ + +=head1 NAME + +Dave Null - The netiquette's guardian angel + +=head1 USAGE + + ./gen_site.pl [OPTIONS] [COMMANDS] + +=head1 DESCRIPTION + +TODO + +=head1 OPTIONS + +=over + +=item B<-baseadmin=string> + +Called SALT_ADMIN in PHP part. Default: C + +=item B<-baseerrors=string> + +There is no equivalent in PHP part, it's harcoded. Default: C + +=item B<-basehome=string> + +Called SALT_PUBLIC in PHP part. Default: C + +=item B<-baseteams=string> + +Called SALT_USER in PHP part. Default: C + +=item B<-deamon> + +Run forever (until JOIN scheduler instruction occurs). + +=item B<-help> + +Displays the help. + +=item B<-outdir=path> + +Path where save generated pages + +=item B<-socket=path> + +Path to the socket to create. + +=item B<-threads=int> + +Number of parallel fetch to perform. + +=back + +=head1 SCHEDULER COMMANDS + +=over + +=item B + +Generate pages for all teams. + +=item B + +Generate pages for the public part. + +=item B + +Generate errors pages. + +=item B + +Generate all pages for the team C<00>. + +=item B + +Generate pages for the C<11> theme for the team C<00>. + +=item B + + + +=item B + +Made a full synchronization of the output directory (remove existing output dir +and replace it by the current temporary content and reset temporary content). + +=item B + +Made a incremental synchronization with the output directory (just copy all +files in the current temporary content to the output dir, don't remove +anything). + +=item B + +Perform a C in the temporary directory content. + +=item B + +Flush the scheduler queue and + +=item B + +Display some help. + +=back + +=head1 DEPENDENCIES + +=over + +=item + +perl >= 5.10.1, compilated with threads support + +=item + +HTTP::Request::Common + +=back + +=head1 AUTHOR + +Pierre-Olivier Mercier + +=head1 LICENSE AND COPYRIGHT + +Copyright (c) 2014 Pierre-Olivier Mercier From 11c27ef2e70272119c0e0384d6b17635808239c0 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 17:16:51 +0100 Subject: [PATCH 0246/2585] Use color in terminal, HTML tag elsewhere --- misc/CA.sh | 71 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index bfc99b5e..5ed1e97b 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh if [[ -z "${TOP_DIR}" ]]; then TOP_DIR=pki @@ -14,15 +14,22 @@ CACERT=./cacert.crt DAYS=2 -#GREEN="\033[1;32m" -#RED="\033[1;31m" -#COLOR_RST="\033[0m" - -GREEN="" -RED="" -COLOR_RST="" -BOLD="" -END_BOLD="" +if [ -z "$PS1" ] +then + GREEN="" + RED="" + COLOR_RST="" + BOLD="" + END_BOLD="" + ECHO_OPTS="" +else + GREEN="\033[1;32m" + RED="\033[1;31m" + COLOR_RST="\033[0m" + BOLD="" + END_BOLD="" + ECHO_OPTS="-e" +fi usage() { @@ -52,8 +59,8 @@ OUTPUT=$(mktemp) case $1 in "-newca" ) - echo -e -n "${GREEN}Create the directories, take care this will delete" - echo -e "the old directories ${COLOR_RST}" + echo -n $ECHO_OPTS "${GREEN}Create the directories, take care this will delete" + echo $ECHO_OPTS "the old directories ${COLOR_RST}" # sleep 1; echo -n "1 "; sleep 1; echo -n "2 "; sleep 1; echo "3" clean "ca" @@ -61,7 +68,7 @@ case $1 in ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') - echo -e "${GREEN}Making CA key and csr${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Making CA key and csr${COLOR_RST}" sed -i 's/=.*#COMMONNAME/= FIC CA #COMMONNAME/' $OPENSSL_CONF sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF @@ -90,7 +97,7 @@ case $1 in exit 4 fi - echo -e "${GREEN}Self signes the CA certificate${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Self signes the CA certificate${COLOR_RST}" openssl ca -batch -create_serial -out ${TOP_DIR}/${CACERT} \ -days ${DAYS} -keyfile ${TOP_DIR}/private/${CAKEY} \ -selfsign -extensions CORE_CA -config ${OPENSSL_CONF} \ @@ -102,9 +109,9 @@ case $1 in fi ;; "-newserver" ) - echo -e "${GREEN}Making the Server key and cert${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Making the Server key and cert${COLOR_RST}" if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then - echo -e "${RED}Can not found the CA's key${COLOR_RST}" + echo $ECHO_OPTS "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi sed -i 's/=.*#COMMONNAME/=10.226.3.70#COMMONNAME/' $OPENSSL_CONF @@ -114,17 +121,17 @@ case $1 in cat $OUTPUT exit 4 fi - echo -e "${GREEN}Signing the Server crt${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Signing the Server crt${COLOR_RST}" openssl ca -policy policy_match -config ${OPENSSL_CONF} \ -out server.crt -extensions SERVER_SSL -infiles server.csr if [ $? -ne 0 ]; then - echo -e "${RED}Signing failed for new server${COLOR_RST}" + echo $ECHO_OPTS "${RED}Signing failed for new server${COLOR_RST}" rm -rf server.key server.crt server.csr cat $OUTPUT exit 3 else rm server.csr # remove ? - echo -e "${GREEN}Signed certificate is in server.crt${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Signed certificate is in server.crt${COLOR_RST}" fi ;; "-newclient" ) @@ -133,13 +140,13 @@ case $1 in exit 1 fi echo "==============================================================" - echo -e "${GREEN}Making the client key and csr of ${BOLD}${2}${END_BOLD}${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Making the client key and csr of ${BOLD}${2}${END_BOLD}${COLOR_RST}" ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then - echo -e "${RED}Can not found the CA's key${COLOR_RST}" + echo $ECHO_OPTS "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi sed -i "s/=.*#COMMONNAME/= $2#COMMONNAME/" $OPENSSL_CONF @@ -160,26 +167,26 @@ case $1 in exit 4 fi - echo -e "${GREEN}Signing the Client crt${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Signing the Client crt${COLOR_RST}" openssl ca -batch -policy policy_match -out ${TOP_DIR}/${2}.crt \ -config ${OPENSSL_CONF} -extensions CLIENT_SSL -infiles ${TOP_DIR}/${2}.csr > $OUTPUT 2>&1 if [ $? -ne 0 ]; then - echo -e "${RED}Signing failed for $2 ${COLOR_RST}" + echo $ECHO_OPTS "${RED}Signing failed for $2 ${COLOR_RST}" cat $OUTPUT clean "client" $2 exit 3 fi - echo -e "${GREEN}Export the Client files to pkcs12${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Export the Client files to pkcs12${COLOR_RST}" openssl pkcs12 -export -inkey ${TOP_DIR}/${2}.key -in ${TOP_DIR}/${2}.crt -name ${2} \ -passin pass:$pass -out ${TOP_DIR}/pkcs/${2}.p12 \ -passout pass:$pass > $OUTPUT 2>&1 if [ $? -ne 0 ]; then - echo -e "${RED}pkcs12 export failed for ${BOLD}$2${END_BOLD}${COLOR_RST}" + echo $ECHO_OPTS "${RED}pkcs12 export failed for ${BOLD}$2${END_BOLD}${COLOR_RST}" cat $OUTPUT clean "client" $2 exit 4 else - echo -e "Exported pkcs12 file is ${2}.p12" + echo $ECHO_OPTS "Exported pkcs12 file is ${2}.p12" fi mv ${TOP_DIR}/${2}.crt ${TOP_DIR}/certs echo "$2:$pass" >> ${TOP_DIR}/../teams.pass @@ -191,32 +198,32 @@ case $1 in echo "Usage: $0 -revoke NAME" exit 1 fi - echo -e "${GREEN}Revocate ${BOLD}${2}${END_BOLD}${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Revocate ${BOLD}${2}${END_BOLD}${COLOR_RST}" openssl ca -revoke ${TOP_DIR}/certs/${2}.crt -config ${OPENSSL_CONF}\ -keyfile ${TOP_DIR}/private/${CAKEY} \ -cert ${TOP_DIR}/${CACERT} > $OUTPUT 2>&1 if [ $? -ne 0 ]; then - echo -e "${RED}Revocation failed for ${BOLD}${2}${END_BOLD}${COLOR_RST}" + echo $ECHO_OPTS "${RED}Revocation failed for ${BOLD}${2}${END_BOLD}${COLOR_RST}" cat $OUTPUT exit 4 fi rm ${TOP_DIR}/certs/${2}.crt rm ${TOP_DIR}/pkcs/${2}.p12 - echo -e "${GREEN}Generate crl.pem${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Generate crl.pem${COLOR_RST}" openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 if [ $? -ne 0 ]; then - echo -e "${RED}Generate crl.pem failed" + echo $ECHO_OPTS "${RED}Generate crl.pem failed" cat $OUTPUT exit 5 fi ;; "-gencrl" ) - echo -e "${GREEN}Generate crl.pem${COLOR_RST}" + echo $ECHO_OPTS "${GREEN}Generate crl.pem${COLOR_RST}" openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 if [ $? -ne 0 ]; then - echo -e "${RED}Generate crl.pem failed" + echo $ECHO_OPTS "${RED}Generate crl.pem failed" cat $OUTPUT exit 5 fi From f7a25e0afcc166cdb54afbde3664c0f7575175b3 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 17:21:08 +0100 Subject: [PATCH 0247/2585] Update TODO --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 49e1beb4..a9e699d5 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,7 @@ - Départager les ex-æquo dans le classement - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe - Ajouter un header dans nginx avec $msec ou $time_iso8601 et calculer le timer à partir de cette valeur, au lieu de se baser sur l'horloge de l'utilisateur +- Quand est généré la CRL ? - Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) - Mettre à jour les logos From 099fdf4db14777df23879b122f62db57c87c9690 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 17:32:30 +0100 Subject: [PATCH 0248/2585] Refactor --- misc/CA.sh | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index 5ed1e97b..502915e5 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -53,6 +53,17 @@ clean() rm -rf $OUTPUT } +gen_crl() +{ + echo $ECHO_OPTS "${GREEN}Generate crl.pem${COLOR_RST}" + openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + echo $ECHO_OPTS "${RED}Generate crl.pem failed" + cat $OUTPUT + exit 5 + fi +} + [ $# -lt 1 ] && usage OUTPUT=$(mktemp) @@ -108,6 +119,7 @@ case $1 in exit 4 fi ;; + "-newserver" ) echo $ECHO_OPTS "${GREEN}Making the Server key and cert${COLOR_RST}" if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then @@ -193,6 +205,7 @@ case $1 in echo "$pass" clean "client" $2 ;; + "-revoke" ) if [ $# -ne 2 ]; then echo "Usage: $0 -revoke NAME" @@ -210,24 +223,13 @@ case $1 in rm ${TOP_DIR}/certs/${2}.crt rm ${TOP_DIR}/pkcs/${2}.p12 - echo $ECHO_OPTS "${GREEN}Generate crl.pem${COLOR_RST}" - openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then - echo $ECHO_OPTS "${RED}Generate crl.pem failed" - cat $OUTPUT - exit 5 - fi - + gen_crl ;; + "-gencrl" ) - echo $ECHO_OPTS "${GREEN}Generate crl.pem${COLOR_RST}" - openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then - echo $ECHO_OPTS "${RED}Generate crl.pem failed" - cat $OUTPUT - exit 5 - fi + gen_crl ;; + * ) usage ;; From 716e1e7ccdfac9fa681d1dc5ababc74ce914d4b9 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 17:32:46 +0100 Subject: [PATCH 0249/2585] Can revoke server certificate --- misc/CA.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/misc/CA.sh b/misc/CA.sh index 502915e5..fc5245cc 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -146,6 +146,26 @@ case $1 in echo $ECHO_OPTS "${GREEN}Signed certificate is in server.crt${COLOR_RST}" fi ;; + + "-revokeserver" ) + echo $ECHO_OPTS "${GREEN}Revocate server certificate${COLOR_RST}" + if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then + echo $ECHO_OPTS "${RED}Can not found the CA's key${COLOR_RST}" + exit 2 + fi + openssl ca -revoke server.crt -config ${OPENSSL_CONF}\ + -keyfile ${TOP_DIR}/private/${CAKEY} \ + -cert ${TOP_DIR}/${CACERT} > $OUTPUT 2>&1 + if [ $? -ne 0 ]; then + echo $ECHO_OPTS "${RED}Server certificate revocation failed${COLOR_RST}" + cat $OUTPUT + exit 4 + fi + rm ${TOP_DIR}/server.crt ${TOP_DIR}/server.key + + gen_crl + ;; + "-newclient" ) if [ $# -ne 2 ]; then echo "Usage: $0 -newclient NAME" From 39ca8940e159a406bdee1b5409fe4bfc59e403ab Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 17:42:58 +0100 Subject: [PATCH 0250/2585] If team certificate file not found, propose to generate it --- onyx/include/common.php | 2 ++ onyx/tpl/bootstrap/admin/users.tpl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/onyx/include/common.php b/onyx/include/common.php index f21a6236..36948af9 100644 --- a/onyx/include/common.php +++ b/onyx/include/common.php @@ -22,5 +22,7 @@ if (is_file($VAR["misc_dir"]."/challenge_started")) $template->assign("END", $VAR['end_challenge']); } +if (!empty($VAR['misc_dir'])) + $template->assign("MISC_DIR", $VAR['misc_dir']); if (!empty($LANG)) $template->assign("LANG", $LANG); diff --git a/onyx/tpl/bootstrap/admin/users.tpl b/onyx/tpl/bootstrap/admin/users.tpl index 387013bb..f0ecb49c 100644 --- a/onyx/tpl/bootstrap/admin/users.tpl +++ b/onyx/tpl/bootstrap/admin/users.tpl @@ -23,7 +23,7 @@ - {if not $t->revoked} + {if not $t->revoked && is_file("{$MISC_DIR}/pki/pkcs/{$t->team_name}.p12")} From 4d1424b29b935bebe24c107823a46fa39e0c80db Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 18:04:39 +0100 Subject: [PATCH 0251/2585] Can revoke/generate server certiticate in admin interface --- htdocs/index.php | 4 ++ misc/CA.sh | 26 ++++++----- onyx/include/admin/certificate.php | 50 +++++++++++++++------ onyx/include/admin/home.php | 20 ++++++--- onyx/tpl/bootstrap/admin/home.tpl | 70 ++++++++++++++++++++---------- onyx/tpl/bootstrap/admin/shell.tpl | 7 +++ 6 files changed, 122 insertions(+), 55 deletions(-) create mode 100644 onyx/tpl/bootstrap/admin/shell.tpl diff --git a/htdocs/index.php b/htdocs/index.php index c0ed32bb..7b582646 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -61,12 +61,16 @@ if ($n && $p[0] == SALT_ADMIN) case "certificate/": case "certificate/newca": case "certificate/newca/": + case "certificate/newsrv": + case "certificate/newsrv/": case "certificate/newclient": case "certificate/newclient/": case "certificate/deleteca": case "certificate/deleteca/": case "certificate/revoke": case "certificate/revoke/": + case "certificate/revokesrv": + case "certificate/revokesrv/": case "certificate/get": case "certificate/get/": $page = require("admin/certificate.php"); diff --git a/misc/CA.sh b/misc/CA.sh index fc5245cc..45fd2f7f 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -1,10 +1,12 @@ #!/bin/sh -if [[ -z "${TOP_DIR}" ]]; then +cd $(dirname "$0") + +if [ -z "${TOP_DIR}" ]; then TOP_DIR=pki fi -if [[ -z "${OPENSSL_CONF}" ]]; then +if [ -z "${OPENSSL_CONF}" ]; then OPENSSL_CONF=openssl.cnf fi @@ -16,24 +18,24 @@ DAYS=2 if [ -z "$PS1" ] then - GREEN="" - RED="" - COLOR_RST="" - BOLD="" - END_BOLD="" - ECHO_OPTS="" -else GREEN="\033[1;32m" RED="\033[1;31m" COLOR_RST="\033[0m" BOLD="" END_BOLD="" ECHO_OPTS="-e" +else + GREEN="" + RED="" + COLOR_RST="" + BOLD="" + END_BOLD="" + ECHO_OPTS="" fi usage() { - echo "Usage: $0 (-newca|-newserver|-newclient NAME|-revoke NAME|-gencrl)" + echo "Usage: $0 (-newca|-newserver|-revokeserver|-newclient NAME|-revoke NAME|-gencrl)" exit 1 } @@ -71,7 +73,7 @@ OUTPUT=$(mktemp) case $1 in "-newca" ) echo -n $ECHO_OPTS "${GREEN}Create the directories, take care this will delete" - echo $ECHO_OPTS "the old directories ${COLOR_RST}" + echo $ECHO_OPTS " the old directories ${COLOR_RST}" # sleep 1; echo -n "1 "; sleep 1; echo -n "2 "; sleep 1; echo "3" clean "ca" @@ -161,7 +163,7 @@ case $1 in cat $OUTPUT exit 4 fi - rm ${TOP_DIR}/server.crt ${TOP_DIR}/server.key + rm server.crt server.key gen_crl ;; diff --git a/onyx/include/admin/certificate.php b/onyx/include/admin/certificate.php index 5698f903..a26cf585 100644 --- a/onyx/include/admin/certificate.php +++ b/onyx/include/admin/certificate.php @@ -27,22 +27,19 @@ function new_client($name, $misc_dir) //TODO handle if already exist putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); putenv("TOP_DIR=$misc_dir/pki"); - $output = shell_exec("$misc_dir/CA.sh -newclient $name"); - return $output; + return shell_exec("$misc_dir/CA.sh -newclient $name"); } function revoke_client($name, $misc_dir) { putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); putenv("TOP_DIR=$misc_dir/pki"); - $output = shell_exec("$misc_dir/CA.sh -revoke $name"); + return shell_exec("$misc_dir/CA.sh -revoke $name"); } if (!empty($p[2])) { - if (isset($VAR['misc_dir'])) - $misc_dir = $VAR['misc_dir']; - else + if (empty($VAR['misc_dir'])) { erreur("Merci d'ajouter la variable misc_dir dans root.xml"); return "admin/home"; @@ -54,7 +51,9 @@ if (!empty($p[2])) { putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); putenv("TOP_DIR=$misc_dir/pki"); - $output = shell_exec("$misc_dir/CA.sh -newca"); + $template->assign("output", + shell_exec("$misc_dir/CA.sh -newca")); + return "admin/shell"; } elseif ($p[2] == "deleteca") @@ -62,16 +61,38 @@ if (!empty($p[2])) $dir = "$misc_dir/pki"; remove_directory($dir); } + + elseif ($p[2] == "newsrv") + { + putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); + putenv("TOP_DIR=$misc_dir/pki"); + $template->assign("output", + shell_exec("$misc_dir/CA.sh -newserver")); + return "admin/shell"; + } + + elseif ($p[2] == "revokesrv") + { + putenv("OPENSSL_CONF=$misc_dir/openssl.cnf"); + putenv("TOP_DIR=$misc_dir/pki"); + $template->assign("output", + shell_exec("$misc_dir/CA.sh -revokeserver")); + return "admin/shell"; + } + elseif ($p[2] == "revoke") { $name = $_GET['name']; if (isset($name)) { - $output = revoke_client($name, $misc_dir); + $template->assign("output", + revoke_client($name, $misc_dir)); //TODO Check revocation failed Team::set_revoked(TRUE, $name); } + return "admin/shell"; } + // Is new team elseif ($p[2] == "newclient") { @@ -80,12 +101,13 @@ if (!empty($p[2])) //TODO check revoked attribute if (isset($name)) { - $output = new_client($name, $misc_dir); + $template->assign("output", + new_client($name, $misc_dir)); Team::set_revoked(FALSE, $name); - erreur($output, "sucess"); - return "admin/import_users"; + return "admin/shell"; } } + elseif ($p[2] == "get") { $name = $_GET['name']; @@ -95,14 +117,15 @@ if (!empty($p[2])) if (file_exists($path) && is_readable($path)) { header("Content-Type: application/force-download"); - header("Content-Length: ".strval(filesize($path))); + header("Content-Length: ".filesize($path)); header("Content-Disposition: attachment; filename=\"$name.p12\""); readfile($path); + exit; } } - exit; } + if ($p[2] == "deleteca" || $p[2] == "newca") { header("Location: /".SALT_ADMIN."/"); @@ -114,4 +137,3 @@ if (!empty($p[2])) exit; } } - diff --git a/onyx/include/admin/home.php b/onyx/include/admin/home.php index 6268084f..2297635a 100644 --- a/onyx/include/admin/home.php +++ b/onyx/include/admin/home.php @@ -20,20 +20,26 @@ else if (is_writable($misc_dir) && !is_dir("$misc_dir/pki/")) mkdir("$misc_dir/pki/"); -$wright = is_writable("$misc_dir/pki/"); -$template->assign("cert_writable", $wright); +$template->assign("cert_writable", is_writable("$misc_dir/pki/")); $ca_file = "$misc_dir/pki/cacert.crt"; - if (file_exists($ca_file)) { if (!is_readable($ca_file)) erreur("Impossible de lire le fichier"); else - { - $data = openssl_x509_parse(file_get_contents(ONYX . '../misc/pki/cacert.crt')); - $template->assign("cert", $data); - } + $template->assign("cert_CA", + openssl_x509_parse(file_get_contents($ca_file))); +} + +$srv_file = "$misc_dir/server.crt"; +if (file_exists($srv_file)) +{ + if (!is_readable($srv_file)) + erreur("Impossible de lire le fichier"); + else + $template->assign("cert_srv", + openssl_x509_parse(file_get_contents($srv_file))); } return "admin/home"; diff --git a/onyx/tpl/bootstrap/admin/home.tpl b/onyx/tpl/bootstrap/admin/home.tpl index 885c26fe..71cb39bc 100644 --- a/onyx/tpl/bootstrap/admin/home.tpl +++ b/onyx/tpl/bootstrap/admin/home.tpl @@ -1,29 +1,55 @@ {extends file="admin/layout.tpl"} {block name=content} -
    -
    -

    Certificat racine

    +
    +
    +
    +
    +

    Certificat racine

    +
    +
    + {if isset($cert_CA)} +
      + {foreach from=$cert_CA.subject key=k item=crt} +
    • [{$k}] : {$crt}
    • + {/foreach} +
    + Supprimer + {elseif ! $cert_writable} +
    Répertoire non accessible en écriture.
    + Nouveau + {else} + Pas de certificat + Nouveau + {/if} +
    +
    -
    - {if isset($cert)} -
      -
    • [C] : {$cert['subject']['C']}
    • -
    • [ST] : {$cert['subject']['ST']}
    • -
    • [O] : {$cert['subject']['O']}
    • -
    • [OU] : {$cert['subject']['OU']}
    • -
    • [CN] : {$cert['subject']['CN']}
    • -
    • [emailAddress] : {$cert['subject']['emailAddress']}
    • -
    - - {elseif isset($cert_writable) && ! $cert_writable} -
    Répertoire non accessible en écriture.
    - - {else} - Pas de certificat - - {/if} + +
    +
    +
    +

    Certificat serveur

    +
    +
    + {if isset($cert_srv)} +
      + {foreach from=$cert_srv.subject key=k item=crt} +
    • [{$k}] : {$crt}
    • + {/foreach} +
    + Supprimer + {elseif ! $cert_writable} +
    Répertoire non accessible en écriture.
    + Nouveau + {else} + Pas de certificat + Nouveau + {/if} +
    +
    diff --git a/onyx/tpl/bootstrap/admin/shell.tpl b/onyx/tpl/bootstrap/admin/shell.tpl new file mode 100644 index 00000000..cc6c0dc9 --- /dev/null +++ b/onyx/tpl/bootstrap/admin/shell.tpl @@ -0,0 +1,7 @@ +{extends file="admin/layout.tpl"} + +{block name=content} +
    +{$output}
    +
    +{/block} From b02c823f9e74c3840c4dfb620402c0ff106aa516 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 20:29:01 +0100 Subject: [PATCH 0252/2585] Few more dependencies --- Dockerfile | 2 ++ README.md | 4 +++- TODO | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 00fe2e20..80617e9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,7 @@ MAINTAINER Pierre-Olivier Mercier RUN apt-get -y update && \ apt-get install -y \ + realpath \ nginx-light \ php5-fpm \ mysql-server \ @@ -16,6 +17,7 @@ RUN apt-get -y update && \ php5-mcrypt \ libmcrypt-dev \ libwww-perl \ + libdigest-whirlpool-perl \ pwgen \ openssl \ && \ diff --git a/README.md b/README.md index 821cd00b..d8afcc29 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,14 @@ CONNTRACK states. ##### Requirements +* `realpath`; * `mysql`; * `nginx` with `fastcgi` module; * `php-fpm` with `mysql` module; * `openssl` and `pwgen` for client certificat generation; * `mcrypt`; -* `HTTP::Request::Common` perl module; +* `HTTP::Request::Common` perl module (provided by `libwww-perl`); +* `Digest::Whirlpool` perl module (provided by `lib-digest-whirlpool-perl`); * `Mcrypt` from CPAN (`cpan -i Mcrypt`, on Debian, it requires `libtool` and `build-essential`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); diff --git a/TODO b/TODO index a9e699d5..667bda0b 100644 --- a/TODO +++ b/TODO @@ -7,3 +7,4 @@ - Mettre à jour les logos - versionner la DTD et la doc associée - valider les documents avec la DTD à l'import +- Lors de l'import des XML, retirer l'éventuel / en début de path From 89c2c4a2dcf2d1d8cee47d3fda1e70eefcb7297a Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 21:02:29 +0100 Subject: [PATCH 0253/2585] Fix bad query when checking for already solved exercice --- check.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check.pl b/check.pl index 92fd49ab..ae3c615d 100755 --- a/check.pl +++ b/check.pl @@ -187,7 +187,7 @@ for my $f (readdir $dh) if (! @$row[0] || $sth->rows) { # Check if the team has not already solved this exercice - $sth = query($dbh, "SELECT S.id FROM solved S WHERE S.id_exercice = ".$dbh->quote($exercice)); + $sth = query($dbh, "SELECT S.id FROM solved S WHERE S.id_team = $team AND S.id_exercice = ".$dbh->quote($exercice)); if (! $sth->rows) { say "resetresetreset:TEAM$team,$theme:SYNCSYN:TEAM$team:SYNC:HOME:SYNC:all:DS"; From 5e89d9d31e945ecd3d21dddf9a5cf7a3151a6736 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 21:03:35 +0100 Subject: [PATCH 0254/2585] Use bash for Debian compat --- README.md | 2 +- backup.sh | 2 +- clear_cache.sh | 2 +- gen_site.sh | 2 +- launch.sh | 4 +++- launch_local.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ synchro.sh | 2 +- 7 files changed, 50 insertions(+), 6 deletions(-) create mode 100755 launch_local.sh diff --git a/README.md b/README.md index d8afcc29..cf6efbea 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ CONNTRACK states. * `mcrypt`; * `HTTP::Request::Common` perl module (provided by `libwww-perl`); * `Digest::Whirlpool` perl module (provided by `lib-digest-whirlpool-perl`); -* `Mcrypt` from CPAN (`cpan -i Mcrypt`, on Debian, it requires `libtool` and +* `Mcrypt` from CPAN (`cpan -i Mcrypt`, on Debian, it requires `libltdl-dev` and `build-essential`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); diff --git a/backup.sh b/backup.sh index 6b23f068..bfdfdee3 100755 --- a/backup.sh +++ b/backup.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This script mades backup of important things diff --git a/clear_cache.sh b/clear_cache.sh index 5d3d5c2f..024aaf5e 100755 --- a/clear_cache.sh +++ b/clear_cache.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This script deletes Onyx framework cache diff --git a/gen_site.sh b/gen_site.sh index 6ef98771..4fa11caf 100755 --- a/gen_site.sh +++ b/gen_site.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash BASEURL="localhost" SALT_TEAM="connected" diff --git a/launch.sh b/launch.sh index ed33db08..bf5f15ef 100755 --- a/launch.sh +++ b/launch.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This script does all actions in backend production environment @@ -14,6 +14,8 @@ then exit $? fi +mkdir -p ./logs + touch ./logs/checks.log tail -f ./logs/checks.log & KP1=$! diff --git a/launch_local.sh b/launch_local.sh new file mode 100755 index 00000000..b86be2c2 --- /dev/null +++ b/launch_local.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# This script does all actions in backend local environment + +rm -f /tmp/stop +cd `dirname "$0"` + +source config.sh + +#if [ "$UID" = "0" ] +#then +# SCRIPT=`pwd`/`basename "$0"` +# su -c "sh $SCRIPT" "$SYNCHRO_USER" +# exit $? +#fi + +mkdir -p ./logs + +touch ./logs/checks.log +tail -f ./logs/checks.log & +KP1=$! + +TMPF=`mktemp` + +tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -bt /challenge/ -ba /challenge-admin/ -o ./out & +KP2=$! + +while ! [ -f /tmp/stop ]; +do + if [ `ls submission | wc -l` -gt 1 ] + then + ./clear_cache.sh top + ./check.pl 2>> ./logs/checks.log >> "$TMPF" + + else + sleep 1 + fi +done + +kill -9 $KP1 $KP2 + +rm -rf "$TMPF" diff --git a/synchro.sh b/synchro.sh index e6f81ce7..8cebbb6d 100755 --- a/synchro.sh +++ b/synchro.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This script synchronizes first, the generated frontend and then # retrieves submissions From e6acdbd68ad950e2036d0c1777fb92f59680c4f4 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 21:56:17 +0100 Subject: [PATCH 0255/2585] Clear theme cache after its edition in admin part --- onyx/include/admin/exercice.php | 1 + 1 file changed, 1 insertion(+) diff --git a/onyx/include/admin/exercice.php b/onyx/include/admin/exercice.php index b007d591..1259b9f5 100644 --- a/onyx/include/admin/exercice.php +++ b/onyx/include/admin/exercice.php @@ -45,6 +45,7 @@ try } $exercice->update(); + Cache::del("ordered_th".$exercice->theme->get_id()); header("Location: /".implode("/", $p)); exit(); } From bbd82406f907d663f640573c88fe92a42e7dbb31 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 21:56:37 +0100 Subject: [PATCH 0256/2585] Optimize exercice numbering --- onyx/include/common/Exercice.class.php | 36 ++++++++++++++------------ 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/onyx/include/common/Exercice.class.php b/onyx/include/common/Exercice.class.php index ad6a8b24..eef3827b 100644 --- a/onyx/include/common/Exercice.class.php +++ b/onyx/include/common/Exercice.class.php @@ -178,26 +178,28 @@ class Exercice { if ($this->require == "") $this->number = 1; - - $db = new BDD(); - - $exo = $this->id; - $ret = 0; - - $checked = array(); - - do + else { - array_push($checked, $exo); - $db->escape($exo); - $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = '".$exo."'"); - $exo = $res['require']; - $ret++; - } while ($exo != "" && !in_array($exo, $checked)); + $db = new BDD(); - $this->number = $ret; + $exo = $this->id; + $ret = 0; - $db->deconnexion(); + $checked = array(); + + do + { + array_push($checked, $exo); + $db->escape($exo); + $res = $db->unique_query("SELECT `require` FROM exercices WHERE id = '".$exo."'"); + $exo = $res['require']; + $ret++; + } while ($exo != "" && !in_array($exo, $checked)); + + $this->number = $ret; + + $db->deconnexion(); + } } function update($create=false) From 8e7273fa88aa93de27846d368162bdd012256e4d Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 22:10:25 +0100 Subject: [PATCH 0257/2585] In deamon mode, argument on CLI are executed first --- gen_site.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gen_site.pl b/gen_site.pl index 17928f21..8914b597 100755 --- a/gen_site.pl +++ b/gen_site.pl @@ -393,6 +393,10 @@ if ($deamon) threads->create(\&create_socket, $m, $socket) if ($socket); + while ($_ = shift) { + parse($m, $_); + } + while(<>) { chomp $_; From 6012021caf301fba54e9252ab1a733aea306d6f2 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 22:16:00 +0100 Subject: [PATCH 0258/2585] Generate pages on launch --- Dockerfile | 4 ++-- gen_hash_link_files.sh | 6 ++++++ launch.sh | 2 +- launch_local.sh | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 80617e9b..499f826b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,7 +41,7 @@ RUN cd /var/www/fic-server/misc; bash ./CA.sh -newca RUN service mysql start && echo "CREATE DATABASE fic;" | mysql -u root && cat /var/www/fic-server/db/fic2014.sql | mysql -u root fic # Uncomment the following line to fill with random values -#RUN cat /var/www/fic-server/db/feed.sql | mysql -u root fic +#RUN service mysql start && cat /var/www/fic-server/db/feed.sql | mysql -u root fic # Configure site ###################################################### @@ -54,4 +54,4 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem # ENVIRONNEMENT ####################################################### EXPOSE 80/tcp 443/tcp -CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && /bin/bash"] +CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && mkdir files && ./gen_hash_link_files.sh files-in files && ./launch_local.sh & /bin/bash"] diff --git a/gen_hash_link_files.sh b/gen_hash_link_files.sh index 2cb4873a..a189a623 100755 --- a/gen_hash_link_files.sh +++ b/gen_hash_link_files.sh @@ -1,5 +1,11 @@ #!/bin/bash +if [ $# -lt 2 ] +then + echo "Usage: $0 from to" + exit 1 +fi + FROM=`realpath $1`; shift TO=`realpath $1`; shift diff --git a/launch.sh b/launch.sh index bf5f15ef..aabe646f 100755 --- a/launch.sh +++ b/launch.sh @@ -22,7 +22,7 @@ KP1=$! TMPF=`mktemp` -tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -o ./out & +tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -o ./out ERRORS HOME all DS & KP2=$! while ! [ -f /tmp/stop ]; diff --git a/launch_local.sh b/launch_local.sh index b86be2c2..d4850c12 100755 --- a/launch_local.sh +++ b/launch_local.sh @@ -22,7 +22,7 @@ KP1=$! TMPF=`mktemp` -tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -bt /challenge/ -ba /challenge-admin/ -o ./out & +tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -bt /challenge/ -ba /challenge-admin/ -o ./out ERRORS HOME all DS & KP2=$! while ! [ -f /tmp/stop ]; From cc02495886d2b04a82e19aa601ebbc13f392db14 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 22:54:42 +0100 Subject: [PATCH 0259/2585] Setup volume to share with others containers --- Dockerfile | 3 ++- TODO | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 499f826b..3cd4a660 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,4 +54,5 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem # ENVIRONNEMENT ####################################################### EXPOSE 80/tcp 443/tcp -CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && mkdir files && ./gen_hash_link_files.sh files-in files && ./launch_local.sh & /bin/bash"] +VOLUME ["/var/www/fic-server/out","/var/www/fic-server/files","/var/www/fic-server/submissions"] +CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && mkdir files && ../gen_hash_link_files.sh ../files-in ../files && (../launch_local.sh &); /bin/bash"] diff --git a/TODO b/TODO index 667bda0b..4471d2db 100644 --- a/TODO +++ b/TODO @@ -8,3 +8,4 @@ - versionner la DTD et la doc associée - valider les documents avec la DTD à l'import - Lors de l'import des XML, retirer l'éventuel / en début de path +- Dockerfile de simulation de frontend From e89582bec4806d25c701cc49ae9e36259bb5d5ed Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 22:55:31 +0100 Subject: [PATCH 0260/2585] Avoid removing root tree directory --- gen_hash_link_files.sh | 2 +- gen_site.pl | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gen_hash_link_files.sh b/gen_hash_link_files.sh index a189a623..1711fe60 100755 --- a/gen_hash_link_files.sh +++ b/gen_hash_link_files.sh @@ -20,7 +20,7 @@ then fi mkdir -p "$TO" || exit 3 -rm -rf "$TO" || exit 3 +rm -rf "$TO/*" || exit 3 for i in `find "$FROM" -mindepth 1 -type f` do diff --git a/gen_site.pl b/gen_site.pl index 8914b597..45175a4c 100755 --- a/gen_site.pl +++ b/gen_site.pl @@ -250,8 +250,7 @@ sub sync abs_path($main::outdir); abs_path($tmpcopy); - remove_tree($main::outdir); - mkdir($main::outdir); + remove_tree($main::outdir, {keep_root => 1}); system("mv '$tmpcopy'/* '$main::outdir/'"); } From f884d42e30c617d1399cd1d9172ae176974d0603 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 23:00:00 +0100 Subject: [PATCH 0261/2585] Updating TODO --- TODO | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODO b/TODO index 4471d2db..2d7c5a11 100644 --- a/TODO +++ b/TODO @@ -9,3 +9,5 @@ - valider les documents avec la DTD à l'import - Lors de l'import des XML, retirer l'éventuel / en début de path - Dockerfile de simulation de frontend +- Au moment du lancement du chrono, ouvrir la socket de communication avec le scheduler et lui ajouter la directive all:S pour regénérer toutes les équipes +- On peut encore soumettre après la fin... From 65edeb149dc729a1657d9251a606852fc05755c5 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 20 Nov 2014 23:09:05 +0100 Subject: [PATCH 0262/2585] Install Mcrypt through cpanm --- Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Dockerfile b/Dockerfile index 3cd4a660..005f30cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,14 @@ RUN apt-get -y update && \ libdigest-whirlpool-perl \ pwgen \ openssl \ + cpanminus \ + build-essential \ + libltdl-dev \ && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN cpanm Mcrypt + # Copying files ####################################################### ADD . /var/www/fic-server/ From 84c3fdd8fafb636a22ea21593b2724c2ca88b2a8 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 10:20:59 +0100 Subject: [PATCH 0263/2585] Catch some SIG to kill sons --- launch.sh | 2 ++ launch_local.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/launch.sh b/launch.sh index aabe646f..f99b81e4 100755 --- a/launch.sh +++ b/launch.sh @@ -25,6 +25,8 @@ TMPF=`mktemp` tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -o ./out ERRORS HOME all DS & KP2=$! +trap "kill $KP1 $KP2; rm -rf '$TMPF'; echo" SIGINT SIGTERM + while ! [ -f /tmp/stop ]; do ./synchro.sh delete diff --git a/launch_local.sh b/launch_local.sh index d4850c12..87b5a8f1 100755 --- a/launch_local.sh +++ b/launch_local.sh @@ -25,6 +25,8 @@ TMPF=`mktemp` tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -bt /challenge/ -ba /challenge-admin/ -o ./out ERRORS HOME all DS & KP2=$! +trap "kill $KP1 $KP2; rm -rf '$TMPF'; echo" SIGINT SIGTERM + while ! [ -f /tmp/stop ]; do if [ `ls submission | wc -l` -gt 1 ] From 016d530b5783b08f3a2180418bb6871a5d67c037 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 10:24:13 +0100 Subject: [PATCH 0264/2585] Make raw copy or hardlink instead of symlink, mainly for container test usage --- Dockerfile | 2 +- gen_hash_link_files.sh | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 005f30cf..844c0529 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,4 +60,4 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem EXPOSE 80/tcp 443/tcp VOLUME ["/var/www/fic-server/out","/var/www/fic-server/files","/var/www/fic-server/submissions"] -CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && mkdir files && ../gen_hash_link_files.sh ../files-in ../files && (../launch_local.sh &); /bin/bash"] +CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && mkdir files && ../gen_hash_link_files.sh --copy ../files-in ../files && (../launch_local.sh &); /bin/bash"] diff --git a/gen_hash_link_files.sh b/gen_hash_link_files.sh index 1711fe60..5daba142 100755 --- a/gen_hash_link_files.sh +++ b/gen_hash_link_files.sh @@ -6,6 +6,18 @@ then exit 1 fi +if [ "$1" = "--hard" ] +then + LN="ln" + shift +elif [ "$1" = "--copy" ] +then + LN="cp" + shift +else + LN="ln -s" +fi + FROM=`realpath $1`; shift TO=`realpath $1`; shift @@ -28,5 +40,5 @@ do HASH=`echo -n $FILE | sha384sum | cut -d " " -f 1` mkdir -p "$TO/$HASH/" - ln -s "$i" "$TO/$HASH/" + $LN "$i" "$TO/$HASH/" done From 6c69867bcc59cdc1652da9a7b5fcdb6a843fdc73 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 12:47:10 +0100 Subject: [PATCH 0265/2585] Document backend launch --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cf6efbea..44b4a67d 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,14 @@ Use `docker ps` to view to which local ports was assigned the contained webserver. +### Database + +Demo data are available in `/var/www/fic-server/db/feed.sql`. In test +environment, you can run the following command: + + mysql -u root fic < /var/www/fic-server/db/feed.sql + + Production Environnement ------------------------ @@ -88,6 +96,18 @@ CONNTRACK states. `build-essential`) to decrypt submissions (see https://metacpan.org/pod/Mcrypt); +##### Files distribution + +You need to manually place challenge given files in the tree. To avoid path +guessing, files path are hashed. To generate hashed paths, use the script +`gen_hash_link_files.sh`: + + mkdir $TO + ./gen_hash_link_files.sh FROM TO + +Where `FROM` is the directory with the orignal tree and `TO` the directory +where placed symlink. + ##### Firewall rules This machine shouldn't have any network connection, except outgoing one to the @@ -98,14 +118,27 @@ frontend for synchronization. Indicate in `/etc/hosts.conf` IP(s) of the frontend. +### Run + +Two scripts are available, depending if directories synchronization has to be +made or not. + +You don't need to handle synchronization if it's done by a separate container +or if frontend is linked to backend. + +The `launch.sh` and `launch_local.sh` scripts do all backend stuff for you: +synchronization with frontend (only `launch.sh`), submission checking and +smart static pages regeneration. + + ### History #### FIC2014 -Two machines were used : one for backend (Deimos) and one for frontend -(Phobos). They ran a GNU/Linux Gentoo Hardened with custom 3.2 kernel without -module loading, unused and unecessary components and with all GrSecurity -features activated. +Two machines (DC7900: Core 2 Quad) were used : one for backend (Deimos) and one +for frontend (Phobos). They ran a GNU/Linux Gentoo Hardened with custom 3.2 +kernel without module loading, unused and unecessary components and with all +GrSecurity features activated. Each machine was two network interfaces: one was used to permit to the backend machine to connect to the frontend (over IPv6). The second interface on the @@ -113,8 +146,20 @@ backend was used for administration purpose (with a laptop not connected to Internet). The second interface on the frontend was used to provide network connectivity to participants. +Both frontend and backend were 2 500GB hard-drives with software RAID1. The +whole logical RAID disk was LUKS encrypted using Serpent algorithm. + The D Day --------- +### Interact with the scheduler + +When you launch `launch.sh` or `launch_local.sh` script, a socket is open at +`/tmp/test.sock`. Use `perl comm-socket.pl /tmp/test.sock` to connect to the +scheduler. Consult `gen_site.pl` manual (`perldoc gen_site.pl`) for list of +available instructions. + +### More + TODO From bca09af2e02cbed50a79e4af85c33e47bbf92411 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 15:55:38 +0100 Subject: [PATCH 0266/2585] Add a Dockerfile for frontend test container; adapt code to simplify synchronization or Docker linkage --- Dockerfile | 5 +- README.md | 8 ++ front/Dockerfile | 30 +++++ front/nginx.conf | 108 ++++++++++++++++++ front/php-fpm.conf | 81 ++++++++++++++ submission.php => front/submission.php | 6 +- misc/CA.sh | 145 ++++++++++++++----------- misc/openssl.cnf | 4 +- nginx-server.conf | 11 +- nginx.conf | 131 ---------------------- nginx_gen_team.sh | 4 +- onyx/include/admin/home.php | 4 +- onyx/include/admin/import_users.php | 2 +- onyx/include/team/exercice.php | 2 +- synchro.sh | 6 +- 15 files changed, 329 insertions(+), 218 deletions(-) create mode 100644 front/Dockerfile create mode 100644 front/nginx.conf create mode 100644 front/php-fpm.conf rename submission.php => front/submission.php (88%) delete mode 100644 nginx.conf mode change 100644 => 100755 nginx_gen_team.sh diff --git a/Dockerfile b/Dockerfile index 844c0529..ab173c72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get -y update && \ libwww-perl \ libdigest-whirlpool-perl \ pwgen \ + curl \ openssl \ cpanminus \ build-essential \ @@ -59,5 +60,5 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem # ENVIRONNEMENT ####################################################### EXPOSE 80/tcp 443/tcp -VOLUME ["/var/www/fic-server/out","/var/www/fic-server/files","/var/www/fic-server/submissions"] -CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; service nginx start && service php5-fpm start && service mysql start && mkdir files && ../gen_hash_link_files.sh --copy ../files-in ../files && (../launch_local.sh &); /bin/bash"] +VOLUME ["/var/www/fic-server/out","/var/www/fic-server/files","/var/www/fic-server/submission","/var/www/fic-server/misc/shared"] +CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then ./CA.sh -newserver; fi; ./CA.sh -gencrl && service nginx start && service php5-fpm start && service mysql start && ../gen_hash_link_files.sh --copy ../files-in ../files && ../nginx_gen_team.sh > ../misc/shared/nginx-teams.conf && (../launch_local.sh &); /bin/bash"] diff --git a/README.md b/README.md index 44b4a67d..f82ac010 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,14 @@ environment, you can run the following command: mysql -u root fic < /var/www/fic-server/db/feed.sql +### Frontend container + +To run the frontend on the same machine as the backend (but in another +container), run the following command: + + docker run -P -ti --volumes-from BACKEND_CNTNR_NAME FRONTEND_IMG + + Production Environnement ------------------------ diff --git a/front/Dockerfile b/front/Dockerfile new file mode 100644 index 00000000..833e9d89 --- /dev/null +++ b/front/Dockerfile @@ -0,0 +1,30 @@ +# DOCKER-VERSION 1.1.0 + +# /!\ WARNING: the container generated through this Dockerfile is made only for development purpose; it is NOT SAFE or production ready. + +FROM debian:wheezy +MAINTAINER Pierre-Olivier Mercier + +# Install packages #################################################### + +RUN apt-get -y update && \ + apt-get install -y \ + nginx-full \ + php5-fpm \ + php5-mcrypt \ + && \ + apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Copying files ####################################################### + +ADD . /var/www/fic-server/front/ + +# Configure softwares ################################################# + +RUN ln -sf /var/www/fic-server/front/nginx.conf /etc/nginx/sites-enabled/default +RUN ln -sf /var/www/fic-server/front/php-fpm.conf /etc/php5/fpm/pool.d/www.conf + +# ENVIRONNEMENT ####################################################### + +EXPOSE 80/tcp 443/tcp +CMD ["sh", "-c", "service nginx start && service php5-fpm start && /bin/bash"] diff --git a/front/nginx.conf b/front/nginx.conf new file mode 100644 index 00000000..2760600e --- /dev/null +++ b/front/nginx.conf @@ -0,0 +1,108 @@ +server_tokens off; +client_header_buffer_size 512; +client_max_body_size 512; + +server { + listen 80 default; + listen [::]:80 ipv6only=on default; + + rewrite ^ https://$host$uri; +} + +server { + listen 443 ssl; + listen [::]:443 ipv6only=on ssl; + + root /var/www/fic-server/out/htdocs/; + + access_log /var/log/nginx/fic.access_log; + error_log /var/log/nginx/fic.error_log; + + ssl_certificate /var/www/fic-server/misc/shared/server.crt; + ssl_certificate_key /var/www/fic-server/misc/shared/server.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; +# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + ssl_ciphers AES256+EECDH:AES256+EDH; + ssl_client_certificate /var/www/fic-server/misc/shared/cacert.crt; + ssl_verify_client optional; + ssl_crl /var/www/fic-server/misc/shared/crl.pem; + + add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + + error_page 400 /errors/400/index.html; + error_page 403 /errors/403/index.html; + error_page 404 /errors/404/index.html; + error_page 413 414 /errors/413/index.html; + error_page 500 503 /errors/500/index.html; + error_page 502 504 /errors/502/index.html; + + location / + { + default_type text/html; + expires epoch; + + set $team 0; + + include /var/www/fic-server/misc/shared/nginx-teams.conf; + + if ($team) { + root /var/www/fic-server/out/teams/$team$1; + rewrite ^/([0-9]+-?[a-zA-Z0-9_-]*)/([a-zA-Z0-9_]+)/submission$ /submission.php?team=$team&theme=$1&exercice=$2 last; + } + if ($team = 0) { + root /var/www/fic-server/out/htdocs/; + } + } + + location /errors + { + root /var/www/fic-server/out/; + } + + location /connected + { + return 403; + } + + location /files + { + root /var/www/fic-server/; + + # option to accelerate file delivery, require a custom nginx + #aio on; + directio 512; + output_buffers 1 128k; + } + + location ~* \favicon.ico$ { + root /var/www/fic-server/out/htdocs/; + access_log off; + expires 1d; + add_header Cache-Control public; + } + + location ~ ^/(assets|img|js|css|fonts)/ { + root /var/www/fic-server/out/htdocs/; + access_log off; + expires 7d; + add_header Cache-Control public; + } + + location ~ /(\.ht|\.git|\.svn|\.onyx) { + return 403; + } + + location /submission.php + { + root /var/www/fic-server/front/; + + limit_rate 4k; + + include /etc/nginx/fastcgi_params; + fastcgi_pass unix:/var/run/php-fpm.sock; + break; + } +} diff --git a/front/php-fpm.conf b/front/php-fpm.conf new file mode 100644 index 00000000..e972ebe8 --- /dev/null +++ b/front/php-fpm.conf @@ -0,0 +1,81 @@ +; Start a new pool named 'www'. +; the variable $pool can we used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = www-data +group = www-data + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses on a +; specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /var/run/php-fpm.sock + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0666 +listen.owner = www-data +listen.group = www-data +listen.mode = 0640 + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 200 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 10 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 5 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 10 diff --git a/submission.php b/front/submission.php similarity index 88% rename from submission.php rename to front/submission.php index f99d2386..7897d759 100644 --- a/submission.php +++ b/front/submission.php @@ -5,15 +5,15 @@ if (!function_exists("show_submission_result")) { function show_submission_result($path) { - if (file_exists(__DIR__."/teams/".$path."/index.html")) - print file_get_contents(__DIR__."/teams/".$path."/index.html"); + if (file_exists(__DIR__."/../out/teams/".$path."/index.html")) + print file_get_contents(__DIR__."/../out/teams/".$path."/index.html"); else header("HTTP/1.1 403 Forbidden"); } } $filename = intval($_GET["team"])."-".intval($_GET["theme"])."-".urlencode($_GET["exercice"]); -$file = __DIR__."/submission/".$filename; +$file = __DIR__."/../submission/".$filename; if (file_exists($file)) diff --git a/misc/CA.sh b/misc/CA.sh index 45fd2f7f..d5248ce7 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -10,10 +10,15 @@ if [ -z "${OPENSSL_CONF}" ]; then OPENSSL_CONF=openssl.cnf fi -CAKEY=./cakey.key -CAREQ=./careq.csr -CACERT=./cacert.crt +CAKEY=${TOP_DIR}/private/cakey.key +CAREQ=${TOP_DIR}/careq.csr +CACRT=./shared/cacert.crt +SRVKEY=./shared/server.key +SRVREQ=./shared/server.csr +SRVCRT=./shared/server.crt + +# Generate certificates valid for: DAYS=2 if [ -z "$PS1" ] @@ -42,12 +47,13 @@ usage() clean() { if [ "$1" = "ca" ]; then - rm -rf ${TOP_DIR} + rm -rf ${TOP_DIR} ./shared/* mkdir -p ${TOP_DIR}/certs mkdir -p ${TOP_DIR}/crl mkdir -p ${TOP_DIR}/newcerts mkdir -p ${TOP_DIR}/private mkdir -p ${TOP_DIR}/pkcs + mkdir -p ./shared echo "01" > ${TOP_DIR}/crlnumber elif [ "$1" = "client" ]; then rm -rf ${TOP_DIR}/${2}.key ${TOP_DIR}/${2}.csr @@ -57,10 +63,10 @@ clean() gen_crl() { - echo $ECHO_OPTS "${GREEN}Generate crl.pem${COLOR_RST}" - openssl ca -config ${OPENSSL_CONF} -gencrl -out ${TOP_DIR}/crl.pem > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then - echo $ECHO_OPTS "${RED}Generate crl.pem failed" + echo $ECHO_OPTS "${GREEN}Generate shared/crl.pem${COLOR_RST}" + if ! openssl ca -config ${OPENSSL_CONF} -gencrl -out shared/crl.pem > $OUTPUT 2>&1 + then + echo $ECHO_OPTS "${RED}Generate shared/crl.pem failed" cat $OUTPUT exit 5 fi @@ -72,9 +78,7 @@ OUTPUT=$(mktemp) case $1 in "-newca" ) - echo -n $ECHO_OPTS "${GREEN}Create the directories, take care this will delete" - echo $ECHO_OPTS " the old directories ${COLOR_RST}" -# sleep 1; echo -n "1 "; sleep 1; echo -n "2 "; sleep 1; echo "3" + echo $ECHO_OPTS "${GREEN}Create the directories, take care this will delete the old directories ${COLOR_RST}" clean "ca" touch ${TOP_DIR}/index.txt @@ -92,30 +96,30 @@ case $1 in fi pass=`pwgen -n -B -y 12 1` - openssl req -batch -new -keyout ${TOP_DIR}/private/${CAKEY} \ - -out ${TOP_DIR}/${CAREQ} -passout pass:$pass \ - -config $OPENSSL_CONF -extensions CORE_CA > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl req -batch -new -keyout ${CAKEY} \ + -out ${CAREQ} -passout pass:$pass \ + -config ${OPENSSL_CONF} -extensions CORE_CA > $OUTPUT 2>&1 + then cat $OUTPUT clean "ca" exit 4 fi # This line deleted the passphase for the FIC 2014 automatisation - openssl rsa -passin pass:$pass -in ${TOP_DIR}/private/${CAKEY} \ - -out ${TOP_DIR}/private/${CAKEY} > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl rsa -passin pass:$pass -in ${CAKEY} \ + -out ${CAKEY} > $OUTPUT 2>&1 + then cat $OUTPUT clean "ca" exit 4 fi echo $ECHO_OPTS "${GREEN}Self signes the CA certificate${COLOR_RST}" - openssl ca -batch -create_serial -out ${TOP_DIR}/${CACERT} \ - -days ${DAYS} -keyfile ${TOP_DIR}/private/${CAKEY} \ - -selfsign -extensions CORE_CA -config ${OPENSSL_CONF} \ - -infiles ${TOP_DIR}/${CAREQ} > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl ca -batch -create_serial -out ${CACRT} \ + -days ${DAYS} -keyfile ${CAKEY} \ + -selfsign -extensions CORE_CA -config ${OPENSSL_CONF} \ + -infiles ${CAREQ} > $OUTPUT 2>&1 + then cat $OUTPUT clean "ca" exit 4 @@ -124,46 +128,45 @@ case $1 in "-newserver" ) echo $ECHO_OPTS "${GREEN}Making the Server key and cert${COLOR_RST}" - if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then + if ! [ -f ${CAKEY} ]; then echo $ECHO_OPTS "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi sed -i 's/=.*#COMMONNAME/=10.226.3.70#COMMONNAME/' $OPENSSL_CONF - openssl req -batch -new -keyout server.key -out server.csr \ - -days ${DAYS} -config ${OPENSSL_CONF} -extensions SERVER_SSL > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl req -batch -new -keyout ${SRVKEY} -out ${SRVREQ} \ + -days ${DAYS} -config ${OPENSSL_CONF} -extensions SERVER_SSL > $OUTPUT 2>&1 + then cat $OUTPUT exit 4 fi echo $ECHO_OPTS "${GREEN}Signing the Server crt${COLOR_RST}" - openssl ca -policy policy_match -config ${OPENSSL_CONF} \ - -out server.crt -extensions SERVER_SSL -infiles server.csr - if [ $? -ne 0 ]; then + if ! openssl ca -policy policy_match -config ${OPENSSL_CONF} \ + -out ${SRVCRT} -extensions SERVER_SSL -infiles ${SRVREQ} + then echo $ECHO_OPTS "${RED}Signing failed for new server${COLOR_RST}" - rm -rf server.key server.crt server.csr + rm -f ${SRVKEY} ${SRVREQ} ${SRVCRT} cat $OUTPUT exit 3 else - rm server.csr # remove ? - echo $ECHO_OPTS "${GREEN}Signed certificate is in server.crt${COLOR_RST}" + rm ${SRVREQ} + echo $ECHO_OPTS "${GREEN}Signed certificate is in ${SRVCRT}${COLOR_RST}" fi ;; "-revokeserver" ) echo $ECHO_OPTS "${GREEN}Revocate server certificate${COLOR_RST}" - if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then + if ! [ -f ${CAKEY} ]; then echo $ECHO_OPTS "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi - openssl ca -revoke server.crt -config ${OPENSSL_CONF}\ - -keyfile ${TOP_DIR}/private/${CAKEY} \ - -cert ${TOP_DIR}/${CACERT} > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl ca -revoke ${SRVCRT} -config ${OPENSSL_CONF} \ + -keyfile ${CAKEY} -cert ${CACRT} > $OUTPUT 2>&1 + then echo $ECHO_OPTS "${RED}Server certificate revocation failed${COLOR_RST}" cat $OUTPUT exit 4 fi - rm server.crt server.key + rm ${SRVKEY} ${SRVCRT} gen_crl ;; @@ -173,13 +176,20 @@ case $1 in echo "Usage: $0 -newclient NAME" exit 1 fi + + CLTNAM=$2 + CLTREQ=${TOP_DIR}/${CLTNAM}.csr + CLTCRT=${TOP_DIR}/${CLTNAM}.crt + CLTKEY=${TOP_DIR}/${CLTNAM}.key + CLTP12=${TOP_DIR}/pkcs/${CLTNAM}.p12 + echo "==============================================================" echo $ECHO_OPTS "${GREEN}Making the client key and csr of ${BOLD}${2}${END_BOLD}${COLOR_RST}" ESCAPED=$(echo "${TOP_DIR}" | sed 's/[\/\.]/\\&/g') sed -i "s/=.*#DIR/= ${ESCAPED} #DIR/" $OPENSSL_CONF - if ! [ -f ${TOP_DIR}/private/${CAKEY} ]; then + if ! [ -f ${CAKEY} ]; then echo $ECHO_OPTS "${RED}Can not found the CA's key${COLOR_RST}" exit 2 fi @@ -193,39 +203,39 @@ case $1 in pass=`pwgen -n -B -y 12 1` - openssl req -batch -new -keyout ${TOP_DIR}/${2}.key -out ${TOP_DIR}/${2}.csr \ - -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} -extensions CLIENT_SSL > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl req -batch -new -keyout "${CLTKEY}" -out "${CLTREQ}" \ + -config ${OPENSSL_CONF} -passout pass:$pass -days ${DAYS} -extensions CLIENT_SSL > $OUTPUT 2>&1 + then cat $OUTPUT - clean "client" $2 + clean "client" ${CLTNAM} exit 4 fi echo $ECHO_OPTS "${GREEN}Signing the Client crt${COLOR_RST}" - openssl ca -batch -policy policy_match -out ${TOP_DIR}/${2}.crt \ - -config ${OPENSSL_CONF} -extensions CLIENT_SSL -infiles ${TOP_DIR}/${2}.csr > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl ca -batch -policy policy_match -out "${CLTCRT}" \ + -config ${OPENSSL_CONF} -extensions CLIENT_SSL -infiles "${CLTREQ}" > $OUTPUT 2>&1 + then echo $ECHO_OPTS "${RED}Signing failed for $2 ${COLOR_RST}" cat $OUTPUT - clean "client" $2 + clean "client" ${CLTNAM} exit 3 fi echo $ECHO_OPTS "${GREEN}Export the Client files to pkcs12${COLOR_RST}" - openssl pkcs12 -export -inkey ${TOP_DIR}/${2}.key -in ${TOP_DIR}/${2}.crt -name ${2} \ - -passin pass:$pass -out ${TOP_DIR}/pkcs/${2}.p12 \ - -passout pass:$pass > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then + if ! openssl pkcs12 -export -inkey "${CLTKEY}" -in "${CLTCRT}" -name ${2} \ + -passin pass:$pass -out "${CLTP12}" \ + -passout pass:$pass > $OUTPUT 2>&1 + then echo $ECHO_OPTS "${RED}pkcs12 export failed for ${BOLD}$2${END_BOLD}${COLOR_RST}" cat $OUTPUT - clean "client" $2 + clean "client" ${CLTNAM} exit 4 else - echo $ECHO_OPTS "Exported pkcs12 file is ${2}.p12" + echo $ECHO_OPTS "Exported pkcs12 file is ${CLTP12}" fi - mv ${TOP_DIR}/${2}.crt ${TOP_DIR}/certs - echo "$2:$pass" >> ${TOP_DIR}/../teams.pass - echo "$pass" - clean "client" $2 + mv ${CLTCRT} ${TOP_DIR}/certs + echo "$CLTNAM:$pass" >> ${TOP_DIR}/../teams.pass + echo "$CLTNAM:$pass" + clean "client" ${CLTNAM} ;; "-revoke" ) @@ -233,17 +243,20 @@ case $1 in echo "Usage: $0 -revoke NAME" exit 1 fi - echo $ECHO_OPTS "${GREEN}Revocate ${BOLD}${2}${END_BOLD}${COLOR_RST}" - openssl ca -revoke ${TOP_DIR}/certs/${2}.crt -config ${OPENSSL_CONF}\ - -keyfile ${TOP_DIR}/private/${CAKEY} \ - -cert ${TOP_DIR}/${CACERT} > $OUTPUT 2>&1 - if [ $? -ne 0 ]; then - echo $ECHO_OPTS "${RED}Revocation failed for ${BOLD}${2}${END_BOLD}${COLOR_RST}" + + CLTNAM=$2 + CLTCRT=${TOP_DIR}/${CLTNAM}.crt + CLTP12=${TOP_DIR}/pkcs/${CLTNAM}.p12 + + echo $ECHO_OPTS "${GREEN}Revocate ${BOLD}${CLTNAM}${END_BOLD}${COLOR_RST}" + if ! openssl ca -revoke ${CLTCRT} -config ${OPENSSL_CONF}\ + -keyfile ${CAKEY} -cert ${CACRT} > $OUTPUT 2>&1 + then + echo $ECHO_OPTS "${RED}Revocation failed for ${BOLD}${CLTNAM}${END_BOLD}${COLOR_RST}" cat $OUTPUT exit 4 fi - rm ${TOP_DIR}/certs/${2}.crt - rm ${TOP_DIR}/pkcs/${2}.p12 + rm "${CLTCRT}" "${CLTP12}" gen_crl ;; diff --git a/misc/openssl.cnf b/misc/openssl.cnf index 1fc532fd..a90cd294 100644 --- a/misc/openssl.cnf +++ b/misc/openssl.cnf @@ -47,11 +47,11 @@ database = $dir/index.txt # database index file. # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. -certificate = $dir/cacert.crt # The CA certificate +certificate = $dir/../shared/cacert.crt # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL -crl = $dir/crl.pem # The current CRL +crl = $dir/../shared/crl.pem # The current CRL private_key = $dir/private/cakey.key # The private key RANDFILE = $dir/private/.rand # private random number file diff --git a/nginx-server.conf b/nginx-server.conf index 3e8e0cc3..250949e9 100644 --- a/nginx-server.conf +++ b/nginx-server.conf @@ -2,11 +2,12 @@ server { listen 443 ssl; listen [::]:443 ipv6only=on ssl; - ssl_certificate /var/www/fic-server/misc/server.crt; - ssl_certificate_key /var/www/fic-server/misc/server.key; -# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; -# ssl_prefer_server_ciphers on; -# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + ssl_certificate /var/www/fic-server/misc/shared/server.crt; + ssl_certificate_key /var/www/fic-server/misc/shared/server.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; +# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; + ssl_ciphers AES256+EECDH:AES256+EDH; include /var/www/fic-server/nginx-server-common.conf; } diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index 170fd8f3..00000000 --- a/nginx.conf +++ /dev/null @@ -1,131 +0,0 @@ -server_tokens off; -client_header_buffer_size 512; -client_max_body_size 512; - -server { - listen 80 default; - listen [::]:80 ipv6only=on default; - - rewrite ^ https://$host$uri; -} - -server { - listen 443 ssl; - listen [::]:443 ipv6only=on ssl; - - root /var/www/fic-server/htdocs/; - - server_tokens off; - - access_log /var/log/nginx/fic.access_log; - error_log /var/log/nginx/fic.error_log; - - ssl_certificate /var/www/fic-server/server.crt; - ssl_certificate_key /var/www/fic-server/server.key; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; -# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!ADH:!AECDH:!MD5:!DSS; - ssl_ciphers AES256+EECDH:AES256+EDH; - ssl_client_certificate /var/www/fic-server/cacert.crt; - ssl_verify_client optional; - ssl_crl /var/www/fic-server/crl.pem; - - add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; - add_header X-Frame-Options DENY; - add_header X-Content-Type-Options nosniff; - - error_page 400 /errors/400/index.html; - error_page 403 /errors/403/index.html; - error_page 404 /errors/404/index.html; - error_page 413 414 /errors/413/index.html; - error_page 500 503 /errors/500/index.html; - error_page 502 504 /errors/502/index.html; - - location / - { - default_type text/html; - expires epoch; - - set $team 0; - - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Amin_Martin/") { set $team 343; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Bernard_Angoustures/") { set $team 344; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Cacace_Diallo/") { set $team 345; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Delaporte_Notebaert/") { set $team 346; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Dibe/") { set $team 347; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Dubief_Roccia/") { set $team 348; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Ezzahoui/") { set $team 349; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Fall/") { set $team 350; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Guerin_Chapiron/") { set $team 351; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Hugot_Hincelin/") { set $team 352; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Jawor_Giraud/") { set $team 353; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Konan/") { set $team 354; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Le_Mignan_Yadaba/") { set $team 355; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Michel-villaz_Gzenayi/") { set $team 356; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Muller_Perrin/") { set $team 357; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Pourcelot/") { set $team 358; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Quint_Kaczmarek/") { set $team 359; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Ruff_Czarny/") { set $team 360; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Sinet_Girault/") { set $team 361; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Therrode/") { set $team 362; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Sabono_Calmeji/") { set $team 363; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=Renaud_Vandemeulebroucke/") { set $team 364; } - if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=De_Priest_Tjonck/") { set $team 365; } - - if ($team) { - root /var/www/fic-server/teams/$team$1; - rewrite ^/([0-9]+-?[a-zA-Z0-9_-]*)/([a-zA-Z0-9_]+)/submission$ /submission.php?team=$team&theme=$1&exercice=$2 last; - } - if ($team = 0) { - root /var/www/fic-server/htdocs/; - } - } - - location /errors - { - root /var/www/fic-server/; - } - - location /connected - { - return 403; - } - - location /files - { - root /var/www/fic-server/; - - aio on; - directio 512; - output_buffers 1 128k; - } - - location ~* \favicon.ico$ { - root /var/www/fic-server/htdocs/; - access_log off; - expires 1d; - add_header Cache-Control public; - } - - location ~ ^/(assets|img|js|css|fonts)/ { - root /var/www/fic-server/htdocs/; - access_log off; - expires 7d; - add_header Cache-Control public; - } - - location ~ /(\.ht|\.git|\.svn|\.onyx) { - return 403; - } - - location /submission.php - { - root /var/www/fic-server/; - - limit_rate 4k; - - include /etc/nginx/fastcgi.conf; - fastcgi_pass unix:/var/run/php-fpm.sock; - break; - } -} diff --git a/nginx_gen_team.sh b/nginx_gen_team.sh old mode 100644 new mode 100755 index 6347421c..5ac57349 --- a/nginx_gen_team.sh +++ b/nginx_gen_team.sh @@ -3,4 +3,6 @@ # Generate from database (exported XML from the website) the part of nginx # configuration file authenticating teams -curl http://localhost/admin/teams/export 2> /dev/null | grep "(.*)<.*$@ if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=\2/") { set $team \1; }@' +cd $(dirname "$0") + +curl http://localhost/$(grep prefix_admin onyx/config/root.xml | sed -E 's@.*(.*).*@\1@')/teams/export 2> /dev/null | grep "(.*)<.*$@ if ($ssl_client_s_dn ~ "/C=FR/ST=France/O=Epita/OU=SRS/CN=\2/") { set $team \1; }@' diff --git a/onyx/include/admin/home.php b/onyx/include/admin/home.php index 2297635a..9f1c1b71 100644 --- a/onyx/include/admin/home.php +++ b/onyx/include/admin/home.php @@ -22,7 +22,7 @@ if (is_writable($misc_dir) && !is_dir("$misc_dir/pki/")) $template->assign("cert_writable", is_writable("$misc_dir/pki/")); -$ca_file = "$misc_dir/pki/cacert.crt"; +$ca_file = "$misc_dir/shared/cacert.crt"; if (file_exists($ca_file)) { if (!is_readable($ca_file)) @@ -32,7 +32,7 @@ if (file_exists($ca_file)) openssl_x509_parse(file_get_contents($ca_file))); } -$srv_file = "$misc_dir/server.crt"; +$srv_file = "$misc_dir/shared/server.crt"; if (file_exists($srv_file)) { if (!is_readable($srv_file)) diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index dece7040..0a3342aa 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -14,7 +14,7 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) return "admin/import_users"; } - if (!file_exists("$misc_dir/pki/cacert.crt")) + if (!file_exists("$misc_dir/shared/cacert.crt")) { erreur("The root certificate file not found, please create this first"); return "admin/import_users"; diff --git a/onyx/include/team/exercice.php b/onyx/include/team/exercice.php index fa6af0d0..9bc2f90c 100644 --- a/onyx/include/team/exercice.php +++ b/onyx/include/team/exercice.php @@ -51,7 +51,7 @@ if (isset($VAR['submission_dir'])) $_GET["theme"] = $p[2]; $_GET["exercice"] = $p[3]; - require("../submission.php"); + require("../front/submission.php"); } // Fallback error diff --git a/synchro.sh b/synchro.sh index 8cebbb6d..aac801eb 100755 --- a/synchro.sh +++ b/synchro.sh @@ -21,11 +21,9 @@ then fi # Synchronize HTML pages -rsync -e ssh -av $OPTS out/errors "$FRONTEND_HOSTNAME":~/ -rsync -e ssh -av $OPTS out/htdocs "$FRONTEND_HOSTNAME":~/ -rsync -e ssh -av $OPTS out/teams "$FRONTEND_HOSTNAME":~/ +rsync -e ssh -av $OPTS out "$FRONTEND_HOSTNAME":~/ rsync -e ssh -avL $OPTS files "$FRONTEND_HOSTNAME":~/ -rsync -e ssh -av $OPTS nginx.conf submission.php misc/server.crt misc/server.key misc/pki/cacert.crt misc/pki/crl.pem "$FRONTEND_HOSTNAME":~/ +rsync -e ssh -av $OPTS front/ misc/shared/ "$FRONTEND_HOSTNAME":~/ # Synchronize submissions rsync -e ssh -av "$FRONTEND_HOSTNAME":~/submission/ submission/ From a23089d841cb9f4501443146b8ff9f790983e1e9 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 16:02:46 +0100 Subject: [PATCH 0267/2585] Don't in dev mode anymore --- onyx/tpl/bootstrap/layout.tpl | 1 - 1 file changed, 1 deletion(-) diff --git a/onyx/tpl/bootstrap/layout.tpl b/onyx/tpl/bootstrap/layout.tpl index a482e1ae..2556a186 100644 --- a/onyx/tpl/bootstrap/layout.tpl +++ b/onyx/tpl/bootstrap/layout.tpl @@ -20,7 +20,6 @@ {block name=head}{/block} - {block name=body} From 4a5f30f967629cbef2921940538a315213e5f472 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 22:39:39 +0100 Subject: [PATCH 0268/2585] Force bash on container launch --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ab173c72..67eed903 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,4 +61,4 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem EXPOSE 80/tcp 443/tcp VOLUME ["/var/www/fic-server/out","/var/www/fic-server/files","/var/www/fic-server/submission","/var/www/fic-server/misc/shared"] -CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then ./CA.sh -newserver; fi; ./CA.sh -gencrl && service nginx start && service php5-fpm start && service mysql start && ../gen_hash_link_files.sh --copy ../files-in ../files && ../nginx_gen_team.sh > ../misc/shared/nginx-teams.conf && (../launch_local.sh &); /bin/bash"] +CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; bash ./CA.sh -gencrl && service nginx start && service php5-fpm start && service mysql start && echo "Copying files..." && ../gen_hash_link_files.sh --copy ../files-in ../files && ../nginx_gen_team.sh > ../misc/shared/nginx-teams.conf && (../launch_local.sh &); /bin/bash"] From 87c4275ba9471447cc1bddd48cd4306b48649954 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 22:39:45 +0100 Subject: [PATCH 0269/2585] Updating TODO --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 2d7c5a11..63de4697 100644 --- a/TODO +++ b/TODO @@ -11,3 +11,4 @@ - Dockerfile de simulation de frontend - Au moment du lancement du chrono, ouvrir la socket de communication avec le scheduler et lui ajouter la directive all:S pour regénérer toutes les équipes - On peut encore soumettre après la fin... +- Gerer les espaces dans les fichiers From 80a0396500396f25506ec989701c87c34faae93b Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 22:44:54 +0100 Subject: [PATCH 0270/2585] Replace invalid character in ID --- onyx/include/admin/import_exercices.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onyx/include/admin/import_exercices.php b/onyx/include/admin/import_exercices.php index 9471d913..79592a4a 100644 --- a/onyx/include/admin/import_exercices.php +++ b/onyx/include/admin/import_exercices.php @@ -40,7 +40,7 @@ if ($SESS->level > 1) { $ex = new Exercice(); - $ex->id = $element->getAttribute("id"); + $ex->id = preg_replace("/[^a-zA-Z0-9_]/g", "_", $element->getAttribute("id")); $ex->level = $element->getAttribute("level"); if ($element->hasAttribute("depends")) $ex->require = $element->getAttribute("depends"); From 16ede02de52308adf0ef64a85658c22be96764b0 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 22:46:47 +0100 Subject: [PATCH 0271/2585] Typo --- onyx/lang/fr/erreurs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onyx/lang/fr/erreurs.json b/onyx/lang/fr/erreurs.json index 3bfc1b57..82d60471 100644 --- a/onyx/lang/fr/erreurs.json +++ b/onyx/lang/fr/erreurs.json @@ -1,6 +1,6 @@ { "400":{"title":"Erreur 400","subtitle":"Requête erronée","content":"Vérifiez les paramètres de votre navigateur, il est très probable que ce problème soit lié à un mauvais certificat client : invalide, révoqué, ..."}, - "403":{"title":"Erreur 403","subtitle":"Accés réglementé","content":"Vous n'êtes pas autorisé à accéder à cette page."}, + "403":{"title":"Erreur 403","subtitle":"Accès réglementé","content":"Vous n'êtes pas autorisé à accéder à cette page."}, "404":{"title":"Erreur 404","subtitle":"Page introuvable","content":"La page à laquelle vous tentez d'accéder n'existe pas ou l'adresse que vous avez tapée est incorrecte."}, "413":{"title":"Erreur 413","subtitle":"Requête trop grande","content":"Vous tentez d'envoyer trop de données que ce que le serveur est prêt ou est capable de traiter."}, "500":{"title":"Erreur 500","subtitle":"Erreur interne","content":"Le serveur est actuellement dans l'incapacité de repondre à votre requête.

    Veuillez recommencer plus tard."}, From 453845090841e8cecb019141bc88cdf2a3f4f909 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 23:07:01 +0100 Subject: [PATCH 0272/2585] Fix CA path --- misc/CA.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/misc/CA.sh b/misc/CA.sh index d5248ce7..362984c9 100755 --- a/misc/CA.sh +++ b/misc/CA.sh @@ -179,7 +179,7 @@ case $1 in CLTNAM=$2 CLTREQ=${TOP_DIR}/${CLTNAM}.csr - CLTCRT=${TOP_DIR}/${CLTNAM}.crt + CLTCRT=${TOP_DIR}/certs/${CLTNAM}.crt CLTKEY=${TOP_DIR}/${CLTNAM}.key CLTP12=${TOP_DIR}/pkcs/${CLTNAM}.p12 @@ -232,7 +232,6 @@ case $1 in else echo $ECHO_OPTS "Exported pkcs12 file is ${CLTP12}" fi - mv ${CLTCRT} ${TOP_DIR}/certs echo "$CLTNAM:$pass" >> ${TOP_DIR}/../teams.pass echo "$CLTNAM:$pass" clean "client" ${CLTNAM} @@ -245,12 +244,12 @@ case $1 in fi CLTNAM=$2 - CLTCRT=${TOP_DIR}/${CLTNAM}.crt + CLTCRT=${TOP_DIR}/certs/${CLTNAM}.crt CLTP12=${TOP_DIR}/pkcs/${CLTNAM}.p12 echo $ECHO_OPTS "${GREEN}Revocate ${BOLD}${CLTNAM}${END_BOLD}${COLOR_RST}" - if ! openssl ca -revoke ${CLTCRT} -config ${OPENSSL_CONF}\ - -keyfile ${CAKEY} -cert ${CACRT} > $OUTPUT 2>&1 + if ! openssl ca -revoke "${CLTCRT}" -config "${OPENSSL_CONF}" \ + -keyfile "${CAKEY}" -cert "${CACRT}" > $OUTPUT 2>&1 then echo $ECHO_OPTS "${RED}Revocation failed for ${BOLD}${CLTNAM}${END_BOLD}${COLOR_RST}" cat $OUTPUT From cf26754ad6fcdb31b47500f2e220da6c6cb66886 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 23:16:57 +0100 Subject: [PATCH 0273/2585] Fix access to exercice after static generation --- onyx/tpl/bootstrap/teams/theme.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/onyx/tpl/bootstrap/teams/theme.tpl b/onyx/tpl/bootstrap/teams/theme.tpl index 14b4052f..0e9c4118 100644 --- a/onyx/tpl/bootstrap/teams/theme.tpl +++ b/onyx/tpl/bootstrap/teams/theme.tpl @@ -6,9 +6,9 @@

    {foreach from=$cur_theme->get_exercices_ordered() item=exercice} {if $exercice->has_solved($my_team)} - {link class="btn btn-success" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name_url()}/{$exercice->get_id()}" label="{$exercice->get_name()}"} + {link class="btn btn-success" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name_url()}/{$exercice->get_id()}/" label="{$exercice->get_name()}"} {elseif $exercice->is_unlocked($my_team)} - {link class="btn btn-primary" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name_url()}/{$exercice->get_id()}" label="{$exercice->get_name()}"} + {link class="btn btn-primary" role="button" href_prefix="/{$SALT_USER}/{$my_team->get_id()}/" href="{$cur_theme->get_id()}-{$cur_theme->get_name_url()}/{$exercice->get_id()}/" label="{$exercice->get_name()}"} {else} {$exercice->get_name()} {/if} From 96828dc1d17baf14d0af72be1c4e6b56ee95b437 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 23:39:51 +0100 Subject: [PATCH 0274/2585] Updating TODO --- TODO | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 63de4697..639d595d 100644 --- a/TODO +++ b/TODO @@ -11,4 +11,5 @@ - Dockerfile de simulation de frontend - Au moment du lancement du chrono, ouvrir la socket de communication avec le scheduler et lui ajouter la directive all:S pour regénérer toutes les équipes - On peut encore soumettre après la fin... -- Gerer les espaces dans les fichiers +- Gerer les espaces dans les fichiers (gen_hash_file plante) +- Ajouter une instruction dans le scheduler pour regen le nginx des teams From 604a2589bd2166a1df968fad62b94fb902228c22 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 21 Nov 2014 23:45:21 +0100 Subject: [PATCH 0275/2585] Alert when no team found --- onyx/include/admin/import_users.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index 0a3342aa..a0275c8b 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -94,6 +94,8 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) } $template->assign("output", $output); } + else + $error = "Aucune team trouvée"; if ($error != "") erreur($error); From 5af236931605fa33f721121964a51d91cb8dabbf Mon Sep 17 00:00:00 2001 From: nemunaire Date: Sat, 22 Nov 2014 21:48:29 +0100 Subject: [PATCH 0276/2585] Updating TODO --- TODO | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 639d595d..cfc7799d 100644 --- a/TODO +++ b/TODO @@ -8,8 +8,12 @@ - versionner la DTD et la doc associée - valider les documents avec la DTD à l'import - Lors de l'import des XML, retirer l'éventuel / en début de path -- Dockerfile de simulation de frontend - Au moment du lancement du chrono, ouvrir la socket de communication avec le scheduler et lui ajouter la directive all:S pour regénérer toutes les équipes - On peut encore soumettre après la fin... - Gerer les espaces dans les fichiers (gen_hash_file plante) - Ajouter une instruction dans le scheduler pour regen le nginx des teams +- image dans la description +- upload/MAJ de fichiers depuis l'interface d'admin? +- trop de thèmes dans l'interface d'admin => menu +- numéro des exercices +- lors de l'import, vérifier que les ID existent => afficher les erreurs MySQL From 335505ef6c74e96945d940e89530b01251b86a09 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Sat, 22 Nov 2014 21:49:10 +0100 Subject: [PATCH 0277/2585] Fix generation of me, rank and summary pages --- onyx/tpl/bootstrap/teams/layout.tpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/onyx/tpl/bootstrap/teams/layout.tpl b/onyx/tpl/bootstrap/teams/layout.tpl index 05ebc41f..7a01b72f 100644 --- a/onyx/tpl/bootstrap/teams/layout.tpl +++ b/onyx/tpl/bootstrap/teams/layout.tpl @@ -30,12 +30,12 @@

    From edce0a99f6702213f42c26d32dc189961b1b7411 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Sun, 23 Nov 2014 16:02:45 +0100 Subject: [PATCH 0278/2585] New instruction to regen nginx team file --- README.md | 6 +++--- TODO | 1 - gen_site.pl | 18 +++++++++++++++--- launch.sh | 2 +- launch_local.sh | 2 +- onyx/config/sample.root.xml | 1 + onyx/include/admin/import_users.php | 2 +- 7 files changed, 22 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f82ac010..af557a0d 100644 --- a/README.md +++ b/README.md @@ -164,9 +164,9 @@ The D Day ### Interact with the scheduler When you launch `launch.sh` or `launch_local.sh` script, a socket is open at -`/tmp/test.sock`. Use `perl comm-socket.pl /tmp/test.sock` to connect to the -scheduler. Consult `gen_site.pl` manual (`perldoc gen_site.pl`) for list of -available instructions. +`/tmp/scheduler.sock`. Use `perl comm-socket.pl /tmp/scheduler.sock` to connect +to the scheduler. Consult `gen_site.pl` manual (`perldoc gen_site.pl`) for list +of available instructions. ### More diff --git a/TODO b/TODO index cfc7799d..244af6a2 100644 --- a/TODO +++ b/TODO @@ -11,7 +11,6 @@ - Au moment du lancement du chrono, ouvrir la socket de communication avec le scheduler et lui ajouter la directive all:S pour regénérer toutes les équipes - On peut encore soumettre après la fin... - Gerer les espaces dans les fichiers (gen_hash_file plante) -- Ajouter une instruction dans le scheduler pour regen le nginx des teams - image dans la description - upload/MAJ de fichiers depuis l'interface d'admin? - trop de thèmes dans l'interface d'admin => menu diff --git a/gen_site.pl b/gen_site.pl index 45175a4c..c21da15f 100755 --- a/gen_site.pl +++ b/gen_site.pl @@ -181,6 +181,14 @@ sub manage $m->stop(); return 1; } + elsif (/^RT(E(A(M(S)?)?)?)?/) + { + if (-x "nginx_gen_team.sh") { + qx(./nginx_gen_team.sh > ./misc/shared/nginx-teams.conf) + } else { + say "Unable to find nginx_gen_team.sh" + } + } elsif (/^help/i) { say "TODO, sorry :("; @@ -795,7 +803,7 @@ __END__ =head1 NAME -Dave Null - The netiquette's guardian angel +FIC parallel WGET =head1 USAGE @@ -873,7 +881,7 @@ Generate pages for the C<11> theme for the team C<00>. =item B - +Clean the temporary directory. =item B @@ -892,7 +900,11 @@ Perform a C in the temporary directory content. =item B -Flush the scheduler queue and +Flush the scheduler queue and wait for all jobs done. + +=item B + +Regenerate the nginx file containing teams IDs. =item B diff --git a/launch.sh b/launch.sh index f99b81e4..d157f502 100755 --- a/launch.sh +++ b/launch.sh @@ -22,7 +22,7 @@ KP1=$! TMPF=`mktemp` -tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -o ./out ERRORS HOME all DS & +tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/scheduler.sock -o ./out ERRORS HOME all DS & KP2=$! trap "kill $KP1 $KP2; rm -rf '$TMPF'; echo" SIGINT SIGTERM diff --git a/launch_local.sh b/launch_local.sh index 87b5a8f1..49d9afb3 100755 --- a/launch_local.sh +++ b/launch_local.sh @@ -22,7 +22,7 @@ KP1=$! TMPF=`mktemp` -tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/test.sock -bt /challenge/ -ba /challenge-admin/ -o ./out ERRORS HOME all DS & +tail -f "$TMPF" | ./gen_site.pl -d -s /tmp/scheduler.sock -bt /challenge/ -ba /challenge-admin/ -o ./out ERRORS HOME all DS & KP2=$! trap "kill $KP1 $KP2; rm -rf '$TMPF'; echo" SIGINT SIGTERM diff --git a/onyx/config/sample.root.xml b/onyx/config/sample.root.xml index 748b5433..eceae299 100644 --- a/onyx/config/sample.root.xml +++ b/onyx/config/sample.root.xml @@ -5,6 +5,7 @@ /var/www/fic-server/files/ /var/www/fic-server/misc/ /var/www/fic-server/submission/ + /tmp/scheduler.sock challenge-public challenge challenge-admin diff --git a/onyx/include/admin/import_users.php b/onyx/include/admin/import_users.php index a0275c8b..f68ad7b1 100644 --- a/onyx/include/admin/import_users.php +++ b/onyx/include/admin/import_users.php @@ -73,7 +73,7 @@ if (!empty($_FILES["inputFile"]['tmp_name'])) if (!$user->update()) { - $error .= "Unable to add user $user->firstname $user->lastname $user->nickname
    "; + $error .= "Unable to add user $user->firstname $user->lastname $user->nickname
    "; $team->drop(); continue; } From 5d7967a157aacdb415111ec4bb18f2c101fcfa70 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Sun, 23 Nov 2014 16:56:30 +0100 Subject: [PATCH 0279/2585] Calculate countdown by reading X-FIC-time giving by the server instead of rely on user system date --- Dockerfile | 2 +- TODO | 1 - front/nginx.conf | 1 + htdocs/js/countdown.js | 42 +++++++++++++++++++++++++--------------- nginx-server-common.conf | 1 + 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index 67eed903..d36a7189 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,4 +61,4 @@ RUN chmod 777 /var/www/fic-server/onyx/cache/ /var/www/fic-server/onyx/cache/tem EXPOSE 80/tcp 443/tcp VOLUME ["/var/www/fic-server/out","/var/www/fic-server/files","/var/www/fic-server/submission","/var/www/fic-server/misc/shared"] -CMD ["sh", "-c", "chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; bash ./CA.sh -gencrl && service nginx start && service php5-fpm start && service mysql start && echo "Copying files..." && ../gen_hash_link_files.sh --copy ../files-in ../files && ../nginx_gen_team.sh > ../misc/shared/nginx-teams.conf && (../launch_local.sh &); /bin/bash"] +CMD chown -R www-data:www-data /var/www/fic-server/misc /var/www/fic-server/submission; cd /var/www/fic-server/misc; if ! [ -f server.crt ]; then bash ./CA.sh -newserver; fi; bash ./CA.sh -gencrl && service nginx start && service php5-fpm start && service mysql start && echo "Copying files..." && ../gen_hash_link_files.sh --copy ../files-in ../files; ../nginx_gen_team.sh > ../misc/shared/nginx-teams.conf; (../launch_local.sh &); /bin/bash diff --git a/TODO b/TODO index 244af6a2..ea697c37 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ - Départager les ex-æquo dans le classement - Résoudre le problème potentiel de famine de l'ordonnanceur en cas de brute-force d'une équipe -- Ajouter un header dans nginx avec $msec ou $time_iso8601 et calculer le timer à partir de cette valeur, au lieu de se baser sur l'horloge de l'utilisateur - Quand est généré la CRL ? - Ajouter dans la conf de nginx un ssl_dhparam + générer le fichier dans un script - Mettre à jour Smarty (et passer en « secure mode » ?) diff --git a/front/nginx.conf b/front/nginx.conf index 2760600e..762d79d0 100644 --- a/front/nginx.conf +++ b/front/nginx.conf @@ -31,6 +31,7 @@ server { add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; + add_header X-FIC-time $msec; error_page 400 /errors/400/index.html; error_page 403 /errors/403/index.html; diff --git a/htdocs/js/countdown.js b/htdocs/js/countdown.js index fee573f2..04caff20 100644 --- a/htdocs/js/countdown.js +++ b/htdocs/js/countdown.js @@ -1,24 +1,34 @@ -function update_end() +function update_end(server_time, receive_date) { - var left; - if (typeof end_challenge === 'undefined') - left = 14400; - else - left = (end_challenge - new Date())/1000; + var elapsed = new Date() - receive_date; - if (left < 0) left = 0; + var left = 10800; + if (typeof end_challenge !== 'undefined') + left = (end_challenge - server_time - elapsed)/1000; - var heure = Math.floor(left / 3600); - var min = Math.floor((left / 60) % 60); - var sec = Math.floor(left % 60); + if (left < 0) left = 0; - $("#hours").html(( heure < 10 ? "0" : "" ) + heure); - $("#min").html(( min < 10 ? "0" : "" ) + min); - $("#sec").html(( sec < 10 ? "0" : "" ) + sec); + var heure = Math.floor(left / 3600); + var min = Math.floor((left / 60) % 60); + var sec = Math.floor(left % 60); + + $("#hours").html(( heure < 10 ? "0" : "" ) + heure); + $("#min").html(( min < 10 ? "0" : "" ) + min); + $("#sec").html(( sec < 10 ? "0" : "" ) + sec); +} + +function getHeader(name, def) { + for (var j = 0; j < getHttp.length(); j++) { + if (getHttp.header(j) == name) + return getHttp.data(j); + } + return def; } $(document).ready(function() { - setInterval( function() { - update_end(); - }, 1000); + server_time = new Date(getHeader("X-FIC-time")); + receive_date = new Date(); + setInterval( function() { + update_end(server_time, receive_date); + }, 1000); }); diff --git a/nginx-server-common.conf b/nginx-server-common.conf index e33e72cf..df7afb55 100644 --- a/nginx-server-common.conf +++ b/nginx-server-common.conf @@ -7,6 +7,7 @@ add_header Strict-Transport-Security "max-age=2592000; includeSubdomains"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; + add_header X-FIC-time $msec; location / { if (-f $request_filename) { From 21e4432fad1a5e59554dbc2540beb44b16d255f3 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 6 Jan 2016 19:30:57 +0100 Subject: [PATCH 0280/2585] Add frontend --- frontend/.gitignore | 1 + frontend/main.go | 33 ++++++++++++++++ frontend/submit.go | 91 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 frontend/.gitignore create mode 100644 frontend/main.go create mode 100644 frontend/submit.go diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..1097e68b --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1 @@ +frontend diff --git a/frontend/main.go b/frontend/main.go new file mode 100644 index 00000000..2427f571 --- /dev/null +++ b/frontend/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "flag" + "fmt" + "log" + "net/http" + "os" +) + +var SubmissionDir string + +func main() { + var bind = flag.String("bind", "0.0.0.0:8080", "Bind port/socket") + var prefix = flag.String("prefix", "", "Request path prefix to strip (from proxy)") + flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions") + flag.Parse() + + log.Println("Creating submission directory...") + if _, err := os.Stat(SubmissionDir); os.IsNotExist(err) { + if err := os.MkdirAll(SubmissionDir, 0777); err != nil { + log.Fatal("Unable to create submission directory: ", err) + } + } + + log.Println("Registering handlers...") + http.Handle(fmt.Sprintf("%s/", *prefix), http.StripPrefix(*prefix, SubmissionHandler{})) + + log.Println(fmt.Sprintf("Ready, listening on %s", *bind)) + if err := http.ListenAndServe(*bind, nil); err != nil { + log.Fatal("Unable to listen and serve: ", err) + } +} diff --git a/frontend/submit.go b/frontend/submit.go new file mode 100644 index 00000000..2b66f644 --- /dev/null +++ b/frontend/submit.go @@ -0,0 +1,91 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "os" + "path" + "strconv" + "strings" +) + +type SubmissionHandler struct{} + +func (SubmissionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) + + w.Header().Set("Content-Type", "application/json") + + + // Check request type and size + if r.Method != "POST" { + http.Error(w, "{errmsg:\"Bad request.\"}", http.StatusBadRequest) + return + } else if r.ContentLength < 0 || r.ContentLength > 255 { + http.Error(w, "{errmsg:\"Request too large or request size unknown\"}", http.StatusRequestEntityTooLarge) + return + } + + + // Extract URL arguments + var sURL = strings.Split(r.URL.Path, "/") + + if len(sURL) != 3 && len(sURL) != 4 { + http.Error(w, "{errmsg:\"Bad request.\"}", http.StatusBadRequest) + return + } + + // Parse arguments + if team, err := strconv.Atoi(sURL[1]); err != nil { + http.Error(w, "{errmsg:\"Bad request.\"}", http.StatusBadRequest) + return + } else if exercice, err := strconv.Atoi(sURL[2]); err != nil { + http.Error(w, "{errmsg:\"Bad request.\"}", http.StatusBadRequest) + return + } else { + if _, err := os.Stat(path.Join(SubmissionDir, fmt.Sprintf("%d", team))); os.IsNotExist(err) { + log.Println("Creating submission directory for", team) + if err := os.MkdirAll(path.Join(SubmissionDir, fmt.Sprintf("%d", team)), 0777); err != nil { + log.Println("Unable to create submission directory: ", err) + http.Error(w, "{errmsg:\"Internal server error. Please retry in few seconds.\"}", http.StatusInternalServerError) + return + } + } + + + // Previous submission not treated + if _, err := os.Stat(path.Join(SubmissionDir, fmt.Sprintf("%d", team), fmt.Sprintf("%d", exercice))); !os.IsNotExist(err) { + http.Error(w, "{errmsg:\"Calm-down. A solution is already being processed.\"}", http.StatusPaymentRequired) + return + } + + + // Read request body + var body []byte + if r.ContentLength > 0 { + tmp := make([]byte, 1024) + for { + n, err := r.Body.Read(tmp) + for j := 0; j < n; j++ { + body = append(body, tmp[j]) + } + if err != nil || n <= 0 { + break + } + } + } + + + // Store content in file + if file, err := os.Create(path.Join(SubmissionDir, fmt.Sprintf("%d", team), fmt.Sprintf("%d", exercice))); err != nil { + log.Println("Unable to open exercice file:", err) + http.Error(w, "{errmsg:\"Internal server error. Please retry in few seconds.\"}", http.StatusInternalServerError) + return + } else { + file.Write(body) + file.Close() + } + http.Error(w, "{errmsg:\"Submission accepted, please wait...\"}", http.StatusAccepted) + } +} From a5dc600f28b5ba8192e0184136f0ea094ad30a96 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 7 Jan 2016 18:27:53 +0100 Subject: [PATCH 0281/2585] Add API basis --- admin/api.go | 85 ++++++++++++++++++++++++++++++++++++++++++++ admin/api_version.go | 11 ++++++ admin/main.go | 27 ++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 admin/api.go create mode 100644 admin/api_version.go create mode 100644 admin/main.go diff --git a/admin/api.go b/admin/api.go new file mode 100644 index 00000000..349d5181 --- /dev/null +++ b/admin/api.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "strings" +) + +type DispatchFunction func([]string, []byte) (interface{}, error) + +var apiRouting = map[string]*(map[string]DispatchFunction){ + "version": &ApiVersionRouting, + //"images": &ApiImagesRouting, + //"users": &ApiUsersRouting, +} + +func ApiRouting(w http.ResponseWriter, r *http.Request) { + log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) + + // Extract URL arguments + var sURL = strings.Split(r.URL.Path, "/") + if sURL[len(sURL)-1] == "" && len(sURL) > 2 { + // Remove trailing / + sURL = sURL[:len(sURL)-1] + } + + w.Header().Set("Content-Type", "application/json") + + var ret interface{} + var err error = nil + + // Read the body + if r.ContentLength < 0 || r.ContentLength > 6553600 { + http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}", err), http.StatusRequestEntityTooLarge) + return + } + var body []byte + if r.ContentLength > 0 { + tmp := make([]byte, 1024) + for { + n, err := r.Body.Read(tmp) + for j := 0; j < n; j++ { + body = append(body, tmp[j]) + } + if err != nil || n <= 0 { + break + } + } + } + + // Route request + if len(sURL) > 1 { + if h, ok := apiRouting[sURL[1]]; ok { + if f, ok := (*h)[r.Method]; ok { + ret, err = f(sURL[2:], body) + } else { + err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[1])) + } + } + } else { + err = errors.New("No action provided.") + } + + // Format response + resStatus := http.StatusOK + if err != nil { + ret = map[string]string{"errmsg": err.Error()} + resStatus = http.StatusBadRequest + } + + if ret == nil { + ret = map[string]string{"errmsg": "Page not found"} + resStatus = http.StatusNotFound + } + + if j, err := json.Marshal(ret); err != nil { + http.Error(w, fmt.Sprintf("{errmsg:\"%q\"}", err), http.StatusInternalServerError) + } else { + w.WriteHeader(resStatus) + w.Write(j) + } +} diff --git a/admin/api_version.go b/admin/api_version.go new file mode 100644 index 00000000..9b4cbbfb --- /dev/null +++ b/admin/api_version.go @@ -0,0 +1,11 @@ +package main + +import () + +var ApiVersionRouting = map[string]DispatchFunction{ + "GET": showVersion, +} + +func showVersion(args []string, body []byte) (interface{}, error) { + return map[string]interface{}{"version": 0.1}, nil +} diff --git a/admin/main.go b/admin/main.go new file mode 100644 index 00000000..87b856fc --- /dev/null +++ b/admin/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "flag" + "fmt" + "log" + "net/http" +) + +var SubmissionDir string +var BaseURL string + +func main() { + var bind = flag.String("bind", "0.0.0.0:8081", "Bind port/socket") + var _ = flag.String("db", "fic.db", "Path to the DB") + flag.StringVar(&BaseURL, "baseurl", "http://fic.srs.epita.fr/", "URL prepended to each URL") + flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions") + flag.Parse() + + log.Println("Registering handlers...") + http.HandleFunc("/", ApiRouting) + + log.Println(fmt.Sprintf("Ready, listening on %s", *bind)) + if err := http.ListenAndServe(*bind, nil); err != nil { + log.Fatal("Unable to listen and serve: ", err) + } +} From abd5e2025ea4ce344668eadc39da20b90d7d9881 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 7 Jan 2016 18:28:16 +0100 Subject: [PATCH 0282/2585] Add DB creation from schema --- admin/.gitignore | 2 + admin/db.go | 109 +++++++++++++++++++++++++++++++++++++++++++++++ admin/main.go | 18 +++++++- 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 admin/.gitignore create mode 100644 admin/db.go diff --git a/admin/.gitignore b/admin/.gitignore new file mode 100644 index 00000000..6a514f21 --- /dev/null +++ b/admin/.gitignore @@ -0,0 +1,2 @@ +admin +fic.db diff --git a/admin/db.go b/admin/db.go new file mode 100644 index 00000000..0a8bc61e --- /dev/null +++ b/admin/db.go @@ -0,0 +1,109 @@ +package main + +import ( + "database/sql" + _ "github.com/mattn/go-sqlite3" +) + +var db *sql.DB + +func DBInit(path string) error { + var err error + if db, err = sql.Open("sqlite3", path); err != nil { + return err + } + + _, err = db.Exec(` +PRAGMA foreign_keys=ON; +`) + return err +} + +func DBCreate() error { + _, err := db.Exec(` +CREATE TABLE IF NOT EXISTS themes( + id_theme INTEGER NOT NULL PRIMARY KEY, + name TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS teams( + id_team INTEGER NOT NULL PRIMARY KEY, + name TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS team_certificates( + id_team INTEGER NOT NULL PRIMARY KEY, + revoked INTEGER NOT NULL, + FOREIGN KEY(id_team) REFERENCES teams(id_team) +); +CREATE TABLE IF NOT EXISTS team_members( + id_member INTEGER NOT NULL PRIMARY KEY, + id_team INTEGER, + firstname TEXT NOT NULL, + lastname TEXT NOT NULL, + nickname TEXT NOT NULL, + company TEXT NOT NULL, + FOREIGN KEY(id_team) REFERENCES teams(id_team) +); +CREATE TABLE IF NOT EXISTS exercices( + id_exercice INTEGER NOT NULL PRIMARY KEY, + id_theme INTEGER NOT NULL, + title TEXT NOT NULL, + statement TEXT NOT NULL, + hint TEXT NOT NULL, + depend INTEGER, + gain INTEGER NOT NULL, + video_uri TEXT NOT NULL, + FOREIGN KEY(id_theme) REFERENCES themes(id_theme), + FOREIGN KEY(depend) REFERENCES exercices(id_exercice) +); +CREATE TABLE IF NOT EXISTS exercice_files( + id_file INTEGER NOT NULL PRIMARY KEY, + path TEXT NOT NULL UNIQUE, + id_exercice INTEGER NOT NULL, + name TEXT NOT NULL, + sha1 BLOB NOT NULL, + FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) +); +CREATE TABLE IF NOT EXISTS exercice_keys( + id_key INTEGER NOT NULL PRIMARY KEY, + id_exercice INTEGER NOT NULL, + type TEXT NOT NULL, + value BLOB NOT NULL, + FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) +); +CREATE TABLE IF NOT EXISTS exercice_solved( + id_exercice INTEGER NOT NULL, + id_team INTEGER NOT NULL, + time TIMESTAMP NOT NULL, + FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice), + FOREIGN KEY(id_team) REFERENCES teams(id_team) +); +CREATE TABLE IF NOT EXISTS exercice_tries( + id_exercice INTEGER NOT NULL, + id_team INTEGER NOT NULL, + time TIMESTAMP NOT NULL, + FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice), + FOREIGN KEY(id_team) REFERENCES teams(id_team) +); +`) + return err +} + +func DBClose() error { + return db.Close() +} + +func DBPrepare(query string) (*sql.Stmt, error) { + return db.Prepare(query) +} + +func DBQuery(query string, args ...interface{}) (*sql.Rows, error) { + return db.Query(query, args...) +} + +func DBExec(query string, args ...interface{}) (sql.Result, error) { + return db.Exec(query, args...) +} + +func DBQueryRow(query string, args ...interface{}) *sql.Row { + return db.QueryRow(query, args...) +} diff --git a/admin/main.go b/admin/main.go index 87b856fc..1979ca64 100644 --- a/admin/main.go +++ b/admin/main.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net/http" + "os" ) var SubmissionDir string @@ -12,11 +13,26 @@ var BaseURL string func main() { var bind = flag.String("bind", "0.0.0.0:8081", "Bind port/socket") - var _ = flag.String("db", "fic.db", "Path to the DB") + var dbfile = flag.String("db", "fic.db", "Path to the DB") flag.StringVar(&BaseURL, "baseurl", "http://fic.srs.epita.fr/", "URL prepended to each URL") flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions") flag.Parse() + log.Println("Opening database...") + if err := DBInit(*dbfile); err != nil { + log.Fatal("Cannot open the database: ", err) + os.Exit(1) + + } + defer DBClose() + + log.Println("Creating database...") + if err := DBCreate(); err != nil { + log.Fatal("Cannot create database: ", err) + os.Exit(1) + + } + log.Println("Registering handlers...") http.HandleFunc("/", ApiRouting) From 6ec37b83ceb6917668543bcabf3042bb97d680f6 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 7 Jan 2016 18:43:02 +0100 Subject: [PATCH 0283/2585] Add DB objects --- admin/api.go | 4 +-- admin/exercice.go | 83 +++++++++++++++++++++++++++++++++++++++++++++ admin/file.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++ admin/key.go | 69 ++++++++++++++++++++++++++++++++++++++ admin/member.go | 73 ++++++++++++++++++++++++++++++++++++++++ admin/team.go | 69 ++++++++++++++++++++++++++++++++++++++ admin/theme.go | 69 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 450 insertions(+), 2 deletions(-) create mode 100644 admin/exercice.go create mode 100644 admin/file.go create mode 100644 admin/key.go create mode 100644 admin/member.go create mode 100644 admin/team.go create mode 100644 admin/theme.go diff --git a/admin/api.go b/admin/api.go index 349d5181..0dd72256 100644 --- a/admin/api.go +++ b/admin/api.go @@ -13,8 +13,8 @@ type DispatchFunction func([]string, []byte) (interface{}, error) var apiRouting = map[string]*(map[string]DispatchFunction){ "version": &ApiVersionRouting, - //"images": &ApiImagesRouting, - //"users": &ApiUsersRouting, + //"themes": &ApiThemesRouting, + //"teams": &ApiTeamsRouting, } func ApiRouting(w http.ResponseWriter, r *http.Request) { diff --git a/admin/exercice.go b/admin/exercice.go new file mode 100644 index 00000000..988ec192 --- /dev/null +++ b/admin/exercice.go @@ -0,0 +1,83 @@ +package main + +import ( + "time" +) + +type Exercice struct { + id int64 + Title string + Statement string + Hint string + depend int64 + Gain int64 + VideoURI string +} + +func (t Theme) GetExercices() ([]Exercice, error) { + if rows, err := DBQuery("SELECT id_exercice, title, statement, hint, depend, gain, video_uri FROM teams WHERE id_theme = ?", t.id); err != nil { + return nil, err + } else { + defer rows.Close() + + var exos = make([]Exercice, 0) + for rows.Next() { + var e Exercice + if err := rows.Scan(&e.id, &e.Title, &e.Statement, &e.Hint, &e.depend, &e.Gain, &e.VideoURI); err != nil { + return nil, err + } + exos = append(exos, e) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return exos, nil + } +} + +func (t Theme) AddExercice(title string, statement string, hint string, depend *Exercice, gain int, videoURI string) (Exercice, error) { + if res, err := DBExec("INSERT INTO exercices (id_theme, title, statement, hint, depend, gain, video_uri) VALUES (?, ?, ?, ?, ?, ?, ?)", t.id, title, statement, hint, depend.id, gain, videoURI); err != nil { + return Exercice{}, err + } else if eid, err := res.LastInsertId(); err != nil { + return Exercice{}, err + } else { + return Exercice{eid, title, statement, hint, depend.id, int64(gain), videoURI}, nil + } +} + +func (e Exercice) Update() (int64, error) { + if res, err := DBExec("UPDATE exercices SET title = ?, statement = ?, hint = ?, depend = ?, gain = ?, video_uri = ? WHERE id_exercice = ?", e.Title, e.Statement, e.Hint, e.depend, e.Gain, e.VideoURI, e.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (e Exercice) Delete() (int64, error) { + if res, err := DBExec("DELETE FROM exercices WHERE id_exercice = ?", e.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (e Exercice) NewTry(t Team) error { + if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time) VALUES (?, ?, ?)", e.id, t.id, time.Now()); err != nil { + return err + } else { + return nil + } +} + +func (e Exercice) Solved(t Team) error { + if _, err := DBExec("INSERT INTO exercice_solved (id_exercice, id_team, time) VALUES (?, ?, ?)", e.id, t.id, time.Now()); err != nil { + return err + } else { + return nil + } +} diff --git a/admin/file.go b/admin/file.go new file mode 100644 index 00000000..82728ef4 --- /dev/null +++ b/admin/file.go @@ -0,0 +1,85 @@ +package main + +import ( + "crypto/sha1" + "io" + "os" + "path" +) + +type EFile struct { + id int64 + Path string + id_exercice int64 + Name string + Checksum []byte +} + +func (e Exercice) GetFiles() ([]EFile, error) { + if rows, err := DBQuery("SELECT id_file, path, name, sha1 FROM exercice_files WHERE id_exercice = ?", e.id); err != nil { + return nil, err + } else { + defer rows.Close() + + var files = make([]EFile, 0) + for rows.Next() { + var f EFile + f.id_exercice = e.id + if err := rows.Scan(&f.id, &f.Path, &f.Name, &f.Checksum); err != nil { + return nil, err + } + files = append(files, f) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return files, nil + } +} + +func (e Exercice) ImportFile(filePath string) (EFile, error) { + if fd, err := os.Open(filePath); err != nil { + return EFile{}, err + } else { + defer fd.Close() + + hash := sha1.New() + if _, err := io.Copy(hash, fd); err != nil { + return EFile{}, err + } + + var result []byte + return e.AddFile(filePath, path.Base(filePath), hash.Sum(result)) + } +} + +func (e Exercice) AddFile(path string, name string, checksum []byte) (EFile, error) { + if res, err := DBExec("INSERT INTO exercice_files (id_exercice, path, name, sha1) VALUES (?, ?, ?, ?)", e.id, path, name, checksum); err != nil { + return EFile{}, err + } else if fid, err := res.LastInsertId(); err != nil { + return EFile{}, err + } else { + return EFile{fid, path, e.id, name, checksum}, nil + } +} + +func (f EFile) Update() (int64, error) { + if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, path = ?, name = ?, sha1 = ? WHERE id_file = ?", f.id_exercice, f.Path, f.Name, f.Checksum, f.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (f EFile) Delete() (int64, error) { + if res, err := DBExec("DELETE FROM exercice_files WHERE id_file = ?", f.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} diff --git a/admin/key.go b/admin/key.go new file mode 100644 index 00000000..3052ddb7 --- /dev/null +++ b/admin/key.go @@ -0,0 +1,69 @@ +package main + +import ( + "crypto/sha512" +) + +type Key struct { + id int64 + id_exercice int64 + Type string + Value [64]byte +} + +func (e Exercice) GetKeys() ([]Key, error) { + if rows, err := DBQuery("SELECT id_key, type, value FROM exercice_keys WHERE id_exercice = ?", e.id); err != nil { + return nil, err + } else { + defer rows.Close() + + var keys = make([]Key, 0) + for rows.Next() { + var k Key + k.id_exercice = e.id + if err := rows.Scan(&k.id, &k.id_exercice, &k.Type, &k.Value); err != nil { + return nil, err + } + keys = append(keys, k) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return keys, nil + } +} + +func (e Exercice) AddRawKey(name string, raw_value string) (Key, error) { + return e.AddKey(name, sha512.Sum512([]byte(raw_value))) +} + +func (e Exercice) AddKey(name string, value [64]byte) (Key, error) { + if res, err := DBExec("INSERT INTO exercice_keys (id_exercice, type, value) VALUES (?, ?, ?)", e.id, name, value); err != nil { + return Key{}, err + } else if kid, err := res.LastInsertId(); err != nil { + return Key{}, err + } else { + return Key{kid, e.id, name, value}, nil + } +} + +func (k Key) Update() (int64, error) { + if res, err := DBExec("UPDATE exercice_keys SET id_exercice = ?, type = ?, value = ? WHERE id_key = ?", k.id_exercice, k.Type, k.Value, k.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (k Key) Delete() (int64, error) { + if res, err := DBExec("DELETE FROM exercice_keys WHERE id_key = ?", k.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} diff --git a/admin/member.go b/admin/member.go new file mode 100644 index 00000000..5de67e41 --- /dev/null +++ b/admin/member.go @@ -0,0 +1,73 @@ +package main + +import () + +type Member struct { + id int64 + Firstname string + Lastname string + Nickname string + Company string +} + +func (t Team) GetMembers() ([]Member, error) { + if rows, err := DBQuery("SELECT id_member, firstname, lastname, nickname, company FROM team_members WHERE id_team = ?", t.id); err != nil { + return nil, err + } else { + defer rows.Close() + + var members = make([]Member, 0) + for rows.Next() { + var m Member + if err := rows.Scan(&m.id, &m.Firstname, &m.Lastname, &m.Nickname, &m.Company); err != nil { + return nil, err + } + members = append(members, m) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return members, nil + } +} + +func (t Team) AddMember(firstname string, lastname string, nickname string, company string) (Member, error) { + if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.id, firstname, lastname, nickname, company); err != nil { + return Member{}, err + } else if mid, err := res.LastInsertId(); err != nil { + return Member{}, err + } else { + return Member{mid, firstname, lastname, nickname, company}, nil + } +} + +func (t Team) GainMember(m Member) error { + if res, err := DBExec("UPDATE team_members SET id_team = ? WHERE id_member = ?", t.id, m.id); err != nil { + return err + } else if _, err := res.RowsAffected(); err != nil { + return err + } else { + return nil + } +} + +func (m Member) Update() (int64, error) { + if res, err := DBExec("UPDATE team_members SET firstname = ?, lastname = ?, nickname = ?, company = ? WHERE id_member = ?", m.Firstname, m.Lastname, m.Nickname, m.Company, m.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (m Member) Delete() (int64, error) { + if res, err := DBExec("DELETE FROM team_members WHERE id_member = ?", m.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} diff --git a/admin/team.go b/admin/team.go new file mode 100644 index 00000000..4cc13a5b --- /dev/null +++ b/admin/team.go @@ -0,0 +1,69 @@ +package main + +import () + +type Team struct { + id int64 + Name string +} + +func GetTeams() ([]Team, error) { + if rows, err := DBQuery("SELECT id_team, name FROM teams"); err != nil { + return nil, err + } else { + defer rows.Close() + + var teams = make([]Team, 0) + for rows.Next() { + var t Team + if err := rows.Scan(&t.id, &t.Name); err != nil { + return nil, err + } + teams = append(teams, t) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return teams, nil + } +} + +func GetTeam(id int) (Team, error) { + var t Team + if err := DBQueryRow("SELECT id_team, name FROM teams WHERE id_team = ?", id).Scan(&t.id, &t.Name); err != nil { + return t, err + } + + return t, nil +} + +func CreateTeam(name string) (Team, error) { + if res, err := DBExec("INSERT INTO teams (name) VALUES (?)", name); err != nil { + return Team{}, err + } else if tid, err := res.LastInsertId(); err != nil { + return Team{}, err + } else { + return Team{tid, name}, nil + } +} + +func (t Team) Update() (int64, error) { + if res, err := DBExec("UPDATE teams SET name = ? WHERE id_team = ?", t.Name, t.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (t Team) Delete() (int64, error) { + if res, err := DBExec("DELETE FROM teams WHERE id_teams = ?", t.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} diff --git a/admin/theme.go b/admin/theme.go new file mode 100644 index 00000000..dbe15a30 --- /dev/null +++ b/admin/theme.go @@ -0,0 +1,69 @@ +package main + +import () + +type Theme struct { + id int64 + Name string +} + +func GetThemes() ([]Theme, error) { + if rows, err := DBQuery("SELECT id_theme, name FROM themes"); err != nil { + return nil, err + } else { + defer rows.Close() + + var themes = make([]Theme, 0) + for rows.Next() { + var t Theme + if err := rows.Scan(&t.id, &t.Name); err != nil { + return nil, err + } + themes = append(themes, t) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return themes, nil + } +} + +func GetTheme(id int) (Theme, error) { + var t Theme + if err := DBQueryRow("SELECT id_theme, name FROM themes WHERE id_theme=?", id).Scan(&t.id, &t.Name); err != nil { + return t, err + } + + return t, nil +} + +func CreateTheme(name string) (Theme, error) { + if res, err := DBExec("INSERT INTO themes (name) VALUES (?)", name); err != nil { + return Theme{}, err + } else if tid, err := res.LastInsertId(); err != nil { + return Theme{}, err + } else { + return Theme{tid, name}, nil + } +} + +func (t Theme) Update() (int64, error) { + if res, err := DBExec("UPDATE themes SET name = ? WHERE id_team = ?", t.Name, t.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} + +func (t Theme) Delete() (int64, error) { + if res, err := DBExec("DELETE FROM themes WHERE id_theme = ?", t.id); err != nil { + return 0, err + } else if nb, err := res.RowsAffected(); err != nil { + return 0, err + } else { + return nb, err + } +} From 5a6bac928eef0efcb8375536bfaf0a04ad3e0a54 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 7 Jan 2016 20:08:48 +0100 Subject: [PATCH 0284/2585] Add team listing --- admin/api.go | 2 +- admin/api_team.go | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 admin/api_team.go diff --git a/admin/api.go b/admin/api.go index 0dd72256..647a883c 100644 --- a/admin/api.go +++ b/admin/api.go @@ -14,7 +14,7 @@ type DispatchFunction func([]string, []byte) (interface{}, error) var apiRouting = map[string]*(map[string]DispatchFunction){ "version": &ApiVersionRouting, //"themes": &ApiThemesRouting, - //"teams": &ApiTeamsRouting, + "teams": &ApiTeamsRouting, } func ApiRouting(w http.ResponseWriter, r *http.Request) { diff --git a/admin/api_team.go b/admin/api_team.go new file mode 100644 index 00000000..450d852a --- /dev/null +++ b/admin/api_team.go @@ -0,0 +1,27 @@ +package main + +import ( + "strconv" +) + +var ApiTeamsRouting = map[string]DispatchFunction{ + "GET": list, +} + +func list(args []string, body []byte) (interface{}, error) { + if len(args) == 1 { + // List given team + if tid, err := strconv.Atoi(string(args[0])); err != nil { + return nil, err + } else if team, err := GetTeam(tid); err != nil { + return nil, err + } else { + return team.GetMembers() + } + } else if len(args) == 0 { + // List all teams + return GetTeams() + } else { + return nil, nil + } +} From b958b01635d4fa1a8783041562aeccfc9144c10b Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 7 Jan 2016 20:32:24 +0100 Subject: [PATCH 0285/2585] Implement team creation --- admin/api_team.go | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/admin/api_team.go b/admin/api_team.go index 450d852a..63efa416 100644 --- a/admin/api_team.go +++ b/admin/api_team.go @@ -1,14 +1,16 @@ package main import ( + "encoding/json" "strconv" ) var ApiTeamsRouting = map[string]DispatchFunction{ - "GET": list, + "GET": listTeam, + "POST": creationTeam, } -func list(args []string, body []byte) (interface{}, error) { +func listTeam(args []string, body []byte) (interface{}, error) { if len(args) == 1 { // List given team if tid, err := strconv.Atoi(string(args[0])); err != nil { @@ -25,3 +27,34 @@ func list(args []string, body []byte) (interface{}, error) { return nil, nil } } + +func creationTeam(args []string, body []byte) (interface{}, error) { + if len(args) == 0 { + type UploadedMember struct { + Firstname string + Lastname string + Nickname string + Company string + } + + // Create a new team + var members []UploadedMember + if err := json.Unmarshal(body, &members); err != nil { + return nil, err + } + + if team, err := CreateTeam(""); err != nil { + return nil, err + } else { + for _, member := range members { + if _, err := team.AddMember(member.Firstname, member.Lastname, member.Nickname, member.Company); err != nil { + return nil, err + } + } + + return "Ok", nil + } + } else { + return nil,nil + } +} From 40f7d7a0be2ae1f80a9c45ac585c62ad1a76274f Mon Sep 17 00:00:00 2001 From: nemunaire Date: Thu, 7 Jan 2016 20:47:07 +0100 Subject: [PATCH 0286/2585] Add theme listing --- admin/api.go | 2 +- admin/api_theme.go | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 admin/api_theme.go diff --git a/admin/api.go b/admin/api.go index 647a883c..3e024278 100644 --- a/admin/api.go +++ b/admin/api.go @@ -13,7 +13,7 @@ type DispatchFunction func([]string, []byte) (interface{}, error) var apiRouting = map[string]*(map[string]DispatchFunction){ "version": &ApiVersionRouting, - //"themes": &ApiThemesRouting, + "themes": &ApiThemesRouting, "teams": &ApiTeamsRouting, } diff --git a/admin/api_theme.go b/admin/api_theme.go new file mode 100644 index 00000000..52d8d429 --- /dev/null +++ b/admin/api_theme.go @@ -0,0 +1,25 @@ +package main + +import ( + "strconv" +) + +var ApiThemesRouting = map[string]DispatchFunction{ + "GET": listTheme, +} + +func listTheme(args []string, body []byte) (interface{}, error) { + if len(args) == 1 { + // List given theme + if tid, err := strconv.Atoi(string(args[0])); err != nil { + return nil, err + } else { + return GetTheme(tid) + } + } else if len(args) == 0 { + // List all themes + return GetThemes() + } else { + return nil, nil + } +} From 8cf2a36fe10f7737a0d72ba6bcf17c385e731f31 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 13 Jan 2016 01:12:36 +0100 Subject: [PATCH 0287/2585] Implement team deletion --- admin/api_team.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/admin/api_team.go b/admin/api_team.go index 63efa416..89ec6c24 100644 --- a/admin/api_team.go +++ b/admin/api_team.go @@ -8,6 +8,7 @@ import ( var ApiTeamsRouting = map[string]DispatchFunction{ "GET": listTeam, "POST": creationTeam, + "DELETE": deletionTeam, } func listTeam(args []string, body []byte) (interface{}, error) { @@ -58,3 +59,17 @@ func creationTeam(args []string, body []byte) (interface{}, error) { return nil,nil } } + +func deletionTeam(args []string, body []byte) (interface{}, error) { + if len(args) == 1 { + if tid, err := strconv.Atoi(string(args[0])); err != nil { + return nil, err + } else if team, err := GetTeam(tid); err != nil { + return nil, err + } else { + return team.Delete() + } + } else { + return nil, nil + } +} From e89af34c5c21d738e25014983429f983cb89bcea Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 13 Jan 2016 01:20:21 +0100 Subject: [PATCH 0288/2585] Change internal variable representation vs JSON one --- admin/exercice.go | 30 +++++++++++++++--------------- admin/file.go | 24 ++++++++++++------------ admin/key.go | 22 +++++++++++----------- admin/member.go | 22 +++++++++++----------- admin/team.go | 12 ++++++------ admin/theme.go | 12 ++++++------ 6 files changed, 61 insertions(+), 61 deletions(-) diff --git a/admin/exercice.go b/admin/exercice.go index 988ec192..b7bb1f56 100644 --- a/admin/exercice.go +++ b/admin/exercice.go @@ -5,17 +5,17 @@ import ( ) type Exercice struct { - id int64 - Title string - Statement string - Hint string - depend int64 - Gain int64 - VideoURI string + Id int64 `json:"id"` + Title string `json:"title"` + Statement string `json:"statement"` + Hint string `json:"hint"` + Depend int64 `json:"depend"` + Gain int64 `json:"gain"` + VideoURI string `json:"videoURI"` } func (t Theme) GetExercices() ([]Exercice, error) { - if rows, err := DBQuery("SELECT id_exercice, title, statement, hint, depend, gain, video_uri FROM teams WHERE id_theme = ?", t.id); err != nil { + if rows, err := DBQuery("SELECT id_exercice, title, statement, hint, depend, gain, video_uri FROM teams WHERE id_theme = ?", t.Id); err != nil { return nil, err } else { defer rows.Close() @@ -23,7 +23,7 @@ func (t Theme) GetExercices() ([]Exercice, error) { var exos = make([]Exercice, 0) for rows.Next() { var e Exercice - if err := rows.Scan(&e.id, &e.Title, &e.Statement, &e.Hint, &e.depend, &e.Gain, &e.VideoURI); err != nil { + if err := rows.Scan(&e.Id, &e.Title, &e.Statement, &e.Hint, &e.Depend, &e.Gain, &e.VideoURI); err != nil { return nil, err } exos = append(exos, e) @@ -37,17 +37,17 @@ func (t Theme) GetExercices() ([]Exercice, error) { } func (t Theme) AddExercice(title string, statement string, hint string, depend *Exercice, gain int, videoURI string) (Exercice, error) { - if res, err := DBExec("INSERT INTO exercices (id_theme, title, statement, hint, depend, gain, video_uri) VALUES (?, ?, ?, ?, ?, ?, ?)", t.id, title, statement, hint, depend.id, gain, videoURI); err != nil { + if res, err := DBExec("INSERT INTO exercices (id_theme, title, statement, hint, depend, gain, video_uri) VALUES (?, ?, ?, ?, ?, ?, ?)", t.Id, title, statement, hint, depend.Id, gain, videoURI); err != nil { return Exercice{}, err } else if eid, err := res.LastInsertId(); err != nil { return Exercice{}, err } else { - return Exercice{eid, title, statement, hint, depend.id, int64(gain), videoURI}, nil + return Exercice{eid, title, statement, hint, depend.Id, int64(gain), videoURI}, nil } } func (e Exercice) Update() (int64, error) { - if res, err := DBExec("UPDATE exercices SET title = ?, statement = ?, hint = ?, depend = ?, gain = ?, video_uri = ? WHERE id_exercice = ?", e.Title, e.Statement, e.Hint, e.depend, e.Gain, e.VideoURI, e.id); err != nil { + if res, err := DBExec("UPDATE exercices SET title = ?, statement = ?, hint = ?, depend = ?, gain = ?, video_uri = ? WHERE id_exercice = ?", e.Title, e.Statement, e.Hint, e.Depend, e.Gain, e.VideoURI, e.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -57,7 +57,7 @@ func (e Exercice) Update() (int64, error) { } func (e Exercice) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM exercices WHERE id_exercice = ?", e.id); err != nil { + if res, err := DBExec("DELETE FROM exercices WHERE id_exercice = ?", e.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -67,7 +67,7 @@ func (e Exercice) Delete() (int64, error) { } func (e Exercice) NewTry(t Team) error { - if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time) VALUES (?, ?, ?)", e.id, t.id, time.Now()); err != nil { + if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time) VALUES (?, ?, ?)", e.Id, t.Id, time.Now()); err != nil { return err } else { return nil @@ -75,7 +75,7 @@ func (e Exercice) NewTry(t Team) error { } func (e Exercice) Solved(t Team) error { - if _, err := DBExec("INSERT INTO exercice_solved (id_exercice, id_team, time) VALUES (?, ?, ?)", e.id, t.id, time.Now()); err != nil { + if _, err := DBExec("INSERT INTO exercice_solved (id_exercice, id_team, time) VALUES (?, ?, ?)", e.Id, t.Id, time.Now()); err != nil { return err } else { return nil diff --git a/admin/file.go b/admin/file.go index 82728ef4..b1255fda 100644 --- a/admin/file.go +++ b/admin/file.go @@ -8,15 +8,15 @@ import ( ) type EFile struct { - id int64 - Path string - id_exercice int64 - Name string - Checksum []byte + Id int64 `json:"id"` + Path string `json:"path"` + IdExercice int64 `json:"idExercice"` + Name string `json:"name"` + Checksum []byte `json:"checksum"` } func (e Exercice) GetFiles() ([]EFile, error) { - if rows, err := DBQuery("SELECT id_file, path, name, sha1 FROM exercice_files WHERE id_exercice = ?", e.id); err != nil { + if rows, err := DBQuery("SELECT id_file, path, name, sha1 FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil { return nil, err } else { defer rows.Close() @@ -24,8 +24,8 @@ func (e Exercice) GetFiles() ([]EFile, error) { var files = make([]EFile, 0) for rows.Next() { var f EFile - f.id_exercice = e.id - if err := rows.Scan(&f.id, &f.Path, &f.Name, &f.Checksum); err != nil { + f.IdExercice = e.Id + if err := rows.Scan(&f.Id, &f.Path, &f.Name, &f.Checksum); err != nil { return nil, err } files = append(files, f) @@ -55,17 +55,17 @@ func (e Exercice) ImportFile(filePath string) (EFile, error) { } func (e Exercice) AddFile(path string, name string, checksum []byte) (EFile, error) { - if res, err := DBExec("INSERT INTO exercice_files (id_exercice, path, name, sha1) VALUES (?, ?, ?, ?)", e.id, path, name, checksum); err != nil { + if res, err := DBExec("INSERT INTO exercice_files (id_exercice, path, name, sha1) VALUES (?, ?, ?, ?)", e.Id, path, name, checksum); err != nil { return EFile{}, err } else if fid, err := res.LastInsertId(); err != nil { return EFile{}, err } else { - return EFile{fid, path, e.id, name, checksum}, nil + return EFile{fid, path, e.Id, name, checksum}, nil } } func (f EFile) Update() (int64, error) { - if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, path = ?, name = ?, sha1 = ? WHERE id_file = ?", f.id_exercice, f.Path, f.Name, f.Checksum, f.id); err != nil { + if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, path = ?, name = ?, sha1 = ? WHERE id_file = ?", f.IdExercice, f.Path, f.Name, f.Checksum, f.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -75,7 +75,7 @@ func (f EFile) Update() (int64, error) { } func (f EFile) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM exercice_files WHERE id_file = ?", f.id); err != nil { + if res, err := DBExec("DELETE FROM exercice_files WHERE id_file = ?", f.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err diff --git a/admin/key.go b/admin/key.go index 3052ddb7..a39f2cf6 100644 --- a/admin/key.go +++ b/admin/key.go @@ -5,14 +5,14 @@ import ( ) type Key struct { - id int64 - id_exercice int64 - Type string - Value [64]byte + Id int64 `json:"id"` + IdExercice int64 `json:"idExercice"` + Type string `json:"type"` + Value [64]byte `json:"value"` } func (e Exercice) GetKeys() ([]Key, error) { - if rows, err := DBQuery("SELECT id_key, type, value FROM exercice_keys WHERE id_exercice = ?", e.id); err != nil { + if rows, err := DBQuery("SELECT id_key, type, value FROM exercice_keys WHERE id_exercice = ?", e.Id); err != nil { return nil, err } else { defer rows.Close() @@ -20,8 +20,8 @@ func (e Exercice) GetKeys() ([]Key, error) { var keys = make([]Key, 0) for rows.Next() { var k Key - k.id_exercice = e.id - if err := rows.Scan(&k.id, &k.id_exercice, &k.Type, &k.Value); err != nil { + k.IdExercice = e.Id + if err := rows.Scan(&k.Id, &k.IdExercice, &k.Type, &k.Value); err != nil { return nil, err } keys = append(keys, k) @@ -39,17 +39,17 @@ func (e Exercice) AddRawKey(name string, raw_value string) (Key, error) { } func (e Exercice) AddKey(name string, value [64]byte) (Key, error) { - if res, err := DBExec("INSERT INTO exercice_keys (id_exercice, type, value) VALUES (?, ?, ?)", e.id, name, value); err != nil { + if res, err := DBExec("INSERT INTO exercice_keys (id_exercice, type, value) VALUES (?, ?, ?)", e.Id, name, value); err != nil { return Key{}, err } else if kid, err := res.LastInsertId(); err != nil { return Key{}, err } else { - return Key{kid, e.id, name, value}, nil + return Key{kid, e.Id, name, value}, nil } } func (k Key) Update() (int64, error) { - if res, err := DBExec("UPDATE exercice_keys SET id_exercice = ?, type = ?, value = ? WHERE id_key = ?", k.id_exercice, k.Type, k.Value, k.id); err != nil { + if res, err := DBExec("UPDATE exercice_keys SET id_exercice = ?, type = ?, value = ? WHERE id_key = ?", k.IdExercice, k.Type, k.Value, k.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -59,7 +59,7 @@ func (k Key) Update() (int64, error) { } func (k Key) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM exercice_keys WHERE id_key = ?", k.id); err != nil { + if res, err := DBExec("DELETE FROM exercice_keys WHERE id_key = ?", k.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err diff --git a/admin/member.go b/admin/member.go index 5de67e41..2e17d1d9 100644 --- a/admin/member.go +++ b/admin/member.go @@ -3,15 +3,15 @@ package main import () type Member struct { - id int64 - Firstname string - Lastname string - Nickname string - Company string + Id int64 `json:"id"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` + Nickname string `json:"nickname"` + Company string `json:"company"` } func (t Team) GetMembers() ([]Member, error) { - if rows, err := DBQuery("SELECT id_member, firstname, lastname, nickname, company FROM team_members WHERE id_team = ?", t.id); err != nil { + if rows, err := DBQuery("SELECT id_member, firstname, lastname, nickname, company FROM team_members WHERE id_team = ?", t.Id); err != nil { return nil, err } else { defer rows.Close() @@ -19,7 +19,7 @@ func (t Team) GetMembers() ([]Member, error) { var members = make([]Member, 0) for rows.Next() { var m Member - if err := rows.Scan(&m.id, &m.Firstname, &m.Lastname, &m.Nickname, &m.Company); err != nil { + if err := rows.Scan(&m.Id, &m.Firstname, &m.Lastname, &m.Nickname, &m.Company); err != nil { return nil, err } members = append(members, m) @@ -33,7 +33,7 @@ func (t Team) GetMembers() ([]Member, error) { } func (t Team) AddMember(firstname string, lastname string, nickname string, company string) (Member, error) { - if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.id, firstname, lastname, nickname, company); err != nil { + if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.Id, firstname, lastname, nickname, company); err != nil { return Member{}, err } else if mid, err := res.LastInsertId(); err != nil { return Member{}, err @@ -43,7 +43,7 @@ func (t Team) AddMember(firstname string, lastname string, nickname string, comp } func (t Team) GainMember(m Member) error { - if res, err := DBExec("UPDATE team_members SET id_team = ? WHERE id_member = ?", t.id, m.id); err != nil { + if res, err := DBExec("UPDATE team_members SET id_team = ? WHERE id_member = ?", t.Id, m.Id); err != nil { return err } else if _, err := res.RowsAffected(); err != nil { return err @@ -53,7 +53,7 @@ func (t Team) GainMember(m Member) error { } func (m Member) Update() (int64, error) { - if res, err := DBExec("UPDATE team_members SET firstname = ?, lastname = ?, nickname = ?, company = ? WHERE id_member = ?", m.Firstname, m.Lastname, m.Nickname, m.Company, m.id); err != nil { + if res, err := DBExec("UPDATE team_members SET firstname = ?, lastname = ?, nickname = ?, company = ? WHERE id_member = ?", m.Firstname, m.Lastname, m.Nickname, m.Company, m.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -63,7 +63,7 @@ func (m Member) Update() (int64, error) { } func (m Member) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM team_members WHERE id_member = ?", m.id); err != nil { + if res, err := DBExec("DELETE FROM team_members WHERE id_member = ?", m.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err diff --git a/admin/team.go b/admin/team.go index 4cc13a5b..f1a42f69 100644 --- a/admin/team.go +++ b/admin/team.go @@ -3,8 +3,8 @@ package main import () type Team struct { - id int64 - Name string + Id int64 `json:"id"` + Name string `json:"name"` } func GetTeams() ([]Team, error) { @@ -16,7 +16,7 @@ func GetTeams() ([]Team, error) { var teams = make([]Team, 0) for rows.Next() { var t Team - if err := rows.Scan(&t.id, &t.Name); err != nil { + if err := rows.Scan(&t.Id, &t.Name); err != nil { return nil, err } teams = append(teams, t) @@ -31,7 +31,7 @@ func GetTeams() ([]Team, error) { func GetTeam(id int) (Team, error) { var t Team - if err := DBQueryRow("SELECT id_team, name FROM teams WHERE id_team = ?", id).Scan(&t.id, &t.Name); err != nil { + if err := DBQueryRow("SELECT id_team, name FROM teams WHERE id_team = ?", id).Scan(&t.Id, &t.Name); err != nil { return t, err } @@ -49,7 +49,7 @@ func CreateTeam(name string) (Team, error) { } func (t Team) Update() (int64, error) { - if res, err := DBExec("UPDATE teams SET name = ? WHERE id_team = ?", t.Name, t.id); err != nil { + if res, err := DBExec("UPDATE teams SET name = ? WHERE id_team = ?", t.Name, t.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -59,7 +59,7 @@ func (t Team) Update() (int64, error) { } func (t Team) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM teams WHERE id_teams = ?", t.id); err != nil { + if res, err := DBExec("DELETE FROM team_members WHERE id_team = ?; DELETE FROM teams WHERE id_team = ?", t.Id, t.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err diff --git a/admin/theme.go b/admin/theme.go index dbe15a30..5ca0b34e 100644 --- a/admin/theme.go +++ b/admin/theme.go @@ -3,8 +3,8 @@ package main import () type Theme struct { - id int64 - Name string + Id int64 `json:"id"` + Name string `json:"name"` } func GetThemes() ([]Theme, error) { @@ -16,7 +16,7 @@ func GetThemes() ([]Theme, error) { var themes = make([]Theme, 0) for rows.Next() { var t Theme - if err := rows.Scan(&t.id, &t.Name); err != nil { + if err := rows.Scan(&t.Id, &t.Name); err != nil { return nil, err } themes = append(themes, t) @@ -31,7 +31,7 @@ func GetThemes() ([]Theme, error) { func GetTheme(id int) (Theme, error) { var t Theme - if err := DBQueryRow("SELECT id_theme, name FROM themes WHERE id_theme=?", id).Scan(&t.id, &t.Name); err != nil { + if err := DBQueryRow("SELECT id_theme, name FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name); err != nil { return t, err } @@ -49,7 +49,7 @@ func CreateTheme(name string) (Theme, error) { } func (t Theme) Update() (int64, error) { - if res, err := DBExec("UPDATE themes SET name = ? WHERE id_team = ?", t.Name, t.id); err != nil { + if res, err := DBExec("UPDATE themes SET name = ? WHERE id_team = ?", t.Name, t.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -59,7 +59,7 @@ func (t Theme) Update() (int64, error) { } func (t Theme) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM themes WHERE id_theme = ?", t.id); err != nil { + if res, err := DBExec("DELETE FROM themes WHERE id_theme = ?", t.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err From d635420a9f69bb45dc23c3ba461890b9784b8db5 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 13 Jan 2016 01:22:01 +0100 Subject: [PATCH 0289/2585] Add static page routing, place API under /api/ --- admin/api.go | 22 ++++++++++++++-------- admin/main.go | 7 ++++++- admin/static.go | 9 +++++++++ 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 admin/static.go diff --git a/admin/api.go b/admin/api.go index 3e024278..8ee191f4 100644 --- a/admin/api.go +++ b/admin/api.go @@ -11,18 +11,24 @@ import ( type DispatchFunction func([]string, []byte) (interface{}, error) -var apiRouting = map[string]*(map[string]DispatchFunction){ +var apiRoutes = map[string]*(map[string]DispatchFunction){ "version": &ApiVersionRouting, "themes": &ApiThemesRouting, "teams": &ApiTeamsRouting, } -func ApiRouting(w http.ResponseWriter, r *http.Request) { +type apiRouting struct{} + +func ApiHandler() http.Handler { + return apiRouting{} +} + +func (a apiRouting) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) // Extract URL arguments - var sURL = strings.Split(r.URL.Path, "/") - if sURL[len(sURL)-1] == "" && len(sURL) > 2 { + var sURL = strings.Split(r.URL.Path, "/")[1:] + if len(sURL) > 1 && sURL[len(sURL)-1] == "" { // Remove trailing / sURL = sURL[:len(sURL)-1] } @@ -52,12 +58,12 @@ func ApiRouting(w http.ResponseWriter, r *http.Request) { } // Route request - if len(sURL) > 1 { - if h, ok := apiRouting[sURL[1]]; ok { + if len(sURL) > 0 { + if h, ok := apiRoutes[sURL[0]]; ok { if f, ok := (*h)[r.Method]; ok { - ret, err = f(sURL[2:], body) + ret, err = f(sURL[1:], body) } else { - err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[1])) + err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[0])) } } } else { diff --git a/admin/main.go b/admin/main.go index 1979ca64..6277cef4 100644 --- a/admin/main.go +++ b/admin/main.go @@ -34,7 +34,12 @@ func main() { } log.Println("Registering handlers...") - http.HandleFunc("/", ApiRouting) + mux := http.NewServeMux() + mux.Handle("/api/", http.StripPrefix("/api", ApiHandler())) + mux.HandleFunc("/teams", StaticRouting) + mux.HandleFunc("/themes", StaticRouting) + mux.Handle("/", http.FileServer(http.Dir("./static/"))) + http.HandleFunc("/", mux.ServeHTTP) log.Println(fmt.Sprintf("Ready, listening on %s", *bind)) if err := http.ListenAndServe(*bind, nil); err != nil { diff --git a/admin/static.go b/admin/static.go new file mode 100644 index 00000000..f82ab08b --- /dev/null +++ b/admin/static.go @@ -0,0 +1,9 @@ +package main + +import ( + "net/http" +) + +func StaticRouting(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "./static/index.html") +} From 181953a9f03fd54c017c24b991693be3960a2a41 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 13 Jan 2016 01:22:54 +0100 Subject: [PATCH 0290/2585] Work on admin web interface --- admin/static/css/bootstrap.min.css | 6 + admin/static/css/slate.min.css | 11 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 +++++++++++++++++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes admin/static/index.html | 27 ++ admin/static/js/angular-resource.min.js | 14 + admin/static/js/angular-route.min.js | 15 + admin/static/js/angular.min.js | 295 ++++++++++++++++++ admin/static/js/app.js | 33 ++ admin/static/js/bootstrap.min.js | 7 + admin/static/js/jquery.min.js | 5 + admin/static/views/team-list.html | 17 + admin/static/views/team-new.html | 11 + 16 files changed, 729 insertions(+) create mode 100644 admin/static/css/bootstrap.min.css create mode 100644 admin/static/css/slate.min.css create mode 100644 admin/static/fonts/glyphicons-halflings-regular.eot create mode 100644 admin/static/fonts/glyphicons-halflings-regular.svg create mode 100644 admin/static/fonts/glyphicons-halflings-regular.ttf create mode 100644 admin/static/fonts/glyphicons-halflings-regular.woff create mode 100644 admin/static/fonts/glyphicons-halflings-regular.woff2 create mode 100644 admin/static/index.html create mode 100644 admin/static/js/angular-resource.min.js create mode 100644 admin/static/js/angular-route.min.js create mode 100644 admin/static/js/angular.min.js create mode 100644 admin/static/js/app.js create mode 100644 admin/static/js/bootstrap.min.js create mode 100644 admin/static/js/jquery.min.js create mode 100644 admin/static/views/team-list.html create mode 100644 admin/static/views/team-new.html diff --git a/admin/static/css/bootstrap.min.css b/admin/static/css/bootstrap.min.css new file mode 100644 index 00000000..4cf729e4 --- /dev/null +++ b/admin/static/css/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/admin/static/css/slate.min.css b/admin/static/css/slate.min.css new file mode 100644 index 00000000..af7e2033 --- /dev/null +++ b/admin/static/css/slate.min.css @@ -0,0 +1,11 @@ +/*! + * bootswatch v3.3.6 + * Homepage: http://bootswatch.com + * Copyright 2012-2015 Thomas Park + * Licensed under MIT + * Based on Bootstrap +*//*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;-webkit-box-shadow:none !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#c8c8c8;background-color:#272b30}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#ffffff;text-decoration:none}a:hover,a:focus{color:#ffffff;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#1c1e22;border:1px solid #0c0d0e;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #1c1e22}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#7a8288}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#f89406;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#7a8288}.text-primary{color:#7a8288}a.text-primary:hover,a.text-primary:focus{color:#62686d}.text-success{color:#ffffff}a.text-success:hover,a.text-success:focus{color:#e6e6e6}.text-info{color:#ffffff}a.text-info:hover,a.text-info:focus{color:#e6e6e6}.text-warning{color:#ffffff}a.text-warning:hover,a.text-warning:focus{color:#e6e6e6}.text-danger{color:#ffffff}a.text-danger:hover,a.text-danger:focus{color:#e6e6e6}.bg-primary{color:#fff;background-color:#7a8288}a.bg-primary:hover,a.bg-primary:focus{background-color:#62686d}.bg-success{background-color:#62c462}a.bg-success:hover,a.bg-success:focus{background-color:#42b142}.bg-info{background-color:#5bc0de}a.bg-info:hover,a.bg-info:focus{background-color:#31b0d5}.bg-warning{background-color:#f89406}a.bg-warning:hover,a.bg-warning:focus{background-color:#c67605}.bg-danger{background-color:#ee5f5b}a.bg-danger:hover,a.bg-danger:focus{background-color:#e9322d}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #1c1e22}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #7a8288}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #7a8288}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#7a8288}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #7a8288;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#ffffff;background-color:#333333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;font-weight:bold;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#3a3f44;background-color:#f5f5f5;border:1px solid #cccccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0%}}table{background-color:#2e3338}caption{padding-top:8px;padding-bottom:8px;color:#7a8288;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #1c1e22}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #1c1e22}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #1c1e22}.table .table{background-color:#272b30}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #1c1e22}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #1c1e22}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#353a41}.table-hover>tbody>tr:hover{background-color:#49515a}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#49515a}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#3e444c}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#62c462}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#4fbd4f}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#5bc0de}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#46b8da}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#f89406}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#df8505}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#ee5f5b}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ec4844}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #1c1e22}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#c8c8c8;border:0;border-bottom:1px solid #1c1e22}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:9px;font-size:14px;line-height:1.42857143;color:#272b30}.form-control{display:block;width:100%;height:38px;padding:8px 12px;font-size:14px;line-height:1.42857143;color:#272b30;background-color:#ffffff;background-image:none;border:1px solid #cccccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control::-moz-placeholder{color:#7a8288;opacity:1}.form-control:-ms-input-placeholder{color:#7a8288}.form-control::-webkit-input-placeholder{color:#7a8288}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#999999;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"].form-control,input[type="time"].form-control,input[type="datetime-local"].form-control,input[type="month"].form-control{line-height:38px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:30px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:54px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:9px;padding-bottom:9px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm textarea.form-control,.form-group-sm select[multiple].form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:54px;padding:14px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:54px;line-height:54px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:54px;padding:14px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:54px;line-height:54px}.form-group-lg textarea.form-control,.form-group-lg select[multiple].form-control{height:auto}.form-group-lg .form-control-static{height:54px;min-height:38px;padding:15px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:47.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:38px;height:38px;line-height:38px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback,.input-group-lg+.form-control-feedback,.form-group-lg .form-control+.form-control-feedback{width:54px;height:54px;line-height:54px}.input-sm+.form-control-feedback,.input-group-sm+.form-control-feedback,.form-group-sm .form-control+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#ffffff}.has-success .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-success .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#62c462}.has-success .form-control-feedback{color:#ffffff}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#ffffff}.has-warning .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-warning .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#f89406}.has-warning .form-control-feedback{color:#ffffff}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#ffffff}.has-error .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-error .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#ee5f5b}.has-error .form-control-feedback{color:#ffffff}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#ffffff}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:9px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:29px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:9px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:15px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:8px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#ffffff;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#ffffff;background-color:#3a3f44;border-color:#3a3f44}.btn-default:focus,.btn-default.focus{color:#ffffff;background-color:#232628;border-color:#000000}.btn-default:hover{color:#ffffff;background-color:#232628;border-color:#1e2023}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#ffffff;background-color:#232628;border-color:#1e2023}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#ffffff;background-color:#121415;border-color:#000000}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#3a3f44;border-color:#3a3f44}.btn-default .badge{color:#3a3f44;background-color:#ffffff}.btn-primary{color:#ffffff;background-color:#7a8288;border-color:#7a8288}.btn-primary:focus,.btn-primary.focus{color:#ffffff;background-color:#62686d;border-color:#3e4245}.btn-primary:hover{color:#ffffff;background-color:#62686d;border-color:#5d6368}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#ffffff;background-color:#62686d;border-color:#5d6368}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#ffffff;background-color:#51565a;border-color:#3e4245}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#7a8288;border-color:#7a8288}.btn-primary .badge{color:#7a8288;background-color:#ffffff}.btn-success{color:#ffffff;background-color:#62c462;border-color:#62c462}.btn-success:focus,.btn-success.focus{color:#ffffff;background-color:#42b142;border-color:#2d792d}.btn-success:hover{color:#ffffff;background-color:#42b142;border-color:#40a940}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#ffffff;background-color:#42b142;border-color:#40a940}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#ffffff;background-color:#399739;border-color:#2d792d}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#62c462;border-color:#62c462}.btn-success .badge{color:#62c462;background-color:#ffffff}.btn-info{color:#ffffff;background-color:#5bc0de;border-color:#5bc0de}.btn-info:focus,.btn-info.focus{color:#ffffff;background-color:#31b0d5;border-color:#1f7e9a}.btn-info:hover{color:#ffffff;background-color:#31b0d5;border-color:#2aabd2}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#ffffff;background-color:#31b0d5;border-color:#2aabd2}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#ffffff;background-color:#269abc;border-color:#1f7e9a}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#5bc0de;border-color:#5bc0de}.btn-info .badge{color:#5bc0de;background-color:#ffffff}.btn-warning{color:#ffffff;background-color:#f89406;border-color:#f89406}.btn-warning:focus,.btn-warning.focus{color:#ffffff;background-color:#c67605;border-color:#7c4a03}.btn-warning:hover{color:#ffffff;background-color:#c67605;border-color:#bc7005}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#ffffff;background-color:#c67605;border-color:#bc7005}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#ffffff;background-color:#a36104;border-color:#7c4a03}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f89406;border-color:#f89406}.btn-warning .badge{color:#f89406;background-color:#ffffff}.btn-danger{color:#ffffff;background-color:#ee5f5b;border-color:#ee5f5b}.btn-danger:focus,.btn-danger.focus{color:#ffffff;background-color:#e9322d;border-color:#b71713}.btn-danger:hover{color:#ffffff;background-color:#e9322d;border-color:#e82924}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#ffffff;background-color:#e9322d;border-color:#e82924}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#ffffff;background-color:#dc1c17;border-color:#b71713}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#ee5f5b;border-color:#ee5f5b}.btn-danger .badge{color:#ee5f5b;background-color:#ffffff}.btn-link{color:#ffffff;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#ffffff;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#7a8288;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:14px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:0.35s;-o-transition-duration:0.35s;transition-duration:0.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid \9;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#3a3f44;border:1px solid #272b30;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);-webkit-background-clip:padding-box;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#272b30}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#c8c8c8;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#ffffff;background-color:#272b30}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#272b30}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#7a8288}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#7a8288;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid \9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:54px;padding:14px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:54px;line-height:54px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:8px 12px;font-size:14px;font-weight:normal;line-height:1;color:#272b30;text-align:center;background-color:#999999;border:1px solid #cccccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:14px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#3e444c}.nav>li.disabled>a{color:#7a8288}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#7a8288;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#3e444c;border-color:#ffffff}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #1c1e22}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#1c1e22 #1c1e22 #1c1e22}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#ffffff;background-color:#3e444c;border:1px solid #1c1e22;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #1c1e22}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #1c1e22;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#272b30}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#ffffff;background-color:transparent}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #1c1e22}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #1c1e22;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#272b30}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:6px;margin-bottom:6px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:6px;margin-bottom:6px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#3a3f44;border-color:#2b2e32}.navbar-default .navbar-brand{color:#c8c8c8}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#ffffff;background-color:none}.navbar-default .navbar-text{color:#c8c8c8}.navbar-default .navbar-nav>li>a{color:#c8c8c8}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#ffffff;background-color:#272b2e}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#ffffff;background-color:#272b2e}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#272b2e}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#272b2e}.navbar-default .navbar-toggle .icon-bar{background-color:#c8c8c8}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#2b2e32}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#272b2e;color:#ffffff}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#c8c8c8}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#ffffff;background-color:#272b2e}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#272b2e}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-default .navbar-link{color:#c8c8c8}.navbar-default .navbar-link:hover{color:#ffffff}.navbar-default .btn-link{color:#c8c8c8}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#ffffff}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#cccccc}.navbar-inverse{background-color:#7a8288;border-color:#62686d}.navbar-inverse .navbar-brand{color:#cccccc}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#ffffff;background-color:none}.navbar-inverse .navbar-text{color:#cccccc}.navbar-inverse .navbar-nav>li>a{color:#cccccc}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#ffffff;background-color:#5d6368}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#ffffff;background-color:#5d6368}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#5d6368}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#5d6368}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#697075}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#5d6368;color:#ffffff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#62686d}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#62686d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#cccccc}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#ffffff;background-color:#5d6368}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#5d6368}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#cccccc}.navbar-inverse .navbar-link:hover{color:#ffffff}.navbar-inverse .btn-link{color:#cccccc}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#ffffff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#cccccc}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:transparent;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#cccccc}.breadcrumb>.active{color:#7a8288}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:8px 12px;line-height:1.42857143;text-decoration:none;color:#ffffff;background-color:#3a3f44;border:1px solid rgba(0,0,0,0.6);margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{z-index:2;color:#ffffff;background-color:transparent;border-color:rgba(0,0,0,0.6)}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:3;color:#ffffff;background-color:#232628;border-color:rgba(0,0,0,0.6);cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#7a8288;background-color:#ffffff;border-color:rgba(0,0,0,0.6);cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:14px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#3a3f44;border:1px solid rgba(0,0,0,0.6);border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:transparent}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#7a8288;background-color:#3a3f44;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#ffffff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#ffffff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#3a3f44}.label-default[href]:hover,.label-default[href]:focus{background-color:#232628}.label-primary{background-color:#7a8288}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#62686d}.label-success{background-color:#62c462}.label-success[href]:hover,.label-success[href]:focus{background-color:#42b142}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f89406}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#c67605}.label-danger{background-color:#ee5f5b}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#e9322d}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;color:#ffffff;line-height:1;vertical-align:middle;white-space:nowrap;text-align:center;background-color:#7a8288;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge,.btn-group-xs>.btn .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#ffffff;background-color:#7a8288}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#1c1e22}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#050506}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px;padding-left:15px;padding-right:15px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#1c1e22;border:1px solid #0c0d0e;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#ffffff}.thumbnail .caption{padding:9px;color:#c8c8c8}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#62c462;border-color:#62bd4f;color:#ffffff}.alert-success hr{border-top-color:#55b142}.alert-success .alert-link{color:#e6e6e6}.alert-info{background-color:#5bc0de;border-color:#3dced8;color:#ffffff}.alert-info hr{border-top-color:#2ac7d2}.alert-info .alert-link{color:#e6e6e6}.alert-warning{background-color:#f89406;border-color:#e96506;color:#ffffff}.alert-warning hr{border-top-color:#d05a05}.alert-warning .alert-link{color:#e6e6e6}.alert-danger{background-color:#ee5f5b;border-color:#ed4d63;color:#ffffff}.alert-danger hr{border-top-color:#ea364f}.alert-danger .alert-link{color:#e6e6e6}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#1c1e22;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#ffffff;text-align:center;background-color:#7a8288;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#62c462}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f89406}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#ee5f5b}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#32383e;border:1px solid rgba(0,0,0,0.6)}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#c8c8c8}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#ffffff}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{text-decoration:none;color:#c8c8c8;background-color:#3e444c}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#999999;color:#7a8288;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#7a8288}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#ffffff;background-color:#3e444c;border-color:rgba(0,0,0,0.6)}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#a2aab4}.list-group-item-success{color:#ffffff;background-color:#62c462}a.list-group-item-success,button.list-group-item-success{color:#ffffff}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,button.list-group-item-success:hover,a.list-group-item-success:focus,button.list-group-item-success:focus{color:#ffffff;background-color:#4fbd4f}a.list-group-item-success.active,button.list-group-item-success.active,a.list-group-item-success.active:hover,button.list-group-item-success.active:hover,a.list-group-item-success.active:focus,button.list-group-item-success.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-info{color:#ffffff;background-color:#5bc0de}a.list-group-item-info,button.list-group-item-info{color:#ffffff}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,button.list-group-item-info:hover,a.list-group-item-info:focus,button.list-group-item-info:focus{color:#ffffff;background-color:#46b8da}a.list-group-item-info.active,button.list-group-item-info.active,a.list-group-item-info.active:hover,button.list-group-item-info.active:hover,a.list-group-item-info.active:focus,button.list-group-item-info.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-warning{color:#ffffff;background-color:#f89406}a.list-group-item-warning,button.list-group-item-warning{color:#ffffff}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,button.list-group-item-warning:hover,a.list-group-item-warning:focus,button.list-group-item-warning:focus{color:#ffffff;background-color:#df8505}a.list-group-item-warning.active,button.list-group-item-warning.active,a.list-group-item-warning.active:hover,button.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus,button.list-group-item-warning.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-danger{color:#ffffff;background-color:#ee5f5b}a.list-group-item-danger,button.list-group-item-danger{color:#ffffff}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,button.list-group-item-danger:hover,a.list-group-item-danger:focus,button.list-group-item-danger:focus{color:#ffffff;background-color:#ec4844}a.list-group-item-danger.active,button.list-group-item-danger.active,a.list-group-item-danger.active:hover,button.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus,button.list-group-item-danger.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#2e3338;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#3e444c;border-top:1px solid rgba(0,0,0,0.6);border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-left:15px;padding-right:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #1c1e22}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid rgba(0,0,0,0.6)}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid rgba(0,0,0,0.6)}.panel-default{border-color:rgba(0,0,0,0.6)}.panel-default>.panel-heading{color:#c8c8c8;background-color:#3e444c;border-color:rgba(0,0,0,0.6)}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:rgba(0,0,0,0.6)}.panel-default>.panel-heading .badge{color:#3e444c;background-color:#c8c8c8}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:rgba(0,0,0,0.6)}.panel-primary{border-color:rgba(0,0,0,0.6)}.panel-primary>.panel-heading{color:#ffffff;background-color:#7a8288;border-color:rgba(0,0,0,0.6)}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:rgba(0,0,0,0.6)}.panel-primary>.panel-heading .badge{color:#7a8288;background-color:#ffffff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:rgba(0,0,0,0.6)}.panel-success{border-color:rgba(0,0,0,0.6)}.panel-success>.panel-heading{color:#ffffff;background-color:#62c462;border-color:rgba(0,0,0,0.6)}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:rgba(0,0,0,0.6)}.panel-success>.panel-heading .badge{color:#62c462;background-color:#ffffff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:rgba(0,0,0,0.6)}.panel-info{border-color:rgba(0,0,0,0.6)}.panel-info>.panel-heading{color:#ffffff;background-color:#5bc0de;border-color:rgba(0,0,0,0.6)}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:rgba(0,0,0,0.6)}.panel-info>.panel-heading .badge{color:#5bc0de;background-color:#ffffff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:rgba(0,0,0,0.6)}.panel-warning{border-color:rgba(0,0,0,0.6)}.panel-warning>.panel-heading{color:#ffffff;background-color:#f89406;border-color:rgba(0,0,0,0.6)}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:rgba(0,0,0,0.6)}.panel-warning>.panel-heading .badge{color:#f89406;background-color:#ffffff}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:rgba(0,0,0,0.6)}.panel-danger{border-color:rgba(0,0,0,0.6)}.panel-danger>.panel-heading{color:#ffffff;background-color:#ee5f5b;border-color:rgba(0,0,0,0.6)}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:rgba(0,0,0,0.6)}.panel-danger>.panel-heading .badge{color:#ee5f5b;background-color:#ffffff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:rgba(0,0,0,0.6)}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#1c1e22;border:1px solid #0c0d0e;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#2e3338;border:1px solid #999999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #1c1e22}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right;border-top:1px solid #1c1e22}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:12px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;background-color:#000000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:14px;background-color:#2e3338;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#2e3338;border-bottom:1px solid #22262a;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#666666;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#2e3338}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#666666;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#2e3338}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#666666;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#2e3338}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#666666;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#2e3338;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);background-color:rgba(0,0,0,0)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0.0001)));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.0001)), to(rgba(0,0,0,0.5)));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #ffffff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#ffffff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.navbar{background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none;border:1px solid rgba(0,0,0,0.6);text-shadow:1px 1px 1px rgba(0,0,0,0.3)}.navbar-inverse{background-image:-webkit-linear-gradient(#8a9196, #7a8288 60%, #70787d);background-image:-o-linear-gradient(#8a9196, #7a8288 60%, #70787d);background-image:-webkit-gradient(linear, left top, left bottom, from(#8a9196), color-stop(60%, #7a8288), to(#70787d));background-image:linear-gradient(#8a9196, #7a8288 60%, #70787d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8a9196', endColorstr='#ff70787d', GradientType=0);-webkit-filter:none;filter:none}.navbar-inverse .badge{background-color:#5d6368}.navbar-nav>li>a{border-right:1px solid rgba(0,0,0,0.2);border-left:1px solid rgba(255,255,255,0.1)}.navbar-nav>li>a:hover{background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none;border-left-color:transparent}.navbar .nav .open>a{border-color:transparent}.navbar-nav>li.active>a{border-left-color:transparent}.navbar-form{margin-left:5px;margin-right:5px}.btn,.btn:hover{border-color:rgba(0,0,0,0.6);text-shadow:1px 1px 1px rgba(0,0,0,0.3)}.btn-default{background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none}.btn-default:hover{background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none}.btn-primary{background-image:-webkit-linear-gradient(#8a9196, #7a8288 60%, #70787d);background-image:-o-linear-gradient(#8a9196, #7a8288 60%, #70787d);background-image:-webkit-gradient(linear, left top, left bottom, from(#8a9196), color-stop(60%, #7a8288), to(#70787d));background-image:linear-gradient(#8a9196, #7a8288 60%, #70787d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8a9196', endColorstr='#ff70787d', GradientType=0);-webkit-filter:none;filter:none}.btn-primary:hover{background-image:-webkit-linear-gradient(#404448, #4e5458 40%, #585e62);background-image:-o-linear-gradient(#404448, #4e5458 40%, #585e62);background-image:-webkit-gradient(linear, left top, left bottom, from(#404448), color-stop(40%, #4e5458), to(#585e62));background-image:linear-gradient(#404448, #4e5458 40%, #585e62);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff404448', endColorstr='#ff585e62', GradientType=0);-webkit-filter:none;filter:none}.btn-success{background-image:-webkit-linear-gradient(#78cc78, #62c462 60%, #53be53);background-image:-o-linear-gradient(#78cc78, #62c462 60%, #53be53);background-image:-webkit-gradient(linear, left top, left bottom, from(#78cc78), color-stop(60%, #62c462), to(#53be53));background-image:linear-gradient(#78cc78, #62c462 60%, #53be53);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff78cc78', endColorstr='#ff53be53', GradientType=0);-webkit-filter:none;filter:none}.btn-success:hover{background-image:-webkit-linear-gradient(#2f7d2f, #379337 40%, #3da23d);background-image:-o-linear-gradient(#2f7d2f, #379337 40%, #3da23d);background-image:-webkit-gradient(linear, left top, left bottom, from(#2f7d2f), color-stop(40%, #379337), to(#3da23d));background-image:linear-gradient(#2f7d2f, #379337 40%, #3da23d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2f7d2f', endColorstr='#ff3da23d', GradientType=0);-webkit-filter:none;filter:none}.btn-info{background-image:-webkit-linear-gradient(#74cae3, #5bc0de 60%, #4ab9db);background-image:-o-linear-gradient(#74cae3, #5bc0de 60%, #4ab9db);background-image:-webkit-gradient(linear, left top, left bottom, from(#74cae3), color-stop(60%, #5bc0de), to(#4ab9db));background-image:linear-gradient(#74cae3, #5bc0de 60%, #4ab9db);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff74cae3', endColorstr='#ff4ab9db', GradientType=0);-webkit-filter:none;filter:none}.btn-info:hover{background-image:-webkit-linear-gradient(#20829f, #2596b8 40%, #28a4c9);background-image:-o-linear-gradient(#20829f, #2596b8 40%, #28a4c9);background-image:-webkit-gradient(linear, left top, left bottom, from(#20829f), color-stop(40%, #2596b8), to(#28a4c9));background-image:linear-gradient(#20829f, #2596b8 40%, #28a4c9);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff20829f', endColorstr='#ff28a4c9', GradientType=0);-webkit-filter:none;filter:none}.btn-warning{background-image:-webkit-linear-gradient(#faa123, #f89406 60%, #e48806);background-image:-o-linear-gradient(#faa123, #f89406 60%, #e48806);background-image:-webkit-gradient(linear, left top, left bottom, from(#faa123), color-stop(60%, #f89406), to(#e48806));background-image:linear-gradient(#faa123, #f89406 60%, #e48806);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffaa123', endColorstr='#ffe48806', GradientType=0);-webkit-filter:none;filter:none}.btn-warning:hover{background-image:-webkit-linear-gradient(#804d03, #9e5f04 40%, #b26a04);background-image:-o-linear-gradient(#804d03, #9e5f04 40%, #b26a04);background-image:-webkit-gradient(linear, left top, left bottom, from(#804d03), color-stop(40%, #9e5f04), to(#b26a04));background-image:linear-gradient(#804d03, #9e5f04 40%, #b26a04);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff804d03', endColorstr='#ffb26a04', GradientType=0);-webkit-filter:none;filter:none}.btn-danger{background-image:-webkit-linear-gradient(#f17a77, #ee5f5b 60%, #ec4d49);background-image:-o-linear-gradient(#f17a77, #ee5f5b 60%, #ec4d49);background-image:-webkit-gradient(linear, left top, left bottom, from(#f17a77), color-stop(60%, #ee5f5b), to(#ec4d49));background-image:linear-gradient(#f17a77, #ee5f5b 60%, #ec4d49);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff17a77', endColorstr='#ffec4d49', GradientType=0);-webkit-filter:none;filter:none}.btn-danger:hover{background-image:-webkit-linear-gradient(#bb1813, #d71c16 40%, #e7201a);background-image:-o-linear-gradient(#bb1813, #d71c16 40%, #e7201a);background-image:-webkit-gradient(linear, left top, left bottom, from(#bb1813), color-stop(40%, #d71c16), to(#e7201a));background-image:linear-gradient(#bb1813, #d71c16 40%, #e7201a);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffbb1813', endColorstr='#ffe7201a', GradientType=0);-webkit-filter:none;filter:none}.btn-link,.btn-link:hover{border-color:transparent}h1,h2,h3,h4,h5,h6{text-shadow:-1px -1px 0 rgba(0,0,0,0.3)}.text-primary,.text-primary:hover{color:#7a8288}.text-success,.text-success:hover{color:#62c462}.text-danger,.text-danger:hover{color:#ee5f5b}.text-warning,.text-warning:hover{color:#f89406}.text-info,.text-info:hover{color:#5bc0de}.table .success,.table .warning,.table .danger,.table .info{color:#fff}.table-bordered tbody tr.success td,.table-bordered tbody tr.warning td,.table-bordered tbody tr.danger td,.table-bordered tbody tr.success:hover td,.table-bordered tbody tr.warning:hover td,.table-bordered tbody tr.danger:hover td{border-color:#1c1e22}.table-responsive>.table{background-color:#2e3338}input,textarea{color:#272b30}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label,.has-warning .form-control-feedback{color:#f89406}.has-warning .form-control,.has-warning .form-control:focus{border-color:#f89406}.has-warning .input-group-addon{background-color:#272b30;border:none}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label,.has-error .form-control-feedback{color:#ee5f5b}.has-error .form-control,.has-error .form-control:focus{border-color:#ee5f5b}.has-error .input-group-addon{background-color:#272b30;border:none}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label,.has-success .form-control-feedback{color:#62c462}.has-success .form-control,.has-success .form-control:focus{border-color:#62c462}.has-success .input-group-addon{background-color:#272b30;border:none}legend{color:#fff}.input-group-addon{border-color:rgba(0,0,0,0.6);text-shadow:1px 1px 1px rgba(0,0,0,0.3);background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none;color:#ffffff}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{border-color:rgba(0,0,0,0.6)}.nav-pills>li>a{background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none;border:1px solid rgba(0,0,0,0.6);text-shadow:1px 1px 1px rgba(0,0,0,0.3)}.nav-pills>li>a:hover{background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none;border:1px solid rgba(0,0,0,0.6)}.nav-pills>li.active>a,.nav-pills>li.active>a:hover{background-color:none;background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none;border:1px solid rgba(0,0,0,0.6)}.nav-pills>li.disabled>a,.nav-pills>li.disabled>a:hover{background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none}.pagination>li>a,.pagination>li>span{text-shadow:1px 1px 1px rgba(0,0,0,0.3);background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none}.pagination>li>a:hover,.pagination>li>span:hover{background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none}.pagination>li.active>a,.pagination>li.active>span{background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none}.pagination>li.disabled>a,.pagination>li.disabled>a:hover,.pagination>li.disabled>span,.pagination>li.disabled>span:hover{background-color:transparent;background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none}.pager>li>a{background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none;text-shadow:1px 1px 1px rgba(0,0,0,0.3)}.pager>li>a:hover{background-image:-webkit-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-o-linear-gradient(#020202, #101112 40%, #191b1d);background-image:-webkit-gradient(linear, left top, left bottom, from(#020202), color-stop(40%, #101112), to(#191b1d));background-image:linear-gradient(#020202, #101112 40%, #191b1d);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff020202', endColorstr='#ff191b1d', GradientType=0);-webkit-filter:none;filter:none}.pager>li.disabled>a,.pager>li.disabled>a:hover{background-color:transparent;background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none}.breadcrumb{border:1px solid rgba(0,0,0,0.6);text-shadow:1px 1px 1px rgba(0,0,0,0.3);background-image:-webkit-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-o-linear-gradient(#484e55, #3a3f44 60%, #313539);background-image:-webkit-gradient(linear, left top, left bottom, from(#484e55), color-stop(60%, #3a3f44), to(#313539));background-image:linear-gradient(#484e55, #3a3f44 60%, #313539);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff484e55', endColorstr='#ff313539', GradientType=0);-webkit-filter:none;filter:none}.alert .alert-link,.alert a{color:#fff;text-decoration:underline}.alert .close{color:#000000;text-decoration:none}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#0c0d0e}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{border-color:rgba(0,0,0,0.6)}a.list-group-item-success.active{background-color:#62c462}a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{background-color:#4fbd4f}a.list-group-item-warning.active{background-color:#f89406}a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{background-color:#df8505}a.list-group-item-danger.active{background-color:#ee5f5b}a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{background-color:#ec4844}.jumbotron{border:1px solid rgba(0,0,0,0.6)}.panel-primary .panel-heading,.panel-success .panel-heading,.panel-danger .panel-heading,.panel-warning .panel-heading,.panel-info .panel-heading{border-color:#000} \ No newline at end of file diff --git a/admin/static/fonts/glyphicons-halflings-regular.eot b/admin/static/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..b93a4953fff68df523aa7656497ee339d6026d64 GIT binary patch literal 20127 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/admin/static/fonts/glyphicons-halflings-regular.ttf b/admin/static/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1413fc609ab6f21774de0cb7e01360095584f65b GIT binary patch literal 45404 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 G`u_lkUM?>H literal 0 HcmV?d00001 diff --git a/admin/static/fonts/glyphicons-halflings-regular.woff2 b/admin/static/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..64539b54c3751a6d9adb44c8e3a45ba5a73b77f0 GIT binary patch literal 18028 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 literal 0 HcmV?d00001 diff --git a/admin/static/index.html b/admin/static/index.html new file mode 100644 index 00000000..96ef0a41 --- /dev/null +++ b/admin/static/index.html @@ -0,0 +1,27 @@ + + + + + Challenge Forensic FIC 2016 - Administration + + + + +
    + +
    +
    +
    +
    + + + + + + + + + diff --git a/admin/static/js/angular-resource.min.js b/admin/static/js/angular-resource.min.js new file mode 100644 index 00000000..c3fb7aab --- /dev/null +++ b/admin/static/js/angular-resource.min.js @@ -0,0 +1,14 @@ +/* + AngularJS v1.4.8 + (c) 2010-2015 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(I,f,C){'use strict';function D(t,e){e=e||{};f.forEach(e,function(f,k){delete e[k]});for(var k in t)!t.hasOwnProperty(k)||"$"===k.charAt(0)&&"$"===k.charAt(1)||(e[k]=t[k]);return e}var y=f.$$minErr("$resource"),B=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;f.module("ngResource",["ng"]).provider("$resource",function(){var t=/^https?:\/\/[^\/]*/,e=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}}; +this.$get=["$http","$q",function(k,F){function w(f,g){this.template=f;this.defaults=r({},e.defaults,g);this.urlParams={}}function z(l,g,s,h){function c(a,q){var c={};q=r({},g,q);u(q,function(b,q){x(b)&&(b=b());var m;if(b&&b.charAt&&"@"==b.charAt(0)){m=a;var d=b.substr(1);if(null==d||""===d||"hasOwnProperty"===d||!B.test("."+d))throw y("badmember",d);for(var d=d.split("."),n=0,g=d.length;n").append(a).html();try{return a[0].nodeType===Na?F(d):d.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+F(b)})}catch(c){return F(d)}}function wc(a){try{return decodeURIComponent(a)}catch(b){}} +function xc(a){var b={};n((a||"").split("&"),function(a){var c,e,f;a&&(e=a=a.replace(/\+/g,"%20"),c=a.indexOf("="),-1!==c&&(e=a.substring(0,c),f=a.substring(c+1)),e=wc(e),y(e)&&(f=y(f)?wc(f):!0,qa.call(b,e)?I(b[e])?b[e].push(f):b[e]=[b[e],f]:b[e]=f))});return b}function Qb(a){var b=[];n(a,function(a,c){I(a)?n(a,function(a){b.push(ja(c,!0)+(!0===a?"":"="+ja(a,!0)))}):b.push(ja(c,!0)+(!0===a?"":"="+ja(a,!0)))});return b.length?b.join("&"):""}function ob(a){return ja(a,!0).replace(/%26/gi,"&").replace(/%3D/gi, +"=").replace(/%2B/gi,"+")}function ja(a,b){return encodeURIComponent(a).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,b?"%20":"+")}function Yd(a,b){var d,c,e=Oa.length;for(c=0;c/,">"));}b=b||[];b.unshift(["$provide",function(b){b.value("$rootElement",a)}]);d.debugInfoEnabled&&b.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);b.unshift("ng");c=eb(b,d.strictDi);c.invoke(["$rootScope", +"$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},e=/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;S&&e.test(S.name)&&(d.debugInfoEnabled=!0,S.name=S.name.replace(e,""));if(S&&!f.test(S.name))return c();S.name=S.name.replace(f,"");fa.resumeBootstrap=function(a){n(a,function(a){b.push(a)});return c()};z(fa.resumeDeferredBootstrap)&&fa.resumeDeferredBootstrap()}function $d(){S.name="NG_ENABLE_DEBUG_INFO!"+S.name;S.location.reload()} +function ae(a){a=fa.element(a).injector();if(!a)throw Aa("test");return a.get("$$testability")}function zc(a,b){b=b||"_";return a.replace(be,function(a,c){return(c?b:"")+a.toLowerCase()})}function ce(){var a;if(!Ac){var b=pb();(oa=q(b)?S.jQuery:b?S[b]:u)&&oa.fn.on?(B=oa,M(oa.fn,{scope:Pa.scope,isolateScope:Pa.isolateScope,controller:Pa.controller,injector:Pa.injector,inheritedData:Pa.inheritedData}),a=oa.cleanData,oa.cleanData=function(b){var c;if(Rb)Rb=!1;else for(var e=0,f;null!=(f=b[e]);e++)(c= +oa._data(f,"events"))&&c.$destroy&&oa(f).triggerHandler("$destroy");a(b)}):B=N;fa.element=B;Ac=!0}}function qb(a,b,d){if(!a)throw Aa("areq",b||"?",d||"required");return a}function Qa(a,b,d){d&&I(a)&&(a=a[a.length-1]);qb(z(a),b,"not a function, got "+(a&&"object"===typeof a?a.constructor.name||"Object":typeof a));return a}function Ra(a,b){if("hasOwnProperty"===a)throw Aa("badname",b);}function Bc(a,b,d){if(!b)return a;b=b.split(".");for(var c,e=a,f=b.length,g=0;g")+c[2];for(c=c[0];c--;)d=d.lastChild;f=cb(f,d.childNodes);d=e.firstChild;d.textContent=""}else f.push(b.createTextNode(a));e.textContent="";e.innerHTML="";n(f,function(a){e.appendChild(a)});return e}function N(a){if(a instanceof N)return a;var b;E(a)&&(a=U(a), +b=!0);if(!(this instanceof N)){if(b&&"<"!=a.charAt(0))throw Ub("nosel");return new N(a)}if(b){b=X;var d;a=(d=Ef.exec(a))?[b.createElement(d[1])]:(d=Lc(a,b))?d.childNodes:[]}Mc(this,a)}function Vb(a){return a.cloneNode(!0)}function ub(a,b){b||vb(a);if(a.querySelectorAll)for(var d=a.querySelectorAll("*"),c=0,e=d.length;cl&&this.remove(t.key);return b}},get:function(a){if(l").parent()[0])});var f=O(a,b,a,c,d,e);K.$$addScopeClass(a);var g=null;return function(b,c,d){qb(b,"scope");e&&e.needsNewScope&&(b=b.$parent.$new());d=d||{};var h=d.parentBoundTranscludeFn,k=d.transcludeControllers;d=d.futureParentElement;h&&h.$$boundTransclude&&(h=h.$$boundTransclude);g||(g=(d= +d&&d[0])?"foreignobject"!==ta(d)&&d.toString().match(/SVG/)?"svg":"html":"html");d="html"!==g?B(Yb(g,B("
    ").append(a).html())):c?Pa.clone.call(a):a;if(k)for(var l in k)d.data("$"+l+"Controller",k[l].instance);K.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,h);return d}}function O(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,m,t,w,D;if(p)for(D=Array(c.length),m=0;mq.priority)break;if(P=q.scope)q.templateUrl||(H(P)?(Ua("new/isolated scope",O||R,q,Z),O=q):Ua("new/isolated scope",O,q,Z)),R=R||q;x=q.name;!q.templateUrl&&q.controller&&(P=q.controller,T=T||$(),Ua("'"+x+"' controller",T[x],q,Z),T[x]=q);if(P=q.transclude)ga=!0,q.$$tlb||(Ua("transclusion",n,q,Z),n=q),"element"==P?(aa=!0,A=q.priority,P=Z,Z=d.$$element=B(X.createComment(" "+x+": "+d[x]+" ")),b=Z[0],Y(f,ra.call(P,0), +b),Ia=K(P,e,A,g&&g.name,{nonTlbTranscludeDirective:n})):(P=B(Vb(b)).contents(),Z.empty(),Ia=K(P,e,u,u,{needsNewScope:q.$$isolateScope||q.$$newScope}));if(q.template)if(L=!0,Ua("template",J,q,Z),J=q,P=z(q.template)?q.template(Z,d):q.template,P=ja(P),q.replace){g=q;P=Tb.test(P)?Xc(Yb(q.templateNamespace,U(P))):[];b=P[0];if(1!=P.length||1!==b.nodeType)throw ha("tplrt",x,"");Y(f,Z,b);P={$attr:{}};var Wc=V(b,[],P),W=a.splice(F+1,a.length-(F+1));(O||R)&&y(Wc,O,R);a=a.concat(Wc).concat(W);S(d,P);M=a.length}else Z.html(P); +if(q.templateUrl)L=!0,Ua("template",J,q,Z),J=q,q.replace&&(g=q),D=Of(a.splice(F,a.length-F),Z,d,f,ga&&Ia,h,l,{controllerDirectives:T,newScopeDirective:R!==q&&R,newIsolateScopeDirective:O,templateDirective:J,nonTlbTranscludeDirective:n}),M=a.length;else if(q.compile)try{G=q.compile(Z,d,Ia),z(G)?t(null,G,N,Q):G&&t(G.pre,G.post,N,Q)}catch(da){c(da,ua(Z))}q.terminal&&(D.terminal=!0,A=Math.max(A,q.priority))}D.scope=R&&!0===R.scope;D.transcludeOnThisElement=ga;D.templateOnThisElement=L;D.transclude=Ia; +m.hasElementTranscludeDirective=aa;return D}function y(a,b,c){for(var d=0,e=a.length;dm.priority)&&-1!=m.restrict.indexOf(f)&&(k&&(m=Ob(m,{$$start:k,$$end:l})),b.push(m),h=m)}catch(D){c(D)}}return h}function G(b){if(e.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,f=c.length;d"+b+"";return c.childNodes[0].childNodes;default:return b}}function Q(a,b){if("srcdoc"==b)return L.HTML;var c=ta(a);if("xlinkHref"==b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return L.RESOURCE_URL}function W(a,c,d,e,f){var g=Q(a,e);f=h[e]||f;var k=b(d,!0,g,f);if(k){if("multiple"===e&&"select"===ta(a))throw ha("selmulti",ua(a));c.push({priority:100,compile:function(){return{pre:function(a,c,h){c=h.$$observers||(h.$$observers=$());if(l.test(e))throw ha("nodomevents"); +var m=h[e];m!==d&&(k=m&&b(m,!0,g,f),d=m);k&&(h[e]=k(a),(c[e]||(c[e]=[])).$$inter=!0,(h.$$observers&&h.$$observers[e].$$scope||a).$watch(k,function(a,b){"class"===e&&a!=b?h.$updateClass(a,b):h.$set(e,a)}))}}}})}}function Y(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g=b)return a;for(;b--;)8===a[b].nodeType&&Pf.call(a,b,1);return a}function Xe(){var a={},b=!1;this.register=function(b,c){Ra(b,"controller");H(b)?M(a,b):a[b]=c};this.allowGlobals=function(){b=!0};this.$get=["$injector","$window",function(d,c){function e(a,b,c,d){if(!a||!H(a.$scope))throw G("$controller")("noscp", +d,b);a.$scope[b]=c}return function(f,g,h,k){var l,m,r;h=!0===h;k&&E(k)&&(r=k);if(E(f)){k=f.match(Uc);if(!k)throw Qf("ctrlfmt",f);m=k[1];r=r||k[3];f=a.hasOwnProperty(m)?a[m]:Bc(g.$scope,m,!0)||(b?Bc(c,m,!0):u);Qa(f,m,!0)}if(h)return h=(I(f)?f[f.length-1]:f).prototype,l=Object.create(h||null),r&&e(g,r,l,m||f.name),M(function(){var a=d.invoke(f,l,g,m);a!==l&&(H(a)||z(a))&&(l=a,r&&e(g,r,l,m||f.name));return l},{instance:l,identifier:r});l=d.instantiate(f,g,m);r&&e(g,r,l,m||f.name);return l}}]}function Ye(){this.$get= +["$window",function(a){return B(a.document)}]}function Ze(){this.$get=["$log",function(a){return function(b,d){a.error.apply(a,arguments)}}]}function Zb(a){return H(a)?da(a)?a.toISOString():db(a):a}function df(){this.$get=function(){return function(a){if(!a)return"";var b=[];oc(a,function(a,c){null===a||q(a)||(I(a)?n(a,function(a,d){b.push(ja(c)+"="+ja(Zb(a)))}):b.push(ja(c)+"="+ja(Zb(a))))});return b.join("&")}}}function ef(){this.$get=function(){return function(a){function b(a,e,f){null===a||q(a)|| +(I(a)?n(a,function(a,c){b(a,e+"["+(H(a)?c:"")+"]")}):H(a)&&!da(a)?oc(a,function(a,c){b(a,e+(f?"":"[")+c+(f?"":"]"))}):d.push(ja(e)+"="+ja(Zb(a))))}if(!a)return"";var d=[];b(a,"",!0);return d.join("&")}}}function $b(a,b){if(E(a)){var d=a.replace(Rf,"").trim();if(d){var c=b("Content-Type");(c=c&&0===c.indexOf($c))||(c=(c=d.match(Sf))&&Tf[c[0]].test(d));c&&(a=uc(d))}}return a}function ad(a){var b=$(),d;E(a)?n(a.split("\n"),function(a){d=a.indexOf(":");var e=F(U(a.substr(0,d)));a=U(a.substr(d+1));e&& +(b[e]=b[e]?b[e]+", "+a:a)}):H(a)&&n(a,function(a,d){var f=F(d),g=U(a);f&&(b[f]=b[f]?b[f]+", "+g:g)});return b}function bd(a){var b;return function(d){b||(b=ad(a));return d?(d=b[F(d)],void 0===d&&(d=null),d):b}}function cd(a,b,d,c){if(z(c))return c(a,b,d);n(c,function(c){a=c(a,b,d)});return a}function cf(){var a=this.defaults={transformResponse:[$b],transformRequest:[function(a){return H(a)&&"[object File]"!==sa.call(a)&&"[object Blob]"!==sa.call(a)&&"[object FormData]"!==sa.call(a)?db(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"}, +post:ia(ac),put:ia(ac),patch:ia(ac)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer"},b=!1;this.useApplyAsync=function(a){return y(a)?(b=!!a,this):b};var d=!0;this.useLegacyPromiseExtensions=function(a){return y(a)?(d=!!a,this):d};var c=this.interceptors=[];this.$get=["$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector",function(e,f,g,h,k,l){function m(b){function c(a){var b=M({},a);b.data=cd(a.data,a.headers,a.status,f.transformResponse); +a=a.status;return 200<=a&&300>a?b:k.reject(b)}function e(a,b){var c,d={};n(a,function(a,e){z(a)?(c=a(b),null!=c&&(d[e]=c)):d[e]=a});return d}if(!fa.isObject(b))throw G("$http")("badreq",b);var f=M({method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse,paramSerializer:a.paramSerializer},b);f.headers=function(b){var c=a.headers,d=M({},b.headers),f,g,h,c=M({},c.common,c[F(b.method)]);a:for(f in c){g=F(f);for(h in d)if(F(h)===g)continue a;d[f]=c[f]}return e(d,ia(b))}(b); +f.method=sb(f.method);f.paramSerializer=E(f.paramSerializer)?l.get(f.paramSerializer):f.paramSerializer;var g=[function(b){var d=b.headers,e=cd(b.data,bd(d),u,b.transformRequest);q(e)&&n(d,function(a,b){"content-type"===F(b)&&delete d[b]});q(b.withCredentials)&&!q(a.withCredentials)&&(b.withCredentials=a.withCredentials);return r(b,e).then(c,c)},u],h=k.when(f);for(n(v,function(a){(a.request||a.requestError)&&g.unshift(a.request,a.requestError);(a.response||a.responseError)&&g.push(a.response,a.responseError)});g.length;){b= +g.shift();var m=g.shift(),h=h.then(b,m)}d?(h.success=function(a){Qa(a,"fn");h.then(function(b){a(b.data,b.status,b.headers,f)});return h},h.error=function(a){Qa(a,"fn");h.then(null,function(b){a(b.data,b.status,b.headers,f)});return h}):(h.success=dd("success"),h.error=dd("error"));return h}function r(c,d){function g(a,c,d,e){function f(){l(c,a,d,e)}J&&(200<=a&&300>a?J.put(R,[a,c,ad(d),e]):J.remove(R));b?h.$applyAsync(f):(f(),h.$$phase||h.$apply())}function l(a,b,d,e){b=-1<=b?b:0;(200<=b&&300>b?n.resolve: +n.reject)({data:a,status:b,headers:bd(d),config:c,statusText:e})}function r(a){l(a.data,a.status,ia(a.headers()),a.statusText)}function v(){var a=m.pendingRequests.indexOf(c);-1!==a&&m.pendingRequests.splice(a,1)}var n=k.defer(),D=n.promise,J,K,O=c.headers,R=t(c.url,c.paramSerializer(c.params));m.pendingRequests.push(c);D.then(v,v);!c.cache&&!a.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(J=H(c.cache)?c.cache:H(a.cache)?a.cache:A);J&&(K=J.get(R),y(K)?K&&z(K.then)?K.then(r,r):I(K)?l(K[1], +K[0],ia(K[2]),K[3]):l(K,200,{},"OK"):J.put(R,D));q(K)&&((K=ed(c.url)?f()[c.xsrfCookieName||a.xsrfCookieName]:u)&&(O[c.xsrfHeaderName||a.xsrfHeaderName]=K),e(c.method,R,d,g,O,c.timeout,c.withCredentials,c.responseType));return D}function t(a,b){0=k&&(p.resolve(v),A(C.$$intervalId),delete f[C.$$intervalId]);n||a.$apply()},h);f[C.$$intervalId]=p;return C}var f={};e.cancel=function(a){return a&&a.$$intervalId in f?(f[a.$$intervalId].reject("canceled"),b.clearInterval(a.$$intervalId),delete f[a.$$intervalId],!0):!1};return e}]}function bc(a){a=a.split("/");for(var b=a.length;b--;)a[b]=ob(a[b]);return a.join("/")}function fd(a,b){var d=wa(a);b.$$protocol=d.protocol;b.$$host=d.hostname;b.$$port=ea(d.port)||Vf[d.protocol]|| +null}function gd(a,b){var d="/"!==a.charAt(0);d&&(a="/"+a);var c=wa(a);b.$$path=decodeURIComponent(d&&"/"===c.pathname.charAt(0)?c.pathname.substring(1):c.pathname);b.$$search=xc(c.search);b.$$hash=decodeURIComponent(c.hash);b.$$path&&"/"!=b.$$path.charAt(0)&&(b.$$path="/"+b.$$path)}function pa(a,b){if(0===b.indexOf(a))return b.substr(a.length)}function Fa(a){var b=a.indexOf("#");return-1==b?a:a.substr(0,b)}function ib(a){return a.replace(/(#.+)|#$/,"$1")}function cc(a,b,d){this.$$html5=!0;d=d||""; +fd(a,this);this.$$parse=function(a){var d=pa(b,a);if(!E(d))throw Db("ipthprfx",a,b);gd(d,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Qb(this.$$search),d=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(a?"?"+a:"")+d;this.$$absUrl=b+this.$$url.substr(1)};this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;y(f=pa(a,c))?(g=f,g=y(f=pa(d,f))?b+(pa("/",f)||f):a+g):y(f=pa(b,c))?g=b+f:b==c+"/"&&(g=b);g&&this.$$parse(g); +return!!g}}function dc(a,b,d){fd(a,this);this.$$parse=function(c){var e=pa(a,c)||pa(b,c),f;q(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",q(e)&&(a=c,this.replace())):(f=pa(d,e),q(f)&&(f=e));gd(f,this);c=this.$$path;var e=a,g=/^\/[A-Z]:(\/.*)/;0===f.indexOf(e)&&(f=f.replace(e,""));g.exec(f)||(c=(f=g.exec(c))?f[1]:c);this.$$path=c;this.$$compose()};this.$$compose=function(){var b=Qb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl=a+(this.$$url? +d+this.$$url:"")};this.$$parseLinkUrl=function(b,d){return Fa(a)==Fa(b)?(this.$$parse(b),!0):!1}}function hd(a,b,d){this.$$html5=!0;dc.apply(this,arguments);this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;a==Fa(c)?f=c:(g=pa(b,c))?f=a+d+g:b===c+"/"&&(f=b);f&&this.$$parse(f);return!!f};this.$$compose=function(){var b=Qb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl=a+d+this.$$url}}function Eb(a){return function(){return this[a]}} +function id(a,b){return function(d){if(q(d))return this[a];this[a]=b(d);this.$$compose();return this}}function hf(){var a="",b={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(b){return y(b)?(a=b,this):a};this.html5Mode=function(a){return $a(a)?(b.enabled=a,this):H(a)?($a(a.enabled)&&(b.enabled=a.enabled),$a(a.requireBase)&&(b.requireBase=a.requireBase),$a(a.rewriteLinks)&&(b.rewriteLinks=a.rewriteLinks),this):b};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window", +function(d,c,e,f,g){function h(a,b,d){var e=l.url(),f=l.$$state;try{c.url(a,b,d),l.$$state=c.state()}catch(g){throw l.url(e),l.$$state=f,g;}}function k(a,b){d.$broadcast("$locationChangeSuccess",l.absUrl(),a,l.$$state,b)}var l,m;m=c.baseHref();var r=c.url(),t;if(b.enabled){if(!m&&b.requireBase)throw Db("nobase");t=r.substring(0,r.indexOf("/",r.indexOf("//")+2))+(m||"/");m=e.history?cc:hd}else t=Fa(r),m=dc;var A=t.substr(0,Fa(t).lastIndexOf("/")+1);l=new m(t,A,"#"+a);l.$$parseLinkUrl(r,r);l.$$state= +c.state();var v=/^\s*(javascript|mailto):/i;f.on("click",function(a){if(b.rewriteLinks&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&2!=a.which&&2!=a.button){for(var e=B(a.target);"a"!==ta(e[0]);)if(e[0]===f[0]||!(e=e.parent())[0])return;var h=e.prop("href"),k=e.attr("href")||e.attr("xlink:href");H(h)&&"[object SVGAnimatedString]"===h.toString()&&(h=wa(h.animVal).href);v.test(h)||!h||e.attr("target")||a.isDefaultPrevented()||!l.$$parseLinkUrl(h,k)||(a.preventDefault(),l.absUrl()!=c.url()&&(d.$apply(),g.angular["ff-684208-preventDefault"]= +!0))}});ib(l.absUrl())!=ib(r)&&c.url(l.absUrl(),!0);var n=!0;c.onUrlChange(function(a,b){q(pa(A,a))?g.location.href=a:(d.$evalAsync(function(){var c=l.absUrl(),e=l.$$state,f;a=ib(a);l.$$parse(a);l.$$state=b;f=d.$broadcast("$locationChangeStart",a,c,b,e).defaultPrevented;l.absUrl()===a&&(f?(l.$$parse(c),l.$$state=e,h(c,!1,e)):(n=!1,k(c,e)))}),d.$$phase||d.$digest())});d.$watch(function(){var a=ib(c.url()),b=ib(l.absUrl()),f=c.state(),g=l.$$replace,m=a!==b||l.$$html5&&e.history&&f!==l.$$state;if(n|| +m)n=!1,d.$evalAsync(function(){var b=l.absUrl(),c=d.$broadcast("$locationChangeStart",b,a,l.$$state,f).defaultPrevented;l.absUrl()===b&&(c?(l.$$parse(a),l.$$state=f):(m&&h(b,g,f===l.$$state?null:l.$$state),k(a,f)))});l.$$replace=!1});return l}]}function jf(){var a=!0,b=this;this.debugEnabled=function(b){return y(b)?(a=b,this):a};this.$get=["$window",function(d){function c(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&& +(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=d.console||{},e=b[a]||b.log||x;a=!1;try{a=!!e.apply}catch(k){}return a?function(){var a=[];n(arguments,function(b){a.push(c(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){a&&c.apply(b,arguments)}}()}}]}function Va(a,b){if("__defineGetter__"===a||"__defineSetter__"===a||"__lookupGetter__"===a||"__lookupSetter__"=== +a||"__proto__"===a)throw ba("isecfld",b);return a}function jd(a,b){a+="";if(!E(a))throw ba("iseccst",b);return a}function xa(a,b){if(a){if(a.constructor===a)throw ba("isecfn",b);if(a.window===a)throw ba("isecwindow",b);if(a.children&&(a.nodeName||a.prop&&a.attr&&a.find))throw ba("isecdom",b);if(a===Object)throw ba("isecobj",b);}return a}function kd(a,b){if(a){if(a.constructor===a)throw ba("isecfn",b);if(a===Wf||a===Xf||a===Yf)throw ba("isecff",b);}}function ld(a,b){if(a&&(a===(0).constructor||a=== +(!1).constructor||a==="".constructor||a==={}.constructor||a===[].constructor||a===Function.constructor))throw ba("isecaf",b);}function Zf(a,b){return"undefined"!==typeof a?a:b}function md(a,b){return"undefined"===typeof a?b:"undefined"===typeof b?a:a+b}function W(a,b){var d,c;switch(a.type){case s.Program:d=!0;n(a.body,function(a){W(a.expression,b);d=d&&a.expression.constant});a.constant=d;break;case s.Literal:a.constant=!0;a.toWatch=[];break;case s.UnaryExpression:W(a.argument,b);a.constant=a.argument.constant; +a.toWatch=a.argument.toWatch;break;case s.BinaryExpression:W(a.left,b);W(a.right,b);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.left.toWatch.concat(a.right.toWatch);break;case s.LogicalExpression:W(a.left,b);W(a.right,b);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.constant?[]:[a];break;case s.ConditionalExpression:W(a.test,b);W(a.alternate,b);W(a.consequent,b);a.constant=a.test.constant&&a.alternate.constant&&a.consequent.constant;a.toWatch=a.constant?[]:[a];break;case s.Identifier:a.constant= +!1;a.toWatch=[a];break;case s.MemberExpression:W(a.object,b);a.computed&&W(a.property,b);a.constant=a.object.constant&&(!a.computed||a.property.constant);a.toWatch=[a];break;case s.CallExpression:d=a.filter?!b(a.callee.name).$stateful:!1;c=[];n(a.arguments,function(a){W(a,b);d=d&&a.constant;a.constant||c.push.apply(c,a.toWatch)});a.constant=d;a.toWatch=a.filter&&!b(a.callee.name).$stateful?c:[a];break;case s.AssignmentExpression:W(a.left,b);W(a.right,b);a.constant=a.left.constant&&a.right.constant; +a.toWatch=[a];break;case s.ArrayExpression:d=!0;c=[];n(a.elements,function(a){W(a,b);d=d&&a.constant;a.constant||c.push.apply(c,a.toWatch)});a.constant=d;a.toWatch=c;break;case s.ObjectExpression:d=!0;c=[];n(a.properties,function(a){W(a.value,b);d=d&&a.value.constant;a.value.constant||c.push.apply(c,a.value.toWatch)});a.constant=d;a.toWatch=c;break;case s.ThisExpression:a.constant=!1,a.toWatch=[]}}function nd(a){if(1==a.length){a=a[0].expression;var b=a.toWatch;return 1!==b.length?b:b[0]!==a?b:u}} +function od(a){return a.type===s.Identifier||a.type===s.MemberExpression}function pd(a){if(1===a.body.length&&od(a.body[0].expression))return{type:s.AssignmentExpression,left:a.body[0].expression,right:{type:s.NGValueParameter},operator:"="}}function qd(a){return 0===a.body.length||1===a.body.length&&(a.body[0].expression.type===s.Literal||a.body[0].expression.type===s.ArrayExpression||a.body[0].expression.type===s.ObjectExpression)}function rd(a,b){this.astBuilder=a;this.$filter=b}function sd(a, +b){this.astBuilder=a;this.$filter=b}function Fb(a){return"constructor"==a}function ec(a){return z(a.valueOf)?a.valueOf():$f.call(a)}function kf(){var a=$(),b=$();this.$get=["$filter",function(d){function c(a,b){return null==a||null==b?a===b:"object"===typeof a&&(a=ec(a),"object"===typeof a)?!1:a===b||a!==a&&b!==b}function e(a,b,d,e,f){var g=e.inputs,h;if(1===g.length){var k=c,g=g[0];return a.$watch(function(a){var b=g(a);c(b,k)||(h=e(a,u,u,[b]),k=b&&ec(b));return h},b,d,f)}for(var l=[],m=[],r=0,n= +g.length;r=this.promise.$$state.status&&d&&d.length&&a(function(){for(var a,e,f=0,g=d.length;fa)for(b in l++,f)qa.call(e,b)||(n--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,g,k=1n&&(v=4-n,q[v]||(q[v]=[]),q[v].push({msg:z(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,newVal:f,oldVal:h}));else if(a===c){r=!1;break a}}catch(y){g(y)}if(!(l=A.$$watchersCount&&A.$$childHead||A!==this&&A.$$nextSibling))for(;A!==this&&!(l=A.$$nextSibling);)A=A.$parent}while(A=l);if((r||u.length)&&!n--)throw w.$$phase=null,d("infdig", +b,q);}while(r||u.length);for(w.$$phase=null;L.length;)try{L.shift()()}catch(x){g(x)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this===w&&k.$$applicationDestroyed();A(this,-this.$$watchersCount);for(var b in this.$$listenerCount)v(this,this.$$listenerCount[b],b);a&&a.$$childHead==this&&(a.$$childHead=this.$$nextSibling);a&&a.$$childTail==this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling= +this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=x;this.$on=this.$watch=this.$watchGroup=function(){return x};this.$$listeners={};this.$$nextSibling=null;m(this)}},$eval:function(a,b){return h(a)(this,b)},$evalAsync:function(a,b){w.$$phase||u.length||k.defer(function(){u.length&&w.$digest()});u.push({scope:this,expression:a,locals:b})},$$postDigest:function(a){L.push(a)},$apply:function(a){try{t("$apply"); +try{return this.$eval(a)}finally{w.$$phase=null}}catch(b){g(b)}finally{try{w.$digest()}catch(c){throw g(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&aa.push(b);C()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,v(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,f=!1,h= +{name:a,targetScope:e,stopPropagation:function(){f=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=cb([h],arguments,1),l,m;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(m=d.length;lHa)throw ya("iequirks");var c=ia(la);c.isEnabled=function(){return a};c.trustAs=d.trustAs;c.getTrusted=d.getTrusted;c.valueOf=d.valueOf;a||(c.trustAs=c.getTrusted=function(a,b){return b},c.valueOf=Ya);c.parseAs=function(a,d){var e=b(d);return e.literal&&e.constant?e:b(d,function(b){return c.getTrusted(a,b)})};var e=c.parseAs,f=c.getTrusted,g=c.trustAs;n(la,function(a, +b){var d=F(b);c[fb("parse_as_"+d)]=function(b){return e(a,b)};c[fb("get_trusted_"+d)]=function(b){return f(a,b)};c[fb("trust_as_"+d)]=function(b){return g(a,b)}});return c}]}function qf(){this.$get=["$window","$document",function(a,b){var d={},c=ea((/android (\d+)/.exec(F((a.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((a.navigator||{}).userAgent),f=b[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,k=f.body&&f.body.style,l=!1,m=!1;if(k){for(var r in k)if(l=h.exec(r)){g=l[0];g=g.substr(0,1).toUpperCase()+ +g.substr(1);break}g||(g="WebkitOpacity"in k&&"webkit");l=!!("transition"in k||g+"Transition"in k);m=!!("animation"in k||g+"Animation"in k);!c||l&&m||(l=E(k.webkitTransition),m=E(k.webkitAnimation))}return{history:!(!a.history||!a.history.pushState||4>c||e),hasEvent:function(a){if("input"===a&&11>=Ha)return!1;if(q(d[a])){var b=f.createElement("div");d[a]="on"+a in b}return d[a]},csp:Ba(),vendorPrefix:g,transitions:l,animations:m,android:c}}]}function sf(){this.$get=["$templateCache","$http","$q","$sce", +function(a,b,d,c){function e(f,g){e.totalPendingRequests++;E(f)&&a.get(f)||(f=c.getTrustedResourceUrl(f));var h=b.defaults&&b.defaults.transformResponse;I(h)?h=h.filter(function(a){return a!==$b}):h===$b&&(h=null);return b.get(f,{cache:a,transformResponse:h})["finally"](function(){e.totalPendingRequests--}).then(function(b){a.put(f,b.data);return b.data},function(a){if(!g)throw ha("tpload",f,a.status,a.statusText);return d.reject(a)})}e.totalPendingRequests=0;return e}]}function tf(){this.$get=["$rootScope", +"$browser","$location",function(a,b,d){return{findBindings:function(a,b,d){a=a.getElementsByClassName("ng-binding");var g=[];n(a,function(a){var c=fa.element(a).data("$binding");c&&n(c,function(c){d?(new RegExp("(^|\\s)"+ud(b)+"(\\s|\\||$)")).test(c)&&g.push(a):-1!=c.indexOf(b)&&g.push(a)})});return g},findModels:function(a,b,d){for(var g=["ng-","data-ng-","ng\\:"],h=0;ha;a=Math.abs(a);var g=Infinity===a;if(!g&&!isFinite(a))return"";var h=a+"",k="",l=!1,m=[];g&&(k="\u221e");if(!g&&-1!==h.indexOf("e")){var r=h.match(/([\d\.]+)e(-?)(\d+)/);r&&"-"==r[2]&&r[3]>e+1?a=0:(k=h,l=!0)}if(g||l)0a&&(k=a.toFixed(e),a=parseFloat(k),k=k.replace(ic,c));else{g=(h.split(ic)[1]||"").length; +q(e)&&(e=Math.min(Math.max(b.minFrac,g),b.maxFrac));a=+(Math.round(+(a.toString()+"e"+e)).toString()+"e"+-e);var g=(""+a).split(ic),h=g[0],g=g[1]||"",r=0,t=b.lgSize,n=b.gSize;if(h.length>=t+n)for(r=h.length-t,l=0;la&&(c="-",a=-a);for(a=""+a;a.length-d)e+=d;0===e&&-12==d&&(e=12);return Gb(e,b,c)}}function Hb(a,b){return function(d,c){var e=d["get"+a](),f=sb(b?"SHORT"+a:a);return c[f][e]}}function Dd(a){var b=(new Date(a,0,1)).getDay();return new Date(a,0,(4>=b?5:12)-b)}function Ed(a){return function(b){var d=Dd(b.getFullYear());b=+new Date(b.getFullYear(),b.getMonth(),b.getDate()+(4-b.getDay()))- ++d;b=1+Math.round(b/6048E5);return Gb(b,a)}}function jc(a,b){return 0>=a.getFullYear()?b.ERAS[0]:b.ERAS[1]}function zd(a){function b(a){var b;if(b=a.match(d)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,k=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=ea(b[9]+b[10]),g=ea(b[9]+b[11]));h.call(a,ea(b[1]),ea(b[2])-1,ea(b[3]));f=ea(b[4]||0)-f;g=ea(b[5]||0)-g;h=ea(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));k.call(a,f,g,h,b)}return a}var d=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; +return function(c,d,f){var g="",h=[],k,l;d=d||"mediumDate";d=a.DATETIME_FORMATS[d]||d;E(c)&&(c=hg.test(c)?ea(c):b(c));Q(c)&&(c=new Date(c));if(!da(c)||!isFinite(c.getTime()))return c;for(;d;)(l=ig.exec(d))?(h=cb(h,l,1),d=h.pop()):(h.push(d),d=null);var m=c.getTimezoneOffset();f&&(m=vc(f,c.getTimezoneOffset()),c=Pb(c,f,!0));n(h,function(b){k=jg[b];g+=k?k(c,a.DATETIME_FORMATS,m):b.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function cg(){return function(a,b){q(b)&&(b=2);return db(a,b)}}function dg(){return function(a, +b,d){b=Infinity===Math.abs(Number(b))?Number(b):ea(b);if(isNaN(b))return a;Q(a)&&(a=a.toString());if(!I(a)&&!E(a))return a;d=!d||isNaN(d)?0:ea(d);d=0>d?Math.max(0,a.length+d):d;return 0<=b?a.slice(d,d+b):0===d?a.slice(b,a.length):a.slice(Math.max(0,d+b),d)}}function Bd(a){function b(b,d){d=d?-1:1;return b.map(function(b){var c=1,h=Ya;if(z(b))h=b;else if(E(b)){if("+"==b.charAt(0)||"-"==b.charAt(0))c="-"==b.charAt(0)?-1:1,b=b.substring(1);if(""!==b&&(h=a(b),h.constant))var k=h(),h=function(a){return a[k]}}return{get:h, +descending:c*d}})}function d(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}return function(a,e,f){if(!za(a))return a;I(e)||(e=[e]);0===e.length&&(e=["+"]);var g=b(e,f);g.push({get:function(){return{}},descending:f?-1:1});a=Array.prototype.map.call(a,function(a,b){return{value:a,predicateValues:g.map(function(c){var e=c.get(a);c=typeof e;if(null===e)c="string",e="null";else if("string"===c)e=e.toLowerCase();else if("object"===c)a:{if("function"===typeof e.valueOf&& +(e=e.valueOf(),d(e)))break a;if(qc(e)&&(e=e.toString(),d(e)))break a;e=b}return{value:e,type:c}})}});a.sort(function(a,b){for(var c=0,d=0,e=g.length;db||37<=b&&40>=b||m(a,this,this.value)});if(e.hasEvent("paste"))b.on("paste cut", +m)}b.on("change",k);c.$render=function(){var a=c.$isEmpty(c.$viewValue)?"":c.$viewValue;b.val()!==a&&b.val(a)}}function Kb(a,b){return function(d,c){var e,f;if(da(d))return d;if(E(d)){'"'==d.charAt(0)&&'"'==d.charAt(d.length-1)&&(d=d.substring(1,d.length-1));if(kg.test(d))return new Date(d);a.lastIndex=0;if(e=a.exec(d))return e.shift(),f=c?{yyyy:c.getFullYear(),MM:c.getMonth()+1,dd:c.getDate(),HH:c.getHours(),mm:c.getMinutes(),ss:c.getSeconds(),sss:c.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0, +mm:0,ss:0,sss:0},n(e,function(a,c){c=s};g.$observe("min",function(a){s=n(a);h.$validate()})}if(y(g.max)||g.ngMax){var p;h.$validators.max=function(a){return!r(a)||q(p)||d(a)<=p};g.$observe("max",function(a){p=n(a);h.$validate()})}}}function Hd(a,b,d,c){(c.$$hasNativeValidators=H(b[0].validity))&&c.$parsers.push(function(a){var c=b.prop("validity")||{}; +return c.badInput&&!c.typeMismatch?u:a})}function Id(a,b,d,c,e){if(y(c)){a=a(c);if(!a.constant)throw lb("constexpr",d,c);return a(b)}return e}function lc(a,b){a="ngClass"+a;return["$animate",function(d){function c(a,b){var c=[],d=0;a:for(;d(?:<\/\1>|)$/,Tb=/<|&#?\w+;/, +Cf=/<([\w:-]+)/,Df=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,ka={option:[1,'"],thead:[1,"
    {$my_team->get_name()}{$my_team->get_name()|replace:"_":" "}Exercice {$i}
    ","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ka.optgroup=ka.option;ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead;ka.th=ka.td;var Kf=Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)& +16)},Pa=N.prototype={ready:function(a){function b(){d||(d=!0,a())}var d=!1;"complete"===X.readyState?setTimeout(b):(this.on("DOMContentLoaded",b),N(S).on("load",b))},toString:function(){var a=[];n(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<=a?B(this[a]):B(this[this.length+a])},length:0,push:mg,sort:[].sort,splice:[].splice},Cb={};n("multiple selected checked disabled readOnly required open".split(" "),function(a){Cb[F(a)]=a});var Rc={};n("input select option textarea button form details".split(" "), +function(a){Rc[a]=!0});var Zc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};n({data:Wb,removeData:vb,hasData:function(a){for(var b in gb[a.ng339])return!0;return!1}},function(a,b){N[b]=a});n({data:Wb,inheritedData:Bb,scope:function(a){return B.data(a,"$scope")||Bb(a.parentNode||a,["$isolateScope","$scope"])},isolateScope:function(a){return B.data(a,"$isolateScope")||B.data(a,"$isolateScopeNoTemplate")},controller:Oc,injector:function(a){return Bb(a, +"$injector")},removeAttr:function(a,b){a.removeAttribute(b)},hasClass:yb,css:function(a,b,d){b=fb(b);if(y(d))a.style[b]=d;else return a.style[b]},attr:function(a,b,d){var c=a.nodeType;if(c!==Na&&2!==c&&8!==c)if(c=F(b),Cb[c])if(y(d))d?(a[b]=!0,a.setAttribute(b,c)):(a[b]=!1,a.removeAttribute(c));else return a[b]||(a.attributes.getNamedItem(b)||x).specified?c:u;else if(y(d))a.setAttribute(b,d);else if(a.getAttribute)return a=a.getAttribute(b,2),null===a?u:a},prop:function(a,b,d){if(y(d))a[b]=d;else return a[b]}, +text:function(){function a(a,d){if(q(d)){var c=a.nodeType;return 1===c||c===Na?a.textContent:""}a.textContent=d}a.$dv="";return a}(),val:function(a,b){if(q(b)){if(a.multiple&&"select"===ta(a)){var d=[];n(a.options,function(a){a.selected&&d.push(a.value||a.text)});return 0===d.length?null:d}return a.value}a.value=b},html:function(a,b){if(q(b))return a.innerHTML;ub(a,!0);a.innerHTML=b},empty:Pc},function(a,b){N.prototype[b]=function(b,c){var e,f,g=this.length;if(a!==Pc&&q(2==a.length&&a!==yb&&a!==Oc? +b:c)){if(H(b)){for(e=0;e <= >= && || ! = |".split(" "),function(a){Lb[a]=!0});var sg={n:"\n",f:"\f",r:"\r", +t:"\t",v:"\v","'":"'",'"':'"'},fc=function(a){this.options=a};fc.prototype={constructor:fc,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a|| +"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,b,d){d=d||this.index;b=y(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw ba("lexerr",a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index","<=",">=");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),b;b=this.expect("+","-");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:s.BinaryExpression,operator:b.text, +left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:s.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.constants.hasOwnProperty(this.peek().text)?a=bb(this.constants[this.consume().text]):this.peek().identifier?a=this.identifier():this.peek().constant?a=this.constant(): +this.throwError("not a primary expression",this.peek());for(var b;b=this.expect("(","[",".");)"("===b.text?(a={type:s.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===b.text?(a={type:s.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:s.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var b={type:s.CallExpression,callee:this.identifier(), +arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return b},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.expression());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:s.Identifier,name:a.text}},constant:function(){return{type:s.Literal,value:this.consume().value}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break; +a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:s.ArrayExpression,elements:a}},object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;b={type:s.Property,kind:"init"};this.peek().constant?b.key=this.constant():this.peek().identifier?b.key=this.identifier():this.throwError("invalid key",this.peek());this.consume(":");b.value=this.expression();a.push(b)}while(this.expect(","))}this.consume("}");return{type:s.ObjectExpression,properties:a}}, +throwError:function(a,b){throw ba("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0===this.tokens.length)throw ba("ueoe",this.text);var b=this.expect(a);b||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return b},peekToken:function(){if(0===this.tokens.length)throw ba("ueoe",this.text);return this.tokens[0]},peek:function(a,b,d,c){return this.peekAhead(0,a,b,d,c)},peekAhead:function(a,b,d,c,e){if(this.tokens.length>a){a=this.tokens[a]; +var f=a.text;if(f===b||f===d||f===c||f===e||!(b||d||c||e))return a}return!1},expect:function(a,b,d,c){return(a=this.peek(a,b,d,c))?(this.tokens.shift(),a):!1},constants:{"true":{type:s.Literal,value:!0},"false":{type:s.Literal,value:!1},"null":{type:s.Literal,value:null},undefined:{type:s.Literal,value:u},"this":{type:s.ThisExpression}}};rd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.state={nextId:0,filters:{},expensiveChecks:b,fn:{vars:[],body:[],own:{}},assign:{vars:[], +body:[],own:{}},inputs:[]};W(c,d.$filter);var e="",f;this.stage="assign";if(f=pd(c))this.state.computing="assign",e=this.nextId(),this.recurse(f,e),this.return_(e),e="fn.assign="+this.generateFunction("assign","s,v,l");f=nd(c.body);d.stage="inputs";n(f,function(a,b){var c="fn"+b;d.state[c]={vars:[],body:[],own:{}};d.state.computing=c;var e=d.nextId();d.recurse(a,e);d.return_(e);d.state.inputs.push(c);a.watchId=b});this.state.computing="fn";this.stage="main";this.recurse(c);e='"'+this.USE+" "+this.STRICT+ +'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+e+this.watchFns()+"return fn;";e=(new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","getStringValue","ensureSafeAssignContext","ifDefined","plus","text",e))(this.$filter,Va,xa,kd,jd,ld,Zf,md,a);this.state=this.stage=u;e.literal=qd(c);e.constant=c.constant;return e},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;n(b,function(b){a.push("var "+b+"="+d.generateFunction(b, +"s"))});b.length&&a.push("fn.inputs=["+b.join(",")+"];");return a.join("")},generateFunction:function(a,b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;n(this.state.filters,function(d,c){a.push(d+"=$filter("+b.escape(c)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,b, +d,c,e,f){var g,h,k=this,l,m;c=c||x;if(!f&&y(a.watchId))b=b||this.nextId(),this.if_("i",this.lazyAssign(b,this.computedMember("i",a.watchId)),this.lazyRecurse(a,b,d,c,e,!0));else switch(a.type){case s.Program:n(a.body,function(b,c){k.recurse(b.expression,u,u,function(a){h=a});c!==a.body.length-1?k.current().body.push(h,";"):k.return_(h)});break;case s.Literal:m=this.escape(a.value);this.assign(b,m);c(m);break;case s.UnaryExpression:this.recurse(a.argument,u,u,function(a){h=a});m=a.operator+"("+this.ifDefined(h, +0)+")";this.assign(b,m);c(m);break;case s.BinaryExpression:this.recurse(a.left,u,u,function(a){g=a});this.recurse(a.right,u,u,function(a){h=a});m="+"===a.operator?this.plus(g,h):"-"===a.operator?this.ifDefined(g,0)+a.operator+this.ifDefined(h,0):"("+g+")"+a.operator+"("+h+")";this.assign(b,m);c(m);break;case s.LogicalExpression:b=b||this.nextId();k.recurse(a.left,b);k.if_("&&"===a.operator?b:k.not(b),k.lazyRecurse(a.right,b));c(b);break;case s.ConditionalExpression:b=b||this.nextId();k.recurse(a.test, +b);k.if_(b,k.lazyRecurse(a.alternate,b),k.lazyRecurse(a.consequent,b));c(b);break;case s.Identifier:b=b||this.nextId();d&&(d.context="inputs"===k.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);Va(a.name);k.if_("inputs"===k.stage||k.not(k.getHasOwnProperty("l",a.name)),function(){k.if_("inputs"===k.stage||"s",function(){e&&1!==e&&k.if_(k.not(k.nonComputedMember("s",a.name)),k.lazyAssign(k.nonComputedMember("s",a.name),"{}"));k.assign(b,k.nonComputedMember("s", +a.name))})},b&&k.lazyAssign(b,k.nonComputedMember("l",a.name)));(k.state.expensiveChecks||Fb(a.name))&&k.addEnsureSafeObject(b);c(b);break;case s.MemberExpression:g=d&&(d.context=this.nextId())||this.nextId();b=b||this.nextId();k.recurse(a.object,g,u,function(){k.if_(k.notNull(g),function(){if(a.computed)h=k.nextId(),k.recurse(a.property,h),k.getStringValue(h),k.addEnsureSafeMemberName(h),e&&1!==e&&k.if_(k.not(k.computedMember(g,h)),k.lazyAssign(k.computedMember(g,h),"{}")),m=k.ensureSafeObject(k.computedMember(g, +h)),k.assign(b,m),d&&(d.computed=!0,d.name=h);else{Va(a.property.name);e&&1!==e&&k.if_(k.not(k.nonComputedMember(g,a.property.name)),k.lazyAssign(k.nonComputedMember(g,a.property.name),"{}"));m=k.nonComputedMember(g,a.property.name);if(k.state.expensiveChecks||Fb(a.property.name))m=k.ensureSafeObject(m);k.assign(b,m);d&&(d.computed=!1,d.name=a.property.name)}},function(){k.assign(b,"undefined")});c(b)},!!e);break;case s.CallExpression:b=b||this.nextId();a.filter?(h=k.filter(a.callee.name),l=[],n(a.arguments, +function(a){var b=k.nextId();k.recurse(a,b);l.push(b)}),m=h+"("+l.join(",")+")",k.assign(b,m),c(b)):(h=k.nextId(),g={},l=[],k.recurse(a.callee,h,g,function(){k.if_(k.notNull(h),function(){k.addEnsureSafeFunction(h);n(a.arguments,function(a){k.recurse(a,k.nextId(),u,function(a){l.push(k.ensureSafeObject(a))})});g.name?(k.state.expensiveChecks||k.addEnsureSafeObject(g.context),m=k.member(g.context,g.name,g.computed)+"("+l.join(",")+")"):m=h+"("+l.join(",")+")";m=k.ensureSafeObject(m);k.assign(b,m)}, +function(){k.assign(b,"undefined")});c(b)}));break;case s.AssignmentExpression:h=this.nextId();g={};if(!od(a.left))throw ba("lval");this.recurse(a.left,u,g,function(){k.if_(k.notNull(g.context),function(){k.recurse(a.right,h);k.addEnsureSafeObject(k.member(g.context,g.name,g.computed));k.addEnsureSafeAssignContext(g.context);m=k.member(g.context,g.name,g.computed)+a.operator+h;k.assign(b,m);c(b||m)})},1);break;case s.ArrayExpression:l=[];n(a.elements,function(a){k.recurse(a,k.nextId(),u,function(a){l.push(a)})}); +m="["+l.join(",")+"]";this.assign(b,m);c(m);break;case s.ObjectExpression:l=[];n(a.properties,function(a){k.recurse(a.value,k.nextId(),u,function(b){l.push(k.escape(a.key.type===s.Identifier?a.key.name:""+a.key.value)+":"+b)})});m="{"+l.join(",")+"}";this.assign(b,m);c(m);break;case s.ThisExpression:this.assign(b,"s");c("s");break;case s.NGValueParameter:this.assign(b,"v"),c("v")}},getHasOwnProperty:function(a,b){var d=a+"."+b,c=this.current().own;c.hasOwnProperty(d)||(c[d]=this.nextId(!1,a+"&&("+ +this.escape(b)+" in "+a+")"));return c[d]},assign:function(a,b){if(a)return this.current().body.push(a,"=",b,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,b){return"ifDefined("+a+","+this.escape(b)+")"},plus:function(a,b){return"plus("+a+","+b+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,b,d){if(!0===a)b();else{var c=this.current().body;c.push("if(",a, +"){");b();c.push("}");d&&(c.push("else{"),d(),c.push("}"))}},not:function(a){return"!("+a+")"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,b){return a+"."+b},computedMember:function(a,b){return a+"["+b+"]"},member:function(a,b,d){return d?this.computedMember(a,b):this.nonComputedMember(a,b)},addEnsureSafeObject:function(a){this.current().body.push(this.ensureSafeObject(a),";")},addEnsureSafeMemberName:function(a){this.current().body.push(this.ensureSafeMemberName(a),";")}, +addEnsureSafeFunction:function(a){this.current().body.push(this.ensureSafeFunction(a),";")},addEnsureSafeAssignContext:function(a){this.current().body.push(this.ensureSafeAssignContext(a),";")},ensureSafeObject:function(a){return"ensureSafeObject("+a+",text)"},ensureSafeMemberName:function(a){return"ensureSafeMemberName("+a+",text)"},ensureSafeFunction:function(a){return"ensureSafeFunction("+a+",text)"},getStringValue:function(a){this.assign(a,"getStringValue("+a+",text)")},ensureSafeAssignContext:function(a){return"ensureSafeAssignContext("+ +a+",text)"},lazyRecurse:function(a,b,d,c,e,f){var g=this;return function(){g.recurse(a,b,d,c,e,f)}},lazyAssign:function(a,b){var d=this;return function(){d.assign(a,b)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(E(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(Q(a))return a.toString();if(!0===a)return"true";if(!1===a)return"false";if(null===a)return"null";if("undefined"=== +typeof a)return"undefined";throw ba("esc");},nextId:function(a,b){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(b?"="+b:""));return d},current:function(){return this.state[this.state.computing]}};sd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.expression=a;this.expensiveChecks=b;W(c,d.$filter);var e,f;if(e=pd(c))f=this.recurse(e);e=nd(c.body);var g;e&&(g=[],n(e,function(a,b){var c=d.recurse(a);a.input=c;g.push(c);a.watchId=b}));var h=[];n(c.body,function(a){h.push(d.recurse(a.expression))}); +e=0===c.body.length?function(){}:1===c.body.length?h[0]:function(a,b){var c;n(h,function(d){c=d(a,b)});return c};f&&(e.assign=function(a,b,c){return f(a,c,b)});g&&(e.inputs=g);e.literal=qd(c);e.constant=c.constant;return e},recurse:function(a,b,d){var c,e,f=this,g;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case s.Literal:return this.value(a.value,b);case s.UnaryExpression:return e=this.recurse(a.argument),this["unary"+a.operator](e,b);case s.BinaryExpression:return c=this.recurse(a.left), +e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case s.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case s.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case s.Identifier:return Va(a.name,f.expression),f.identifier(a.name,f.expensiveChecks||Fb(a.name),b,d,f.expression);case s.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed||(Va(a.property.name, +f.expression),e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d,f.expression):this.nonComputedMember(c,e,f.expensiveChecks,b,d,f.expression);case s.CallExpression:return g=[],n(a.arguments,function(a){g.push(f.recurse(a))}),a.filter&&(e=this.$filter(a.callee.name)),a.filter||(e=this.recurse(a.callee,!0)),a.filter?function(a,c,d,f){for(var r=[],n=0;n":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>b(c,e,f,g);return d?{value:c}:c}},"binary<=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)<=b(c,e,f,g);return d?{value:c}:c}},"binary>=":function(a,b,d){return function(c, +e,f,g){c=a(c,e,f,g)>=b(c,e,f,g);return d?{value:c}:c}},"binary&&":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)&&b(c,e,f,g);return d?{value:c}:c}},"binary||":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)||b(c,e,f,g);return d?{value:c}:c}},"ternary?:":function(a,b,d,c){return function(e,f,g,h){e=a(e,f,g,h)?b(e,f,g,h):d(e,f,g,h);return c?{value:e}:e}},value:function(a,b){return function(){return b?{context:u,name:u,value:a}:a}},identifier:function(a,b,d,c,e){return function(f,g,h,k){f= +g&&a in g?g:f;c&&1!==c&&f&&!f[a]&&(f[a]={});g=f?f[a]:u;b&&xa(g,e);return d?{context:f,name:a,value:g}:g}},computedMember:function(a,b,d,c,e){return function(f,g,h,k){var l=a(f,g,h,k),m,n;null!=l&&(m=b(f,g,h,k),m=jd(m),Va(m,e),c&&1!==c&&l&&!l[m]&&(l[m]={}),n=l[m],xa(n,e));return d?{context:l,name:m,value:n}:n}},nonComputedMember:function(a,b,d,c,e,f){return function(g,h,k,l){g=a(g,h,k,l);e&&1!==e&&g&&!g[b]&&(g[b]={});h=null!=g?g[b]:u;(d||Fb(b))&&xa(h,f);return c?{context:g,name:b,value:h}:h}},inputs:function(a, +b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};var gc=function(a,b,d){this.lexer=a;this.$filter=b;this.options=d;this.ast=new s(this.lexer);this.astCompiler=d.csp?new sd(this.ast,b):new rd(this.ast,b)};gc.prototype={constructor:gc,parse:function(a){return this.astCompiler.compile(a,this.options.expensiveChecks)}};$();$();var $f=Object.prototype.valueOf,ya=G("$sce"),la={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},ha=G("$compile"),Y=X.createElement("a"),wd=wa(S.location.href); +xd.$inject=["$document"];Jc.$inject=["$provide"];yd.$inject=["$locale"];Ad.$inject=["$locale"];var ic=".",jg={yyyy:ca("FullYear",4),yy:ca("FullYear",2,0,!0),y:ca("FullYear",1),MMMM:Hb("Month"),MMM:Hb("Month",!0),MM:ca("Month",2,1),M:ca("Month",1,1),dd:ca("Date",2),d:ca("Date",1),HH:ca("Hours",2),H:ca("Hours",1),hh:ca("Hours",2,-12),h:ca("Hours",1,-12),mm:ca("Minutes",2),m:ca("Minutes",1),ss:ca("Seconds",2),s:ca("Seconds",1),sss:ca("Milliseconds",3),EEEE:Hb("Day"),EEE:Hb("Day",!0),a:function(a,b){return 12> +a.getHours()?b.AMPMS[0]:b.AMPMS[1]},Z:function(a,b,d){a=-1*d;return a=(0<=a?"+":"")+(Gb(Math[0=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}},ig=/((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,hg=/^\-?\d+$/;zd.$inject=["$locale"];var eg=na(F),fg=na(sb);Bd.$inject=["$parse"];var he=na({restrict:"E",compile:function(a,b){if(!b.href&&!b.xlinkHref)return function(a, +b){if("a"===b[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===sa.call(b.prop("href"))?"xlink:href":"href";b.on("click",function(a){b.attr(e)||a.preventDefault()})}}}}),tb={};n(Cb,function(a,b){function d(a,d,e){a.$watch(e[c],function(a){e.$set(b,!!a)})}if("multiple"!=a){var c=va("ng-"+b),e=d;"checked"===a&&(e=function(a,b,e){e.ngModel!==e[c]&&d(a,b,e)});tb[c]=function(){return{restrict:"A",priority:100,link:e}}}});n(Zc,function(a,b){tb[b]=function(){return{priority:100,link:function(a, +c,e){if("ngPattern"===b&&"/"==e.ngPattern.charAt(0)&&(c=e.ngPattern.match(lg))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});n(["src","srcset","href"],function(a){var b=va("ng-"+a);tb[b]=function(){return{priority:99,link:function(d,c,e){var f=a,g=a;"href"===a&&"[object SVGAnimatedString]"===sa.call(c.prop("href"))&&(g="xlinkHref",e.$attr[g]="xlink:href",f=null);e.$observe(b,function(b){b?(e.$set(g,b),Ha&&f&&c.prop(f,e[g])):"href"===a&&e.$set(g,null)})}}}}); +var Ib={$addControl:x,$$renameControl:function(a,b){a.$name=b},$removeControl:x,$setValidity:x,$setDirty:x,$setPristine:x,$setSubmitted:x};Fd.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var Nd=function(a){return["$timeout","$parse",function(b,d){function c(a){return""===a?d('this[""]').assign:d(a).assign||x}return{name:"form",restrict:a?"EAC":"E",require:["form","^^?form"],controller:Fd,compile:function(d,f){d.addClass(Wa).addClass(mb);var g=f.name?"name":a&&f.ngForm?"ngForm": +!1;return{pre:function(a,d,e,f){var n=f[0];if(!("action"in e)){var q=function(b){a.$apply(function(){n.$commitViewValue();n.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",q,!1);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",q,!1)},0,!1)})}(f[1]||n.$$parentForm).$addControl(n);var s=g?c(n.$name):x;g&&(s(a,n),e.$observe(g,function(b){n.$name!==b&&(s(a,u),n.$$parentForm.$$renameControl(n,b),s=c(n.$name),s(a,n))}));d.on("$destroy",function(){n.$$parentForm.$removeControl(n); +s(a,u);M(n,Ib)})}}}}}]},ie=Nd(),ve=Nd(!0),kg=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,tg=/^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/,ug=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,vg=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,Od=/^(\d{4})-(\d{2})-(\d{2})$/,Pd=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,mc=/^(\d{4})-W(\d\d)$/,Qd=/^(\d{4})-(\d\d)$/, +Rd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Sd={text:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);kc(c)},date:kb("date",Od,Kb(Od,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":kb("datetimelocal",Pd,Kb(Pd,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:kb("time",Rd,Kb(Rd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:kb("week",mc,function(a,b){if(da(a))return a;if(E(a)){mc.lastIndex=0;var d=mc.exec(a);if(d){var c=+d[1],e=+d[2],f=d=0,g=0,h=0,k=Dd(c),e=7*(e-1);b&&(d=b.getHours(),f= +b.getMinutes(),g=b.getSeconds(),h=b.getMilliseconds());return new Date(c,0,k.getDate()+e,d,f,g,h)}}return NaN},"yyyy-Www"),month:kb("month",Qd,Kb(Qd,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f){Hd(a,b,d,c);jb(a,b,d,c,e,f);c.$$parserName="number";c.$parsers.push(function(a){return c.$isEmpty(a)?null:vg.test(a)?parseFloat(a):u});c.$formatters.push(function(a){if(!c.$isEmpty(a)){if(!Q(a))throw lb("numfmt",a);a=a.toString()}return a});if(y(d.min)||d.ngMin){var g;c.$validators.min=function(a){return c.$isEmpty(a)|| +q(g)||a>=g};d.$observe("min",function(a){y(a)&&!Q(a)&&(a=parseFloat(a,10));g=Q(a)&&!isNaN(a)?a:u;c.$validate()})}if(y(d.max)||d.ngMax){var h;c.$validators.max=function(a){return c.$isEmpty(a)||q(h)||a<=h};d.$observe("max",function(a){y(a)&&!Q(a)&&(a=parseFloat(a,10));h=Q(a)&&!isNaN(a)?a:u;c.$validate()})}},url:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);kc(c);c.$$parserName="url";c.$validators.url=function(a,b){var d=a||b;return c.$isEmpty(d)||tg.test(d)}},email:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);kc(c); +c.$$parserName="email";c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)||ug.test(d)}},radio:function(a,b,d,c){q(d.name)&&b.attr("name",++nb);b.on("click",function(a){b[0].checked&&c.$setViewValue(d.value,a&&a.type)});c.$render=function(){b[0].checked=d.value==c.$viewValue};d.$observe("value",c.$render)},checkbox:function(a,b,d,c,e,f,g,h){var k=Id(h,a,"ngTrueValue",d.ngTrueValue,!0),l=Id(h,a,"ngFalseValue",d.ngFalseValue,!1);b.on("click",function(a){c.$setViewValue(b[0].checked,a&& +a.type)});c.$render=function(){b[0].checked=c.$viewValue};c.$isEmpty=function(a){return!1===a};c.$formatters.push(function(a){return ma(a,k)});c.$parsers.push(function(a){return a?k:l})},hidden:x,button:x,submit:x,reset:x,file:x},Dc=["$browser","$sniffer","$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e,f,g,h){h[0]&&(Sd[F(g.type)]||Sd.text)(e,f,g,h[0],b,a,d,c)}}}}],wg=/^(true|false|\d+)$/,Ne=function(){return{restrict:"A",priority:100,compile:function(a, +b){return wg.test(b.ngValue)?function(a,b,e){e.$set("value",a.$eval(e.ngValue))}:function(a,b,e){a.$watch(e.ngValue,function(a){e.$set("value",a)})}}}},ne=["$compile",function(a){return{restrict:"AC",compile:function(b){a.$$addBindingClass(b);return function(b,c,e){a.$$addBindingInfo(c,e.ngBind);c=c[0];b.$watch(e.ngBind,function(a){c.textContent=q(a)?"":a})}}}}],pe=["$interpolate","$compile",function(a,b){return{compile:function(d){b.$$addBindingClass(d);return function(c,d,f){c=a(d.attr(f.$attr.ngBindTemplate)); +b.$$addBindingInfo(d,c.expressions);d=d[0];f.$observe("ngBindTemplate",function(a){d.textContent=q(a)?"":a})}}}}],oe=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g=b(e.ngBindHtml,function(a){return(a||"").toString()});d.$$addBindingClass(c);return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){c.html(a.getTrustedHtml(f(b))||"")})}}}}],Me=na({restrict:"A",require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}), +qe=lc("",!0),se=lc("Odd",0),re=lc("Even",1),te=La({compile:function(a,b){b.$set("ngCloak",u);a.removeClass("ng-cloak")}}),ue=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Ic={},xg={blur:!0,focus:!0};n("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var b=va("ng-"+a);Ic[b]=["$parse","$rootScope",function(d,c){return{restrict:"A",compile:function(e,f){var g= +d(f[b],null,!0);return function(b,d){d.on(a,function(d){var e=function(){g(b,{$event:d})};xg[a]&&c.$$phase?b.$evalAsync(e):b.$apply(e)})}}}}]});var xe=["$animate",function(a){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(b,d,c,e,f){var g,h,k;b.$watch(c.ngIf,function(b){b?h||f(function(b,e){h=e;b[b.length++]=X.createComment(" end ngIf: "+c.ngIf+" ");g={clone:b};a.enter(b,d.parent(),d)}):(k&&(k.remove(),k=null),h&&(h.$destroy(),h=null),g&&(k= +rb(g.clone),a.leave(k).then(function(){k=null}),g=null))})}}}],ye=["$templateRequest","$anchorScroll","$animate",function(a,b,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:fa.noop,compile:function(c,e){var f=e.ngInclude||e.src,g=e.onload||"",h=e.autoscroll;return function(c,e,m,n,q){var s=0,v,u,p,C=function(){u&&(u.remove(),u=null);v&&(v.$destroy(),v=null);p&&(d.leave(p).then(function(){u=null}),u=p,p=null)};c.$watch(f,function(f){var m=function(){!y(h)||h&&!c.$eval(h)|| +b()},u=++s;f?(a(f,!0).then(function(a){if(u===s){var b=c.$new();n.template=a;a=q(b,function(a){C();d.enter(a,null,e).then(m)});v=b;p=a;v.$emit("$includeContentLoaded",f);c.$eval(g)}},function(){u===s&&(C(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(C(),n.template=null)})}}}}],Pe=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(b,d,c,e){/SVG/.test(d[0].toString())?(d.empty(),a(Lc(e.template,X).childNodes)(b,function(a){d.append(a)}, +{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],ze=La({priority:450,compile:function(){return{pre:function(a,b,d){a.$eval(d.ngInit)}}}}),Le=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,b,d,c){var e=b.attr(d.$attr.ngList)||", ",f="false"!==d.ngTrim,g=f?U(e):e;c.$parsers.push(function(a){if(!q(a)){var b=[];a&&n(a.split(g),function(a){a&&b.push(f?U(a):a)});return b}});c.$formatters.push(function(a){return I(a)?a.join(e):u});c.$isEmpty=function(a){return!a|| +!a.length}}}},mb="ng-valid",Jd="ng-invalid",Wa="ng-pristine",Jb="ng-dirty",Ld="ng-pending",lb=G("ngModel"),yg=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,b,d,c,e,f,g,h,k,l){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=u;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1; +this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=u;this.$name=l(d.name||"",!1)(a);this.$$parentForm=Ib;var m=e(d.ngModel),r=m.assign,t=m,s=r,v=null,B,p=this;this.$$setOptions=function(a){if((p.$options=a)&&a.getterSetter){var b=e(d.ngModel+"()"),f=e(d.ngModel+"($$$p)");t=function(a){var c=m(a);z(c)&&(c=b(a));return c};s=function(a,b){z(m(a))?f(a,{$$$p:p.$modelValue}):r(a,p.$modelValue)}}else if(!m.assign)throw lb("nonassign",d.ngModel,ua(c));};this.$render=x;this.$isEmpty= +function(a){return q(a)||""===a||null===a||a!==a};var C=0;Gd({ctrl:this,$element:c,set:function(a,b){a[b]=!0},unset:function(a,b){delete a[b]},$animate:f});this.$setPristine=function(){p.$dirty=!1;p.$pristine=!0;f.removeClass(c,Jb);f.addClass(c,Wa)};this.$setDirty=function(){p.$dirty=!0;p.$pristine=!1;f.removeClass(c,Wa);f.addClass(c,Jb);p.$$parentForm.$setDirty()};this.$setUntouched=function(){p.$touched=!1;p.$untouched=!0;f.setClass(c,"ng-untouched","ng-touched")};this.$setTouched=function(){p.$touched= +!0;p.$untouched=!1;f.setClass(c,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){g.cancel(v);p.$viewValue=p.$$lastCommittedViewValue;p.$render()};this.$validate=function(){if(!Q(p.$modelValue)||!isNaN(p.$modelValue)){var a=p.$$rawModelValue,b=p.$valid,c=p.$modelValue,d=p.$options&&p.$options.allowInvalid;p.$$runValidators(a,p.$$lastCommittedViewValue,function(e){d||b===e||(p.$modelValue=e?a:u,p.$modelValue!==c&&p.$$writeModelToScope())})}};this.$$runValidators=function(a,b,c){function d(){var c= +!0;n(p.$validators,function(d,e){var g=d(a,b);c=c&&g;f(e,g)});return c?!0:(n(p.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;n(p.$asyncValidators,function(e,g){var h=e(a,b);if(!h||!z(h.then))throw lb("$asyncValidators",h);f(g,u);c.push(h.then(function(){f(g,!0)},function(a){d=!1;f(g,!1)}))});c.length?k.all(c).then(function(){g(d)},x):g(!0)}function f(a,b){h===C&&p.$setValidity(a,b)}function g(a){h===C&&c(a)}C++;var h=C;(function(){var a=p.$$parserName||"parse";if(q(B))f(a, +null);else return B||(n(p.$validators,function(a,b){f(b,null)}),n(p.$asyncValidators,function(a,b){f(b,null)})),f(a,B),B;return!0})()?d()?e():g(!1):g(!1)};this.$commitViewValue=function(){var a=p.$viewValue;g.cancel(v);if(p.$$lastCommittedViewValue!==a||""===a&&p.$$hasNativeValidators)p.$$lastCommittedViewValue=a,p.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var b=p.$$lastCommittedViewValue;if(B=q(b)?u:!0)for(var c=0;ce||c.$isEmpty(b)||b.length<=e}}}}},Gc=function(){return{restrict:"A",require:"?ngModel",link:function(a,b,d,c){if(c){var e=0;d.$observe("minlength",function(a){e=ea(a)||0;c.$validate()});c.$validators.minlength=function(a,b){return c.$isEmpty(b)||b.length>=e}}}}};S.angular.bootstrap? +console.log("WARNING: Tried to load angular more than once."):(ce(),ee(fa),fa.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "), +SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4", +negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",pluralCat:function(a,c){var e=a|0,f=c;u===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),B(X).ready(function(){Zd(X,yc)}))})(window,document);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(''); +//# sourceMappingURL=angular.min.js.map diff --git a/admin/static/js/app.js b/admin/static/js/app.js new file mode 100644 index 00000000..5853e29b --- /dev/null +++ b/admin/static/js/app.js @@ -0,0 +1,33 @@ +angular.module("FICApp", ["ngRoute", "ngResource"]) + .config(function($routeProvider, $locationProvider) { + $routeProvider + .when("/teams", { + controller: "TeamsListController", + templateUrl: "views/team-list.html" + }) + .when("/teams/new", { + controller: "TeamNewController", + templateUrl: "views/team-new.html" + }); + $locationProvider.html5Mode(true); + }) + .run(function($rootScope) { + $rootScope.message = "Hello Angular!"; + }); + +angular.module("FICApp") + .factory("Team", function($resource) { + return $resource("/api/teams/:id", { id: '@id' }, { + 'update': { method: "PATCH" } + }) + }); + +angular.module("FICApp") + .controller("TeamsListController", function($scope, Team, $location) { + $scope.teams = Team.query(); + $scope.fields = ["id", "name"]; + + $scope.show = function(id) { + $location.url("/teams/" + id); + }; + }); diff --git a/admin/static/js/bootstrap.min.js b/admin/static/js/bootstrap.min.js new file mode 100644 index 00000000..e79c0651 --- /dev/null +++ b/admin/static/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/admin/static/js/jquery.min.js b/admin/static/js/jquery.min.js new file mode 100644 index 00000000..6c60672f --- /dev/null +++ b/admin/static/js/jquery.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.12.0 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; +return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML="
    a",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:l.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n(" From 5e74b3f7ce98b217dd487aa8a056b80cdc4562c5 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 13 Oct 2016 19:52:13 +0200 Subject: [PATCH 0392/2585] [admin] Can retrieves tries rate --- admin/api_team.go | 4 ++++ libfic/team.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/admin/api_team.go b/admin/api_team.go index da32dee4..3c9f449f 100644 --- a/admin/api_team.go +++ b/admin/api_team.go @@ -85,6 +85,8 @@ func listTeam(args []string, body []byte) (interface{}, error) { return fic.MyJSONTeam(team, true) } else if args[1] == "wait.json" { return fic.MyJSONTeam(team, false) + } else if args[1] == "tries" { + return fic.GetTries(team, nil) } else if team != nil && args[1] == "members" { return team.GetMembers() } else if args[1] == "certificate" && team != nil { @@ -95,6 +97,8 @@ func listTeam(args []string, body []byte) (interface{}, error) { } else if len(args) == 1 { if args[0] == "teams.json" { return fic.ExportTeams() + } else if args[0] == "tries" { + return fic.GetTries(nil, nil) } else if args[0] == "nginx" { return nginxGenTeam() } else if args[0] == "binding" { diff --git a/libfic/team.go b/libfic/team.go index 10d67b72..4be647a4 100644 --- a/libfic/team.go +++ b/libfic/team.go @@ -1,6 +1,7 @@ package fic import ( + "database/sql" "fmt" "time" ) @@ -152,6 +153,61 @@ func (t Team) HasAccess(e Exercice) bool { } } +func NbTry(t *Team, e Exercice) int { + var cnt *int + + if t != nil { + DBQueryRow("SELECT COUNT(*) FROM exercice_tries WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&cnt) + } else { + DBQueryRow("SELECT COUNT(*) FROM exercice_tries WHERE id_exercice = ?", e.Id).Scan(&cnt) + } + + if cnt == nil { + return 0 + } else { + return *cnt + } +} + +func GetTries(t *Team, e *Exercice) ([]time.Time, error) { + var rows *sql.Rows + var err error + + if t == nil { + if e == nil { + rows, err = DBQuery("SELECT time FROM exercice_tries ORDER BY time ASC") + } else { + rows, err = DBQuery("SELECT time FROM exercice_tries WHERE id_exercice = ? ORDER BY time ASC", e.Id) + } + } else { + if e == nil { + rows, err = DBQuery("SELECT time FROM exercice_tries WHERE id_team = ? ORDER BY time ASC", t.Id) + } else { + rows, err = DBQuery("SELECT time FROM exercice_tries WHERE id_team = ? AND id_exercice = ? ORDER BY time ASC", t.Id, e.Id) + } + } + + if err != nil { + return nil, err + } else { + defer rows.Close() + + times := make([]time.Time, 0) + for rows.Next() { + var tm time.Time + if err := rows.Scan(&tm); err != nil { + return nil, err + } + times = append(times, tm) + } + if err := rows.Err(); err != nil { + return nil, err + } + + return times, nil + } +} + func (t Team) HasSolved(e Exercice) (bool, time.Time, int64) { var nb *int64 var tm *time.Time From 017adfb2b15d60a50dcf11102146d1a43e0f8476 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 13 Oct 2016 19:52:40 +0200 Subject: [PATCH 0393/2585] [admin] statistic generation --- admin/api_team.go | 6 +++ libfic/team.go | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/admin/api_team.go b/admin/api_team.go index 3c9f449f..a5ba9a7a 100644 --- a/admin/api_team.go +++ b/admin/api_team.go @@ -85,6 +85,12 @@ func listTeam(args []string, body []byte) (interface{}, error) { return fic.MyJSONTeam(team, true) } else if args[1] == "wait.json" { return fic.MyJSONTeam(team, false) + } else if args[1] == "stats.json" { + if team != nil { + return team.GetStats() + } else { + return fic.GetTeamsStats(nil) + } } else if args[1] == "tries" { return fic.GetTries(team, nil) } else if team != nil && args[1] == "members" { diff --git a/libfic/team.go b/libfic/team.go index 4be647a4..5db84293 100644 --- a/libfic/team.go +++ b/libfic/team.go @@ -226,6 +226,108 @@ func (t Team) HasSolved(e Exercice) (bool, time.Time, int64) { } } +func IsSolved(e Exercice) (int, time.Time) { + var nb *int + var tm *time.Time + if DBQueryRow("SELECT COUNT(id_exercice), MIN(time) FROM exercice_solved WHERE id_exercice = ?", e.Id).Scan(&nb, &tm); nb == nil || tm == nil { + return 0, time.Time{} + } else { + return *nb, *tm + } +} + +type statLine struct { + Tip string `json:"tip"` + Total int `json:"total"` + Solved int `json:"solved"` + Tried int `json:"tried"` + Tries int `json:"tries"` +} + +type teamStats struct { + Levels []statLine `json:"levels"` + Themes []statLine `json:"themes"` +} + +func (s *teamStats) GetLevel(level int) *statLine { + level -= 1 + + for len(s.Levels) <= level { + s.Levels = append(s.Levels, statLine{ + fmt.Sprintf("Level %d", (len(s.Levels) + 1)), + 0, + 0, + 0, + 0, + }) + } + + return &s.Levels[level] +} + +func (t Team) GetStats() (interface{}, error) { + return GetTeamsStats(&t) +} + +func GetTeamsStats(t *Team) (interface{}, error) { + stat := teamStats{} + + if themes, err := GetThemes(); err != nil { + return nil, err + } else { + for _, theme := range themes { + total := 0 + solved := 0 + tried := 0 + tries := 0 + + if exercices, err := theme.GetExercices(); err != nil { + return nil, err + } else { + for _, exercice := range exercices { + var lvl int + if lvl, err = exercice.GetLevel(); err != nil { + return nil, err + } + sLvl := stat.GetLevel(lvl) + + total += 1 + sLvl.Total += 1 + + if t != nil { + if b, _, _ := t.HasSolved(exercice); b { + solved += 1 + sLvl.Solved += 1 + } + } else { + if n, _ := IsSolved(exercice); n > 0 { + solved += 1 + sLvl.Solved += 1 + } + } + + try := NbTry(t, exercice) + if try > 0 { + tried += 1 + tries += try + sLvl.Tried += 1 + sLvl.Tries += try + } + } + } + + stat.Themes = append(stat.Themes, statLine{ + theme.Name, + total, + solved, + tried, + tries, + }) + } + + return stat, nil + } +} type exportedTeam struct { Name string `json:"name"` From 347f317dd9431eb13d2feb11d03b3eead829bd25 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 13 Oct 2016 19:52:54 +0200 Subject: [PATCH 0394/2585] [admin] Improve interface --- admin/static/img/epita.png | Bin 0 -> 39967 bytes admin/static/img/fic.png | Bin 0 -> 40107 bytes admin/static/img/srs.png | Bin 0 -> 29880 bytes admin/static/index.html | 33 +++- admin/static/js/app.js | 338 ++++++++++++++++++++++++++++++++++- admin/static/views/home.html | 9 + admin/static/views/team.html | 54 ++++++ 7 files changed, 421 insertions(+), 13 deletions(-) create mode 100644 admin/static/img/epita.png create mode 100644 admin/static/img/fic.png create mode 100644 admin/static/img/srs.png create mode 100644 admin/static/views/home.html create mode 100644 admin/static/views/team.html diff --git a/admin/static/img/epita.png b/admin/static/img/epita.png new file mode 100644 index 0000000000000000000000000000000000000000..e89f7181dc2b749a4d27d616d0a570e9006f765e GIT binary patch literal 39967 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 literal 0 HcmV?d00001 diff --git a/admin/static/img/fic.png b/admin/static/img/fic.png new file mode 100644 index 0000000000000000000000000000000000000000..7956bd4db0fab2c34246cc7658fb3dd0c95b47b5 GIT binary patch literal 40107 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 D5^Cq@ literal 0 HcmV?d00001 diff --git a/admin/static/img/srs.png b/admin/static/img/srs.png new file mode 100644 index 0000000000000000000000000000000000000000..82294f52864d2244b12f89e20d2cc5e6d5a76aa8 GIT binary patch literal 29880 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 DAqC!t literal 0 HcmV?d00001 diff --git a/admin/static/index.html b/admin/static/index.html index e2142455..c409ffa9 100644 --- a/admin/static/index.html +++ b/admin/static/index.html @@ -2,15 +2,40 @@ - Challenge Forensic FIC 2016 - Administration + Challenge Forensic - Administration + -
    -
    ","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ka.optgroup=ka.option;ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead;ka.th=ka.td;var Kf=Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)& -16)},Pa=N.prototype={ready:function(a){function b(){d||(d=!0,a())}var d=!1;"complete"===X.readyState?setTimeout(b):(this.on("DOMContentLoaded",b),N(S).on("load",b))},toString:function(){var a=[];n(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<=a?B(this[a]):B(this[this.length+a])},length:0,push:mg,sort:[].sort,splice:[].splice},Cb={};n("multiple selected checked disabled readOnly required open".split(" "),function(a){Cb[F(a)]=a});var Rc={};n("input select option textarea button form details".split(" "), -function(a){Rc[a]=!0});var Zc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};n({data:Wb,removeData:vb,hasData:function(a){for(var b in gb[a.ng339])return!0;return!1}},function(a,b){N[b]=a});n({data:Wb,inheritedData:Bb,scope:function(a){return B.data(a,"$scope")||Bb(a.parentNode||a,["$isolateScope","$scope"])},isolateScope:function(a){return B.data(a,"$isolateScope")||B.data(a,"$isolateScopeNoTemplate")},controller:Oc,injector:function(a){return Bb(a, -"$injector")},removeAttr:function(a,b){a.removeAttribute(b)},hasClass:yb,css:function(a,b,d){b=fb(b);if(y(d))a.style[b]=d;else return a.style[b]},attr:function(a,b,d){var c=a.nodeType;if(c!==Na&&2!==c&&8!==c)if(c=F(b),Cb[c])if(y(d))d?(a[b]=!0,a.setAttribute(b,c)):(a[b]=!1,a.removeAttribute(c));else return a[b]||(a.attributes.getNamedItem(b)||x).specified?c:u;else if(y(d))a.setAttribute(b,d);else if(a.getAttribute)return a=a.getAttribute(b,2),null===a?u:a},prop:function(a,b,d){if(y(d))a[b]=d;else return a[b]}, -text:function(){function a(a,d){if(q(d)){var c=a.nodeType;return 1===c||c===Na?a.textContent:""}a.textContent=d}a.$dv="";return a}(),val:function(a,b){if(q(b)){if(a.multiple&&"select"===ta(a)){var d=[];n(a.options,function(a){a.selected&&d.push(a.value||a.text)});return 0===d.length?null:d}return a.value}a.value=b},html:function(a,b){if(q(b))return a.innerHTML;ub(a,!0);a.innerHTML=b},empty:Pc},function(a,b){N.prototype[b]=function(b,c){var e,f,g=this.length;if(a!==Pc&&q(2==a.length&&a!==yb&&a!==Oc? -b:c)){if(H(b)){for(e=0;e <= >= && || ! = |".split(" "),function(a){Lb[a]=!0});var sg={n:"\n",f:"\f",r:"\r", -t:"\t",v:"\v","'":"'",'"':'"'},fc=function(a){this.options=a};fc.prototype={constructor:fc,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a|| -"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,b,d){d=d||this.index;b=y(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw ba("lexerr",a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index","<=",">=");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),b;b=this.expect("+","-");)a={type:s.BinaryExpression,operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:s.BinaryExpression,operator:b.text, -left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:s.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.constants.hasOwnProperty(this.peek().text)?a=bb(this.constants[this.consume().text]):this.peek().identifier?a=this.identifier():this.peek().constant?a=this.constant(): -this.throwError("not a primary expression",this.peek());for(var b;b=this.expect("(","[",".");)"("===b.text?(a={type:s.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===b.text?(a={type:s.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:s.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var b={type:s.CallExpression,callee:this.identifier(), -arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return b},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.expression());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:s.Identifier,name:a.text}},constant:function(){return{type:s.Literal,value:this.consume().value}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break; -a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:s.ArrayExpression,elements:a}},object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;b={type:s.Property,kind:"init"};this.peek().constant?b.key=this.constant():this.peek().identifier?b.key=this.identifier():this.throwError("invalid key",this.peek());this.consume(":");b.value=this.expression();a.push(b)}while(this.expect(","))}this.consume("}");return{type:s.ObjectExpression,properties:a}}, -throwError:function(a,b){throw ba("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0===this.tokens.length)throw ba("ueoe",this.text);var b=this.expect(a);b||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return b},peekToken:function(){if(0===this.tokens.length)throw ba("ueoe",this.text);return this.tokens[0]},peek:function(a,b,d,c){return this.peekAhead(0,a,b,d,c)},peekAhead:function(a,b,d,c,e){if(this.tokens.length>a){a=this.tokens[a]; -var f=a.text;if(f===b||f===d||f===c||f===e||!(b||d||c||e))return a}return!1},expect:function(a,b,d,c){return(a=this.peek(a,b,d,c))?(this.tokens.shift(),a):!1},constants:{"true":{type:s.Literal,value:!0},"false":{type:s.Literal,value:!1},"null":{type:s.Literal,value:null},undefined:{type:s.Literal,value:u},"this":{type:s.ThisExpression}}};rd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.state={nextId:0,filters:{},expensiveChecks:b,fn:{vars:[],body:[],own:{}},assign:{vars:[], -body:[],own:{}},inputs:[]};W(c,d.$filter);var e="",f;this.stage="assign";if(f=pd(c))this.state.computing="assign",e=this.nextId(),this.recurse(f,e),this.return_(e),e="fn.assign="+this.generateFunction("assign","s,v,l");f=nd(c.body);d.stage="inputs";n(f,function(a,b){var c="fn"+b;d.state[c]={vars:[],body:[],own:{}};d.state.computing=c;var e=d.nextId();d.recurse(a,e);d.return_(e);d.state.inputs.push(c);a.watchId=b});this.state.computing="fn";this.stage="main";this.recurse(c);e='"'+this.USE+" "+this.STRICT+ -'";\n'+this.filterPrefix()+"var fn="+this.generateFunction("fn","s,l,a,i")+e+this.watchFns()+"return fn;";e=(new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","getStringValue","ensureSafeAssignContext","ifDefined","plus","text",e))(this.$filter,Va,xa,kd,jd,ld,Zf,md,a);this.state=this.stage=u;e.literal=qd(c);e.constant=c.constant;return e},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;n(b,function(b){a.push("var "+b+"="+d.generateFunction(b, -"s"))});b.length&&a.push("fn.inputs=["+b.join(",")+"];");return a.join("")},generateFunction:function(a,b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;n(this.state.filters,function(d,c){a.push(d+"=$filter("+b.escape(c)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,b, -d,c,e,f){var g,h,k=this,l,m;c=c||x;if(!f&&y(a.watchId))b=b||this.nextId(),this.if_("i",this.lazyAssign(b,this.computedMember("i",a.watchId)),this.lazyRecurse(a,b,d,c,e,!0));else switch(a.type){case s.Program:n(a.body,function(b,c){k.recurse(b.expression,u,u,function(a){h=a});c!==a.body.length-1?k.current().body.push(h,";"):k.return_(h)});break;case s.Literal:m=this.escape(a.value);this.assign(b,m);c(m);break;case s.UnaryExpression:this.recurse(a.argument,u,u,function(a){h=a});m=a.operator+"("+this.ifDefined(h, -0)+")";this.assign(b,m);c(m);break;case s.BinaryExpression:this.recurse(a.left,u,u,function(a){g=a});this.recurse(a.right,u,u,function(a){h=a});m="+"===a.operator?this.plus(g,h):"-"===a.operator?this.ifDefined(g,0)+a.operator+this.ifDefined(h,0):"("+g+")"+a.operator+"("+h+")";this.assign(b,m);c(m);break;case s.LogicalExpression:b=b||this.nextId();k.recurse(a.left,b);k.if_("&&"===a.operator?b:k.not(b),k.lazyRecurse(a.right,b));c(b);break;case s.ConditionalExpression:b=b||this.nextId();k.recurse(a.test, -b);k.if_(b,k.lazyRecurse(a.alternate,b),k.lazyRecurse(a.consequent,b));c(b);break;case s.Identifier:b=b||this.nextId();d&&(d.context="inputs"===k.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);Va(a.name);k.if_("inputs"===k.stage||k.not(k.getHasOwnProperty("l",a.name)),function(){k.if_("inputs"===k.stage||"s",function(){e&&1!==e&&k.if_(k.not(k.nonComputedMember("s",a.name)),k.lazyAssign(k.nonComputedMember("s",a.name),"{}"));k.assign(b,k.nonComputedMember("s", -a.name))})},b&&k.lazyAssign(b,k.nonComputedMember("l",a.name)));(k.state.expensiveChecks||Fb(a.name))&&k.addEnsureSafeObject(b);c(b);break;case s.MemberExpression:g=d&&(d.context=this.nextId())||this.nextId();b=b||this.nextId();k.recurse(a.object,g,u,function(){k.if_(k.notNull(g),function(){if(a.computed)h=k.nextId(),k.recurse(a.property,h),k.getStringValue(h),k.addEnsureSafeMemberName(h),e&&1!==e&&k.if_(k.not(k.computedMember(g,h)),k.lazyAssign(k.computedMember(g,h),"{}")),m=k.ensureSafeObject(k.computedMember(g, -h)),k.assign(b,m),d&&(d.computed=!0,d.name=h);else{Va(a.property.name);e&&1!==e&&k.if_(k.not(k.nonComputedMember(g,a.property.name)),k.lazyAssign(k.nonComputedMember(g,a.property.name),"{}"));m=k.nonComputedMember(g,a.property.name);if(k.state.expensiveChecks||Fb(a.property.name))m=k.ensureSafeObject(m);k.assign(b,m);d&&(d.computed=!1,d.name=a.property.name)}},function(){k.assign(b,"undefined")});c(b)},!!e);break;case s.CallExpression:b=b||this.nextId();a.filter?(h=k.filter(a.callee.name),l=[],n(a.arguments, -function(a){var b=k.nextId();k.recurse(a,b);l.push(b)}),m=h+"("+l.join(",")+")",k.assign(b,m),c(b)):(h=k.nextId(),g={},l=[],k.recurse(a.callee,h,g,function(){k.if_(k.notNull(h),function(){k.addEnsureSafeFunction(h);n(a.arguments,function(a){k.recurse(a,k.nextId(),u,function(a){l.push(k.ensureSafeObject(a))})});g.name?(k.state.expensiveChecks||k.addEnsureSafeObject(g.context),m=k.member(g.context,g.name,g.computed)+"("+l.join(",")+")"):m=h+"("+l.join(",")+")";m=k.ensureSafeObject(m);k.assign(b,m)}, -function(){k.assign(b,"undefined")});c(b)}));break;case s.AssignmentExpression:h=this.nextId();g={};if(!od(a.left))throw ba("lval");this.recurse(a.left,u,g,function(){k.if_(k.notNull(g.context),function(){k.recurse(a.right,h);k.addEnsureSafeObject(k.member(g.context,g.name,g.computed));k.addEnsureSafeAssignContext(g.context);m=k.member(g.context,g.name,g.computed)+a.operator+h;k.assign(b,m);c(b||m)})},1);break;case s.ArrayExpression:l=[];n(a.elements,function(a){k.recurse(a,k.nextId(),u,function(a){l.push(a)})}); -m="["+l.join(",")+"]";this.assign(b,m);c(m);break;case s.ObjectExpression:l=[];n(a.properties,function(a){k.recurse(a.value,k.nextId(),u,function(b){l.push(k.escape(a.key.type===s.Identifier?a.key.name:""+a.key.value)+":"+b)})});m="{"+l.join(",")+"}";this.assign(b,m);c(m);break;case s.ThisExpression:this.assign(b,"s");c("s");break;case s.NGValueParameter:this.assign(b,"v"),c("v")}},getHasOwnProperty:function(a,b){var d=a+"."+b,c=this.current().own;c.hasOwnProperty(d)||(c[d]=this.nextId(!1,a+"&&("+ -this.escape(b)+" in "+a+")"));return c[d]},assign:function(a,b){if(a)return this.current().body.push(a,"=",b,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,b){return"ifDefined("+a+","+this.escape(b)+")"},plus:function(a,b){return"plus("+a+","+b+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,b,d){if(!0===a)b();else{var c=this.current().body;c.push("if(",a, -"){");b();c.push("}");d&&(c.push("else{"),d(),c.push("}"))}},not:function(a){return"!("+a+")"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,b){return a+"."+b},computedMember:function(a,b){return a+"["+b+"]"},member:function(a,b,d){return d?this.computedMember(a,b):this.nonComputedMember(a,b)},addEnsureSafeObject:function(a){this.current().body.push(this.ensureSafeObject(a),";")},addEnsureSafeMemberName:function(a){this.current().body.push(this.ensureSafeMemberName(a),";")}, -addEnsureSafeFunction:function(a){this.current().body.push(this.ensureSafeFunction(a),";")},addEnsureSafeAssignContext:function(a){this.current().body.push(this.ensureSafeAssignContext(a),";")},ensureSafeObject:function(a){return"ensureSafeObject("+a+",text)"},ensureSafeMemberName:function(a){return"ensureSafeMemberName("+a+",text)"},ensureSafeFunction:function(a){return"ensureSafeFunction("+a+",text)"},getStringValue:function(a){this.assign(a,"getStringValue("+a+",text)")},ensureSafeAssignContext:function(a){return"ensureSafeAssignContext("+ -a+",text)"},lazyRecurse:function(a,b,d,c,e,f){var g=this;return function(){g.recurse(a,b,d,c,e,f)}},lazyAssign:function(a,b){var d=this;return function(){d.assign(a,b)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(E(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(Q(a))return a.toString();if(!0===a)return"true";if(!1===a)return"false";if(null===a)return"null";if("undefined"=== -typeof a)return"undefined";throw ba("esc");},nextId:function(a,b){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(b?"="+b:""));return d},current:function(){return this.state[this.state.computing]}};sd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.expression=a;this.expensiveChecks=b;W(c,d.$filter);var e,f;if(e=pd(c))f=this.recurse(e);e=nd(c.body);var g;e&&(g=[],n(e,function(a,b){var c=d.recurse(a);a.input=c;g.push(c);a.watchId=b}));var h=[];n(c.body,function(a){h.push(d.recurse(a.expression))}); -e=0===c.body.length?function(){}:1===c.body.length?h[0]:function(a,b){var c;n(h,function(d){c=d(a,b)});return c};f&&(e.assign=function(a,b,c){return f(a,c,b)});g&&(e.inputs=g);e.literal=qd(c);e.constant=c.constant;return e},recurse:function(a,b,d){var c,e,f=this,g;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case s.Literal:return this.value(a.value,b);case s.UnaryExpression:return e=this.recurse(a.argument),this["unary"+a.operator](e,b);case s.BinaryExpression:return c=this.recurse(a.left), -e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case s.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case s.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case s.Identifier:return Va(a.name,f.expression),f.identifier(a.name,f.expensiveChecks||Fb(a.name),b,d,f.expression);case s.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed||(Va(a.property.name, -f.expression),e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d,f.expression):this.nonComputedMember(c,e,f.expensiveChecks,b,d,f.expression);case s.CallExpression:return g=[],n(a.arguments,function(a){g.push(f.recurse(a))}),a.filter&&(e=this.$filter(a.callee.name)),a.filter||(e=this.recurse(a.callee,!0)),a.filter?function(a,c,d,f){for(var r=[],n=0;n":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>b(c,e,f,g);return d?{value:c}:c}},"binary<=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)<=b(c,e,f,g);return d?{value:c}:c}},"binary>=":function(a,b,d){return function(c, -e,f,g){c=a(c,e,f,g)>=b(c,e,f,g);return d?{value:c}:c}},"binary&&":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)&&b(c,e,f,g);return d?{value:c}:c}},"binary||":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)||b(c,e,f,g);return d?{value:c}:c}},"ternary?:":function(a,b,d,c){return function(e,f,g,h){e=a(e,f,g,h)?b(e,f,g,h):d(e,f,g,h);return c?{value:e}:e}},value:function(a,b){return function(){return b?{context:u,name:u,value:a}:a}},identifier:function(a,b,d,c,e){return function(f,g,h,k){f= -g&&a in g?g:f;c&&1!==c&&f&&!f[a]&&(f[a]={});g=f?f[a]:u;b&&xa(g,e);return d?{context:f,name:a,value:g}:g}},computedMember:function(a,b,d,c,e){return function(f,g,h,k){var l=a(f,g,h,k),m,n;null!=l&&(m=b(f,g,h,k),m=jd(m),Va(m,e),c&&1!==c&&l&&!l[m]&&(l[m]={}),n=l[m],xa(n,e));return d?{context:l,name:m,value:n}:n}},nonComputedMember:function(a,b,d,c,e,f){return function(g,h,k,l){g=a(g,h,k,l);e&&1!==e&&g&&!g[b]&&(g[b]={});h=null!=g?g[b]:u;(d||Fb(b))&&xa(h,f);return c?{context:g,name:b,value:h}:h}},inputs:function(a, -b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};var gc=function(a,b,d){this.lexer=a;this.$filter=b;this.options=d;this.ast=new s(this.lexer);this.astCompiler=d.csp?new sd(this.ast,b):new rd(this.ast,b)};gc.prototype={constructor:gc,parse:function(a){return this.astCompiler.compile(a,this.options.expensiveChecks)}};$();$();var $f=Object.prototype.valueOf,ya=G("$sce"),la={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},ha=G("$compile"),Y=X.createElement("a"),wd=wa(S.location.href); -xd.$inject=["$document"];Jc.$inject=["$provide"];yd.$inject=["$locale"];Ad.$inject=["$locale"];var ic=".",jg={yyyy:ca("FullYear",4),yy:ca("FullYear",2,0,!0),y:ca("FullYear",1),MMMM:Hb("Month"),MMM:Hb("Month",!0),MM:ca("Month",2,1),M:ca("Month",1,1),dd:ca("Date",2),d:ca("Date",1),HH:ca("Hours",2),H:ca("Hours",1),hh:ca("Hours",2,-12),h:ca("Hours",1,-12),mm:ca("Minutes",2),m:ca("Minutes",1),ss:ca("Seconds",2),s:ca("Seconds",1),sss:ca("Milliseconds",3),EEEE:Hb("Day"),EEE:Hb("Day",!0),a:function(a,b){return 12> -a.getHours()?b.AMPMS[0]:b.AMPMS[1]},Z:function(a,b,d){a=-1*d;return a=(0<=a?"+":"")+(Gb(Math[0=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}},ig=/((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,hg=/^\-?\d+$/;zd.$inject=["$locale"];var eg=na(F),fg=na(sb);Bd.$inject=["$parse"];var he=na({restrict:"E",compile:function(a,b){if(!b.href&&!b.xlinkHref)return function(a, -b){if("a"===b[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===sa.call(b.prop("href"))?"xlink:href":"href";b.on("click",function(a){b.attr(e)||a.preventDefault()})}}}}),tb={};n(Cb,function(a,b){function d(a,d,e){a.$watch(e[c],function(a){e.$set(b,!!a)})}if("multiple"!=a){var c=va("ng-"+b),e=d;"checked"===a&&(e=function(a,b,e){e.ngModel!==e[c]&&d(a,b,e)});tb[c]=function(){return{restrict:"A",priority:100,link:e}}}});n(Zc,function(a,b){tb[b]=function(){return{priority:100,link:function(a, -c,e){if("ngPattern"===b&&"/"==e.ngPattern.charAt(0)&&(c=e.ngPattern.match(lg))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});n(["src","srcset","href"],function(a){var b=va("ng-"+a);tb[b]=function(){return{priority:99,link:function(d,c,e){var f=a,g=a;"href"===a&&"[object SVGAnimatedString]"===sa.call(c.prop("href"))&&(g="xlinkHref",e.$attr[g]="xlink:href",f=null);e.$observe(b,function(b){b?(e.$set(g,b),Ha&&f&&c.prop(f,e[g])):"href"===a&&e.$set(g,null)})}}}}); -var Ib={$addControl:x,$$renameControl:function(a,b){a.$name=b},$removeControl:x,$setValidity:x,$setDirty:x,$setPristine:x,$setSubmitted:x};Fd.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var Nd=function(a){return["$timeout","$parse",function(b,d){function c(a){return""===a?d('this[""]').assign:d(a).assign||x}return{name:"form",restrict:a?"EAC":"E",require:["form","^^?form"],controller:Fd,compile:function(d,f){d.addClass(Wa).addClass(mb);var g=f.name?"name":a&&f.ngForm?"ngForm": -!1;return{pre:function(a,d,e,f){var n=f[0];if(!("action"in e)){var q=function(b){a.$apply(function(){n.$commitViewValue();n.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",q,!1);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",q,!1)},0,!1)})}(f[1]||n.$$parentForm).$addControl(n);var s=g?c(n.$name):x;g&&(s(a,n),e.$observe(g,function(b){n.$name!==b&&(s(a,u),n.$$parentForm.$$renameControl(n,b),s=c(n.$name),s(a,n))}));d.on("$destroy",function(){n.$$parentForm.$removeControl(n); -s(a,u);M(n,Ib)})}}}}}]},ie=Nd(),ve=Nd(!0),kg=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,tg=/^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/,ug=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,vg=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,Od=/^(\d{4})-(\d{2})-(\d{2})$/,Pd=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,mc=/^(\d{4})-W(\d\d)$/,Qd=/^(\d{4})-(\d\d)$/, -Rd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Sd={text:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);kc(c)},date:kb("date",Od,Kb(Od,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":kb("datetimelocal",Pd,Kb(Pd,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:kb("time",Rd,Kb(Rd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:kb("week",mc,function(a,b){if(da(a))return a;if(E(a)){mc.lastIndex=0;var d=mc.exec(a);if(d){var c=+d[1],e=+d[2],f=d=0,g=0,h=0,k=Dd(c),e=7*(e-1);b&&(d=b.getHours(),f= -b.getMinutes(),g=b.getSeconds(),h=b.getMilliseconds());return new Date(c,0,k.getDate()+e,d,f,g,h)}}return NaN},"yyyy-Www"),month:kb("month",Qd,Kb(Qd,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f){Hd(a,b,d,c);jb(a,b,d,c,e,f);c.$$parserName="number";c.$parsers.push(function(a){return c.$isEmpty(a)?null:vg.test(a)?parseFloat(a):u});c.$formatters.push(function(a){if(!c.$isEmpty(a)){if(!Q(a))throw lb("numfmt",a);a=a.toString()}return a});if(y(d.min)||d.ngMin){var g;c.$validators.min=function(a){return c.$isEmpty(a)|| -q(g)||a>=g};d.$observe("min",function(a){y(a)&&!Q(a)&&(a=parseFloat(a,10));g=Q(a)&&!isNaN(a)?a:u;c.$validate()})}if(y(d.max)||d.ngMax){var h;c.$validators.max=function(a){return c.$isEmpty(a)||q(h)||a<=h};d.$observe("max",function(a){y(a)&&!Q(a)&&(a=parseFloat(a,10));h=Q(a)&&!isNaN(a)?a:u;c.$validate()})}},url:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);kc(c);c.$$parserName="url";c.$validators.url=function(a,b){var d=a||b;return c.$isEmpty(d)||tg.test(d)}},email:function(a,b,d,c,e,f){jb(a,b,d,c,e,f);kc(c); -c.$$parserName="email";c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)||ug.test(d)}},radio:function(a,b,d,c){q(d.name)&&b.attr("name",++nb);b.on("click",function(a){b[0].checked&&c.$setViewValue(d.value,a&&a.type)});c.$render=function(){b[0].checked=d.value==c.$viewValue};d.$observe("value",c.$render)},checkbox:function(a,b,d,c,e,f,g,h){var k=Id(h,a,"ngTrueValue",d.ngTrueValue,!0),l=Id(h,a,"ngFalseValue",d.ngFalseValue,!1);b.on("click",function(a){c.$setViewValue(b[0].checked,a&& -a.type)});c.$render=function(){b[0].checked=c.$viewValue};c.$isEmpty=function(a){return!1===a};c.$formatters.push(function(a){return ma(a,k)});c.$parsers.push(function(a){return a?k:l})},hidden:x,button:x,submit:x,reset:x,file:x},Dc=["$browser","$sniffer","$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e,f,g,h){h[0]&&(Sd[F(g.type)]||Sd.text)(e,f,g,h[0],b,a,d,c)}}}}],wg=/^(true|false|\d+)$/,Ne=function(){return{restrict:"A",priority:100,compile:function(a, -b){return wg.test(b.ngValue)?function(a,b,e){e.$set("value",a.$eval(e.ngValue))}:function(a,b,e){a.$watch(e.ngValue,function(a){e.$set("value",a)})}}}},ne=["$compile",function(a){return{restrict:"AC",compile:function(b){a.$$addBindingClass(b);return function(b,c,e){a.$$addBindingInfo(c,e.ngBind);c=c[0];b.$watch(e.ngBind,function(a){c.textContent=q(a)?"":a})}}}}],pe=["$interpolate","$compile",function(a,b){return{compile:function(d){b.$$addBindingClass(d);return function(c,d,f){c=a(d.attr(f.$attr.ngBindTemplate)); -b.$$addBindingInfo(d,c.expressions);d=d[0];f.$observe("ngBindTemplate",function(a){d.textContent=q(a)?"":a})}}}}],oe=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g=b(e.ngBindHtml,function(a){return(a||"").toString()});d.$$addBindingClass(c);return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){c.html(a.getTrustedHtml(f(b))||"")})}}}}],Me=na({restrict:"A",require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}), -qe=lc("",!0),se=lc("Odd",0),re=lc("Even",1),te=La({compile:function(a,b){b.$set("ngCloak",u);a.removeClass("ng-cloak")}}),ue=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Ic={},xg={blur:!0,focus:!0};n("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var b=va("ng-"+a);Ic[b]=["$parse","$rootScope",function(d,c){return{restrict:"A",compile:function(e,f){var g= -d(f[b],null,!0);return function(b,d){d.on(a,function(d){var e=function(){g(b,{$event:d})};xg[a]&&c.$$phase?b.$evalAsync(e):b.$apply(e)})}}}}]});var xe=["$animate",function(a){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(b,d,c,e,f){var g,h,k;b.$watch(c.ngIf,function(b){b?h||f(function(b,e){h=e;b[b.length++]=X.createComment(" end ngIf: "+c.ngIf+" ");g={clone:b};a.enter(b,d.parent(),d)}):(k&&(k.remove(),k=null),h&&(h.$destroy(),h=null),g&&(k= -rb(g.clone),a.leave(k).then(function(){k=null}),g=null))})}}}],ye=["$templateRequest","$anchorScroll","$animate",function(a,b,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:fa.noop,compile:function(c,e){var f=e.ngInclude||e.src,g=e.onload||"",h=e.autoscroll;return function(c,e,m,n,q){var s=0,v,u,p,C=function(){u&&(u.remove(),u=null);v&&(v.$destroy(),v=null);p&&(d.leave(p).then(function(){u=null}),u=p,p=null)};c.$watch(f,function(f){var m=function(){!y(h)||h&&!c.$eval(h)|| -b()},u=++s;f?(a(f,!0).then(function(a){if(u===s){var b=c.$new();n.template=a;a=q(b,function(a){C();d.enter(a,null,e).then(m)});v=b;p=a;v.$emit("$includeContentLoaded",f);c.$eval(g)}},function(){u===s&&(C(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(C(),n.template=null)})}}}}],Pe=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(b,d,c,e){/SVG/.test(d[0].toString())?(d.empty(),a(Lc(e.template,X).childNodes)(b,function(a){d.append(a)}, -{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],ze=La({priority:450,compile:function(){return{pre:function(a,b,d){a.$eval(d.ngInit)}}}}),Le=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,b,d,c){var e=b.attr(d.$attr.ngList)||", ",f="false"!==d.ngTrim,g=f?U(e):e;c.$parsers.push(function(a){if(!q(a)){var b=[];a&&n(a.split(g),function(a){a&&b.push(f?U(a):a)});return b}});c.$formatters.push(function(a){return I(a)?a.join(e):u});c.$isEmpty=function(a){return!a|| -!a.length}}}},mb="ng-valid",Jd="ng-invalid",Wa="ng-pristine",Jb="ng-dirty",Ld="ng-pending",lb=G("ngModel"),yg=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,b,d,c,e,f,g,h,k,l){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=u;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1; -this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=u;this.$name=l(d.name||"",!1)(a);this.$$parentForm=Ib;var m=e(d.ngModel),r=m.assign,t=m,s=r,v=null,B,p=this;this.$$setOptions=function(a){if((p.$options=a)&&a.getterSetter){var b=e(d.ngModel+"()"),f=e(d.ngModel+"($$$p)");t=function(a){var c=m(a);z(c)&&(c=b(a));return c};s=function(a,b){z(m(a))?f(a,{$$$p:p.$modelValue}):r(a,p.$modelValue)}}else if(!m.assign)throw lb("nonassign",d.ngModel,ua(c));};this.$render=x;this.$isEmpty= -function(a){return q(a)||""===a||null===a||a!==a};var C=0;Gd({ctrl:this,$element:c,set:function(a,b){a[b]=!0},unset:function(a,b){delete a[b]},$animate:f});this.$setPristine=function(){p.$dirty=!1;p.$pristine=!0;f.removeClass(c,Jb);f.addClass(c,Wa)};this.$setDirty=function(){p.$dirty=!0;p.$pristine=!1;f.removeClass(c,Wa);f.addClass(c,Jb);p.$$parentForm.$setDirty()};this.$setUntouched=function(){p.$touched=!1;p.$untouched=!0;f.setClass(c,"ng-untouched","ng-touched")};this.$setTouched=function(){p.$touched= -!0;p.$untouched=!1;f.setClass(c,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){g.cancel(v);p.$viewValue=p.$$lastCommittedViewValue;p.$render()};this.$validate=function(){if(!Q(p.$modelValue)||!isNaN(p.$modelValue)){var a=p.$$rawModelValue,b=p.$valid,c=p.$modelValue,d=p.$options&&p.$options.allowInvalid;p.$$runValidators(a,p.$$lastCommittedViewValue,function(e){d||b===e||(p.$modelValue=e?a:u,p.$modelValue!==c&&p.$$writeModelToScope())})}};this.$$runValidators=function(a,b,c){function d(){var c= -!0;n(p.$validators,function(d,e){var g=d(a,b);c=c&&g;f(e,g)});return c?!0:(n(p.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;n(p.$asyncValidators,function(e,g){var h=e(a,b);if(!h||!z(h.then))throw lb("$asyncValidators",h);f(g,u);c.push(h.then(function(){f(g,!0)},function(a){d=!1;f(g,!1)}))});c.length?k.all(c).then(function(){g(d)},x):g(!0)}function f(a,b){h===C&&p.$setValidity(a,b)}function g(a){h===C&&c(a)}C++;var h=C;(function(){var a=p.$$parserName||"parse";if(q(B))f(a, -null);else return B||(n(p.$validators,function(a,b){f(b,null)}),n(p.$asyncValidators,function(a,b){f(b,null)})),f(a,B),B;return!0})()?d()?e():g(!1):g(!1)};this.$commitViewValue=function(){var a=p.$viewValue;g.cancel(v);if(p.$$lastCommittedViewValue!==a||""===a&&p.$$hasNativeValidators)p.$$lastCommittedViewValue=a,p.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var b=p.$$lastCommittedViewValue;if(B=q(b)?u:!0)for(var c=0;ce||c.$isEmpty(b)||b.length<=e}}}}},Gc=function(){return{restrict:"A",require:"?ngModel",link:function(a,b,d,c){if(c){var e=0;d.$observe("minlength",function(a){e=ea(a)||0;c.$validate()});c.$validators.minlength=function(a,b){return c.$isEmpty(b)||b.length>=e}}}}};S.angular.bootstrap? -console.log("WARNING: Tried to load angular more than once."):(ce(),ee(fa),fa.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "), -SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4", -negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",pluralCat:function(a,c){var e=a|0,f=c;u===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),B(X).ready(function(){Zd(X,yc)}))})(window,document);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(''); -//# sourceMappingURL=angular.min.js.map diff --git a/admin/static/js/angular.min.js b/admin/static/js/angular.min.js new file mode 120000 index 00000000..86b88964 --- /dev/null +++ b/admin/static/js/angular.min.js @@ -0,0 +1 @@ +../../../frontend/static/js/angular.min.js \ No newline at end of file diff --git a/admin/static/js/bootstrap.min.js b/admin/static/js/bootstrap.min.js deleted file mode 100644 index e79c0651..00000000 --- a/admin/static/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under the MIT license - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/admin/static/js/bootstrap.min.js b/admin/static/js/bootstrap.min.js new file mode 120000 index 00000000..d074c9db --- /dev/null +++ b/admin/static/js/bootstrap.min.js @@ -0,0 +1 @@ +../../../frontend/static/js/bootstrap.min.js \ No newline at end of file diff --git a/admin/static/js/jquery.min.js b/admin/static/js/jquery.min.js deleted file mode 100644 index 6c60672f..00000000 --- a/admin/static/js/jquery.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery v1.12.0 | (c) jQuery Foundation | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; -return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML="
    a",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:l.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n(" +
    + +
    From 8c2e8a19d1e43e5ff93eaa427d0803d37dd6d45a Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 5 Jan 2017 02:18:31 +0100 Subject: [PATCH 0447/2585] front: use ng-pluralize --- frontend/static/index.html | 6 +++--- frontend/static/views/theme.html | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/static/index.html b/frontend/static/index.html index 01de3f90..84c638b4 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -83,8 +83,8 @@
    - {{ teams[my.team_id].rank }}e sur {{ teams_count }} – - {{ my.score }} points + {{ teams[my.team_id].rank }} sur {{ teams_count }} – +
    @@ -97,7 +97,7 @@
    diff --git a/frontend/static/views/theme.html b/frontend/static/views/theme.html index ebaf8c8c..792cf571 100644 --- a/frontend/static/views/theme.html +++ b/frontend/static/views/theme.html @@ -8,8 +8,8 @@

      -
    • Gain : {{ themes[current_theme].exercices[current_exercice].gain }} points +50% happy hour +50% first blood
    • -
    • Résolu par : {{ themes[current_theme].exercices[current_exercice].solved }} équipes
    • +
    • Gain : +50% happy hour +50% first blood
    • +
    • Résolu par : .
    @@ -37,7 +37,7 @@

    {{ hint.title }}

    -

    Cet indice vous coûtera {{ hint.cost }}% des points de l'exercice

    +

    Débloquer cet indice vous coûtera .

    @@ -47,7 +47,7 @@
    Soumettre une solution
      -
    • {{ my.exercices[current_exercice].solved_number }} tentative(s) effectuée(s). Dernière solution envoyée à {{ my.exercices[current_exercice].solved_time | date:"mediumTime" }}.
    • +
    • . Dernière solution envoyée à {{ my.exercices[current_exercice].solved_time | date:"mediumTime" }}.
    • Votre solution a bien été envoyée !{{ sberr }} {{ message }}
    @@ -69,7 +69,7 @@
    Challenge réussi !
    - Vous êtes la {{ my.exercices[current_exercice].solved_number }}e équipe à avoir résolu ce challenge à {{ my.exercices[current_exercice].solved_time | date:"mediumTime" }}. Vous avez marqué {{ themes[current_theme].exercices[current_exercice].gain }} points ! + Vous êtes la {{ my.exercices[current_exercice].solved_number }} équipe à avoir résolu ce challenge à {{ my.exercices[current_exercice].solved_time | date:"mediumTime" }}. Vous avez marqué !
    From b772a227057508723fcc50983f0b6ca14d1592c5 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 5 Jan 2017 02:21:32 +0100 Subject: [PATCH 0448/2585] Hints can something else than text --- admin/api/exercice.go | 30 +++++++++++++++++++++++---- admin/api/file.go | 12 +++-------- admin/fill_exercices.sh | 35 ++++++++++++++++++++++++-------- frontend/static/views/theme.html | 4 +++- libfic/file.go | 3 +-- libfic/hint.go | 10 +++++++++ 6 files changed, 69 insertions(+), 25 deletions(-) diff --git a/admin/api/exercice.go b/admin/api/exercice.go index e00772e7..309a0d71 100644 --- a/admin/api/exercice.go +++ b/admin/api/exercice.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "errors" + "strings" "srs.epita.fr/fic-server/libfic" @@ -119,17 +120,29 @@ func createExerciceKey(exercice fic.Exercice, body []byte) (interface{}, error) return exercice.AddRawKey(uk.Type, uk.Key) } +type uploadedHint struct { + Title string + Content string + Cost int64 + Path string +} + func createExerciceHint(exercice fic.Exercice, body []byte) (interface{}, error) { - var uh fic.EHint + var uh uploadedHint if err := json.Unmarshal(body, &uh); err != nil { return nil, err } - if len(uh.Content) == 0 { + if len(uh.Content) != 0 { + return exercice.AddHint(uh.Title, uh.Content, uh.Cost) + } else if len(uh.Path) != 0 { + return importFile(uploadedFile{Path: uh.Path}, + func(filePath string, origin string, digest []byte) (interface{}, error) { + return exercice.AddHint(uh.Title, "$FILES" + strings.TrimPrefix(filePath, fic.FilesDir), uh.Cost) + }) + } else { return nil, errors.New("Hint's content not filled") } - - return exercice.AddHint(uh.Title, uh.Content, uh.Cost) } func showExerciceHint(hint fic.EHint, body []byte) (interface{}, error) { @@ -189,6 +202,15 @@ func deleteExerciceKey(key fic.Key, _ fic.Exercice, _ []byte) (interface{}, erro } +func createExerciceFile(exercice fic.Exercice, body []byte) (interface{}, error) { + var uf uploadedFile + if err := json.Unmarshal(body, &uf); err != nil { + return nil, err + } + + return importFile(uf, exercice.ImportFile) +} + func showExerciceFile(file fic.EFile, body []byte) (interface{}, error) { return file, nil } diff --git a/admin/api/file.go b/admin/api/file.go index e8667107..66d8dc46 100644 --- a/admin/api/file.go +++ b/admin/api/file.go @@ -5,7 +5,6 @@ import ( "crypto/sha512" "encoding/base32" "encoding/hex" - "encoding/json" "errors" "fmt" "log" @@ -29,12 +28,7 @@ type uploadedFile struct { Parts []string } -func createExerciceFile(exercice fic.Exercice, body []byte) (interface{}, error) { - var uf uploadedFile - if err := json.Unmarshal(body, &uf); err != nil { - return nil, err - } - +func importFile(uf uploadedFile, next func(string, string, []byte) (interface{}, error)) (interface{}, error) { var hash [sha512.Size]byte var logStr string var fromURI string @@ -80,7 +74,7 @@ func createExerciceFile(exercice fic.Exercice, body []byte) (interface{}, error) pathname := path.Join(fic.FilesDir, strings.ToLower(base32.StdEncoding.EncodeToString(hash[:])), path.Base(fromURI)) // Remove the file if it exists - if _, err := os.Stat(pathname); os.IsExist(err) && !RapidImport { + if _, err := os.Stat(pathname); !os.IsNotExist(err) && !RapidImport { if err := os.Remove(pathname); err != nil { return nil, err } @@ -98,7 +92,7 @@ func createExerciceFile(exercice fic.Exercice, body []byte) (interface{}, error) if digest, err := hex.DecodeString(uf.Digest); err != nil { return nil, err } else { - return exercice.ImportFile(pathname, fromURI, digest) + return next(pathname, fromURI, digest) } } diff --git a/admin/fill_exercices.sh b/admin/fill_exercices.sh index 149fad64..b57756b6 100755 --- a/admin/fill_exercices.sh +++ b/admin/fill_exercices.sh @@ -59,8 +59,12 @@ new_hint() { TITLE=`echo "$3" | sed 's/"/\\\\"/g'` CONTENT=`echo "$4" | sed 's/"/\\\\"/g' | sed ':a;N;$!ba;s/\n/
    /g'` COST="$5" + URI="$6" - curl -f -s -d "{\"title\": \"$TITLE\", \"content\": \"$CONTENT\", \"cost\": $COST}" "${BASEURL}/api/themes/$THEME/exercices/$EXERCICE/hints" | + [ -n "${CONTENT}" ] && CONTENT=", \"content\": \"${CONTENT}\"" + [ -n "${URI}" ] && URI=", \"path\": \"${BASEFILE}${URI}\"" + + curl -f -s -d "{\"title\": \"$TITLE\"$CONTENT$URI, \"cost\": $COST}" "${BASEURL}/api/themes/$THEME/exercices/$EXERCICE/hints" | grep -Eo '"id":[0-9]+,' | grep -Eo "[0-9]+" } @@ -191,15 +195,28 @@ do # Hints - EXO_HINT=$(get_file "${THM_BASEURI}${EXO_BASEURI}/hint.txt") - if [ -n "$EXO_HINT" ]; then - HINT_ID=`new_hint "${THEME_ID}" "${EXO_ID}" "Astuce #1" "${EXO_HINT}" "${HINT_COST}"` - if [ -z "$HINT_ID" ]; then - echo -e "\e[31;01m!!! An error occured during hint import!\e[00m (title=Astuce #1;content=${EXO_HINT};cost=${HINT_COST})" - else - echo -e "\e[32m>>> New hint added:\e[00m $HINT_ID - Astuce #1" + HINTS=$(get_dir "${THM_BASEURI}${EXO_BASEURI}/hints/" | sed -E 's#(.*)#hints/\1#') + [ -z "${HINTS}" ] && HINTS=$(get_dir "${THM_BASEURI}${EXO_BASEURI}/" | grep ^hint.) + [ -z "${HINTS}" ] && HINTS="hint.txt" + HINT_COUNT=1 + echo "${HINTS}" | while read HINT + do + EXO_HINT=$(get_file "${THM_BASEURI}${EXO_BASEURI}/${HINT}") + if [ -n "$EXO_HINT" ]; then + if echo "${EXO_HINT}" | file --mime-type -b - | grep text/ && [ $(echo "${EXO_HINT}" | wc -l) -lt 25 ]; then + HINT_ID=`new_hint "${THEME_ID}" "${EXO_ID}" "Astuce #${HINT_COUNT}" "${EXO_HINT}" "${HINT_COST}"` + else + HINT_ID=`new_hint "${THEME_ID}" "${EXO_ID}" "Astuce #${HINT_COUNT}" "" "${HINT_COST}" "${THM_BASEURI}${EXO_BASEURI}/${HINT}"` + fi + + if [ -z "$HINT_ID" ]; then + echo -e "\e[31;01m!!! An error occured during hint import!\e[00m (title=Astuce #${HINT_COUNT};content=${EXO_HINT};cost=${HINT_COST})" + else + echo -e "\e[32m>>> New hint added:\e[00m $HINT_ID - Astuce #${HINT_COUNT}" + fi fi - fi + HINT_COUNT=$(($HINT_COUNT + 1)) + done # Files: splited diff --git a/frontend/static/views/theme.html b/frontend/static/views/theme.html index 792cf571..af62f802 100644 --- a/frontend/static/views/theme.html +++ b/frontend/static/views/theme.html @@ -35,8 +35,10 @@
    + Télécharger

    {{ hint.title }}

    -

    +

    +

    Utilisez le bouton pour télécharger l'indice.

    Débloquer cet indice vous coûtera .

    diff --git a/libfic/file.go b/libfic/file.go index 5b3e74ed..658f7a22 100644 --- a/libfic/file.go +++ b/libfic/file.go @@ -69,7 +69,7 @@ func (e Exercice) GetFiles() ([]EFile, error) { } } -func (e Exercice) ImportFile(filePath string, origin string, digest []byte) (EFile, error) { +func (e Exercice) ImportFile(filePath string, origin string, digest []byte) (interface{}, error) { if digest == nil && !OptionalDigest { return EFile{}, errors.New("No digest given.") } else if fi, err := os.Stat(filePath); err != nil { @@ -84,7 +84,6 @@ func (e Exercice) ImportFile(filePath string, origin string, digest []byte) (EFi if _, err := io.Copy(hash, reader); err != nil { return EFile{}, err } - result := hash.Sum(nil) if len(digest) != len(result) { diff --git a/libfic/hint.go b/libfic/hint.go index 123d4a02..6dab02b6 100644 --- a/libfic/hint.go +++ b/libfic/hint.go @@ -1,6 +1,8 @@ package fic import ( + "path" + "strings" ) type EHint struct { @@ -11,11 +13,18 @@ type EHint struct { Cost int64 `json:"cost"` } +func treatHintContent(content *string) { + if strings.HasPrefix(*content, "$FILES") { + *content = "$FILES" + path.Join(FilesDir, strings.TrimPrefix(*content, "$FILES")) + } +} + func GetHint(id int64) (EHint, error) { var h EHint if err := DBQueryRow("SELECT id_hint, id_exercice, title, content, cost FROM exercice_hints WHERE id_hint = ?", id).Scan(&h.Id, &h.IdExercice, &h.Title, &h.Content, &h.Cost); err != nil { return h, err } + treatHintContent(&h.Content) return h, nil } @@ -33,6 +42,7 @@ func (e Exercice) GetHints() ([]EHint, error) { if err := rows.Scan(&h.Id, &h.Title, &h.Content, &h.Cost); err != nil { return nil, err } + treatHintContent(&h.Content) hints = append(hints, h) } if err := rows.Err(); err != nil { From 21e4b04c193dcfa0abdba95932d90c00febafdbc Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sat, 14 Jan 2017 15:03:25 +0100 Subject: [PATCH 0449/2585] frontend: dedicate a field in JSON to file hint --- frontend/static/views/theme.html | 20 +++++++++----------- libfic/hint.go | 22 ++++++++++++---------- libfic/team_my.go | 14 +++++++------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/frontend/static/views/theme.html b/frontend/static/views/theme.html index af62f802..d0c8974e 100644 --- a/frontend/static/views/theme.html +++ b/frontend/static/views/theme.html @@ -30,18 +30,16 @@
    Indices
    - +

    +

    Cliquez ici pour télécharger l'indice.

    +

    Débloquer cet indice vous coûtera .

    +
    +
    diff --git a/libfic/hint.go b/libfic/hint.go index 6dab02b6..a47b3501 100644 --- a/libfic/hint.go +++ b/libfic/hint.go @@ -6,16 +6,18 @@ import ( ) type EHint struct { - Id int64 `json:"id"` - IdExercice int64 `json:"idExercice"` - Title string `json:"title"` + Id int64 `json:"id"` + IdExercice int64 `json:"idExercice"` + Title string `json:"title"` Content string `json:"content"` - Cost int64 `json:"cost"` + File string `json:"file"` + Cost int64 `json:"cost"` } -func treatHintContent(content *string) { - if strings.HasPrefix(*content, "$FILES") { - *content = "$FILES" + path.Join(FilesDir, strings.TrimPrefix(*content, "$FILES")) +func treatHintContent(h *EHint) { + if strings.HasPrefix(h.Content, "$FILES") { + h.File = path.Join(FilesDir, strings.TrimPrefix(h.Content, "$FILES")) + h.Content = "" } } @@ -24,7 +26,7 @@ func GetHint(id int64) (EHint, error) { if err := DBQueryRow("SELECT id_hint, id_exercice, title, content, cost FROM exercice_hints WHERE id_hint = ?", id).Scan(&h.Id, &h.IdExercice, &h.Title, &h.Content, &h.Cost); err != nil { return h, err } - treatHintContent(&h.Content) + treatHintContent(&h) return h, nil } @@ -42,7 +44,7 @@ func (e Exercice) GetHints() ([]EHint, error) { if err := rows.Scan(&h.Id, &h.Title, &h.Content, &h.Cost); err != nil { return nil, err } - treatHintContent(&h.Content) + treatHintContent(&h) hints = append(hints, h) } if err := rows.Err(); err != nil { @@ -59,7 +61,7 @@ func (e Exercice) AddHint(title string, content string, cost int64) (EHint, erro } else if hid, err := res.LastInsertId(); err != nil { return EHint{}, err } else { - return EHint{hid, e.Id, title, content, cost}, nil + return EHint{hid, e.Id, title, content, "", cost}, nil } } diff --git a/libfic/team_my.go b/libfic/team_my.go index 6e5404e9..242d0bb0 100644 --- a/libfic/team_my.go +++ b/libfic/team_my.go @@ -14,11 +14,11 @@ type myTeamFile struct { Size int64 `json:"size"` } type myTeamHint struct { - HintId int64 `json:"id"` - Title string `json:"title"` - Content string `json:"content"` - Cost int64 `json:"cost"` - Unlocked bool `json:"unlocked"` + HintId int64 `json:"id"` + Title string `json:"title"` + Content *string `json:"content"` + File *string `json:"file"` + Cost int64 `json:"cost"` } type myTeamExercice struct { ThemeId int `json:"theme_id"` @@ -99,9 +99,9 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) { } else { for _, h := range hints { if t == nil || t.HasHint(h) { - exercice.Hints = append(exercice.Hints, myTeamHint{h.Id, h.Title, h.Content, h.Cost, true}) + exercice.Hints = append(exercice.Hints, myTeamHint{h.Id, h.Title, &h.Content, &h.File, h.Cost}) } else { - exercice.Hints = append(exercice.Hints, myTeamHint{h.Id, h.Title, "", h.Cost, false}) + exercice.Hints = append(exercice.Hints, myTeamHint{h.Id, h.Title, nil, nil, h.Cost}) } } } From 78ce24f3f720eb465dba7d943ea488ff4d6b5634 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sun, 15 Jan 2017 23:56:28 +0100 Subject: [PATCH 0450/2585] fixup! fixup! WIP esthetic changes --- frontend/static/css/fic.css | 1 - frontend/static/index.html | 4 +-- frontend/static/js/challenge.js | 5 ++-- frontend/static/public.html | 50 ++++++++++++++++++-------------- frontend/static/views/theme.html | 8 ++--- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/frontend/static/css/fic.css b/frontend/static/css/fic.css index 2f9a7d81..081f0c84 100644 --- a/frontend/static/css/fic.css +++ b/frontend/static/css/fic.css @@ -15,7 +15,6 @@ body { } .navbar #clock { font-size: 70px; - text-align: center; } .point, .expired { transition: color text-shadow 1s; diff --git a/frontend/static/index.html b/frontend/static/index.html index 84c638b4..964d927a 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -46,7 +46,7 @@ Epita
    -
    +
    {{ time.hours | time }} : {{ time.minutes | time }} @@ -107,7 +107,7 @@
    diff --git a/frontend/static/js/challenge.js b/frontend/static/js/challenge.js index 6b5d21ee..2dbad794 100644 --- a/frontend/static/js/challenge.js +++ b/frontend/static/js/challenge.js @@ -30,14 +30,12 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) }); $locationProvider.html5Mode(true); }) - .run(function($rootScope, $timeout) { + .run(function($rootScope, $interval) { $rootScope.current_theme = 0; $rootScope.current_exercice = 0; $rootScope.time = {}; function updTime() { - $timeout.cancel($rootScope.cbm); - $rootScope.cbm = $timeout(updTime, 1000); if (sessionStorage.userService) { var time = angular.fromJson(sessionStorage.userService); var srv_cur = (Date.now() + (time.cu * 1000 - time.he)) / 1000; @@ -68,6 +66,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) } } updTime(); + $interval(updTime, 1000); }) .controller("DataController", function($sce, $scope, $http, $rootScope, $timeout) { var actMenu = function() { diff --git a/frontend/static/public.html b/frontend/static/public.html index f3c5411f..b805d76c 100644 --- a/frontend/static/public.html +++ b/frontend/static/public.html @@ -20,7 +20,7 @@ - + -
    +
    +
    - - - - - - + + - - - - + + + + + + + + + + + + + + + +
    Niveau 1Niveau 2Niveau 3Niveau 4Niveau 5
    {{ th.name }}
    {{ themes[th].name }}{{ ex.solved }}{{ ex.tried }}
    Niveau {{ lvl }} + + {{ exercice.solved }} + {{ exercice.tried }} + +
    {{ team.rank }}ere
    {{ team.name }}
    + {{ mystats.themes[tid].solved }}/{{ mystats.themes[tid].total }} + ({{ mystats.themes[tid].tries }}) +
    + Résolus + Total résolus
    + Tentatives +
    + {{ mystats.themes[tid].solved }}
    + {{ mystats.themes[tid].tries }} +
    +
    - +
    +
    @@ -171,31 +156,139 @@ - - - + + +
    PlaceScore
    {{ r.rank }}ere
    {{ r.rank }}ere {{ r.name }} {{ r.score }}
    - - + + -
    +
    -
    +
    +
    {{ e.since | since }}
    - - Epita - + + +
    @@ -209,5 +302,10 @@ + From 416ad65c875229760c71043153181d0b48ef5a5b Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 20 Jan 2017 19:18:43 +0100 Subject: [PATCH 0464/2585] admin: add public interface management --- admin/api/public.go | 80 ++++++++++++++++++++ admin/index.go | 1 + admin/static.go | 3 + admin/static/index.html | 1 + admin/static/js/app.js | 80 ++++++++++++++++++++ admin/static/views/public.html | 129 +++++++++++++++++++++++++++++++++ 6 files changed, 294 insertions(+) create mode 100644 admin/api/public.go create mode 100644 admin/static/views/public.html diff --git a/admin/api/public.go b/admin/api/public.go new file mode 100644 index 00000000..ceccf230 --- /dev/null +++ b/admin/api/public.go @@ -0,0 +1,80 @@ +package api + +import ( + "encoding/json" + "os" + "path" + + "github.com/julienschmidt/httprouter" +) + +func init() { + router.GET("/api/public.json", apiHandler(getPublic)) + router.DELETE("/api/public.json", apiHandler(deletePublic)) + router.PUT("/api/public.json", apiHandler(savePublic)) +} + +type FICPublicScene struct { + Type string `json:"type"` + Params map[string]interface{} `json:"params"` +} + +func readPublic(path string) ([]FICPublicScene, error) { + var s []FICPublicScene + if fd, err := os.Open(path); err != nil { + return s, err + } else { + defer fd.Close() + jdec := json.NewDecoder(fd) + + if err := jdec.Decode(&s); err != nil { + return s, err + } + + return s, nil + } +} + +func savePublicTo(path string, s []FICPublicScene) error { + if fd, err := os.Create(path); err != nil { + return err + } else { + defer fd.Close() + jenc := json.NewEncoder(fd) + + if err := jenc.Encode(s); err != nil { + return err + } + + return nil + } +} + +func getPublic(_ httprouter.Params, body []byte) (interface{}, error) { + if _, err := os.Stat(path.Join(TeamsDir, "_public", "public.json")); !os.IsNotExist(err) { + return readPublic(path.Join(TeamsDir, "_public", "public.json")) + } else { + return []FICPublicScene{}, nil + } +} + +func deletePublic(_ httprouter.Params, body []byte) (interface{}, error) { + if err := savePublicTo(path.Join(TeamsDir, "_public", "public.json"), []FICPublicScene{}); err != nil { + return nil, err + } else { + return []FICPublicScene{}, err + } +} + +func savePublic(_ httprouter.Params, body []byte) (interface{}, error) { + var scenes []FICPublicScene + if err := json.Unmarshal(body, &scenes); err != nil { + return nil, err + } + + if err := savePublicTo(path.Join(TeamsDir, "_public", "public.json"), scenes); err != nil { + return nil, err + } else { + return scenes, err + } +} diff --git a/admin/index.go b/admin/index.go index 85c7448c..7e1270f2 100644 --- a/admin/index.go +++ b/admin/index.go @@ -23,6 +23,7 @@ const indextpl = `
  • Équipes
  • Thèmes
  • Exercices
  • +
  • Public
  • Événements
  • Paramètres
  • diff --git a/admin/static.go b/admin/static.go index ba2bebf5..9d1bb918 100644 --- a/admin/static.go +++ b/admin/static.go @@ -19,6 +19,9 @@ func init() { api.Router().GET("/events/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { http.ServeFile(w, r, path.Join(StaticDir, "index.html")) }) + api.Router().GET("/public", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + http.ServeFile(w, r, path.Join(StaticDir, "index.html")) + }) api.Router().GET("/settings/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { http.ServeFile(w, r, path.Join(StaticDir, "index.html")) }) diff --git a/admin/static/index.html b/admin/static/index.html index dcbd3374..631dd44a 100644 --- a/admin/static/index.html +++ b/admin/static/index.html @@ -21,6 +21,7 @@
  • Équipes
  • Thèmes
  • Exercices
  • +
  • Public
  • Événements
  • Paramètres
  • diff --git a/admin/static/js/app.js b/admin/static/js/app.js index 64a77597..458e49f8 100644 --- a/admin/static/js/app.js +++ b/admin/static/js/app.js @@ -37,6 +37,10 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"]) controller: "TeamNewController", templateUrl: "views/team-new.html" }) + .when("/public", { + controller: "PublicController", + templateUrl: "views/public.html" + }) .when("/events", { controller: "EventsListController", templateUrl: "views/event-list.html" @@ -65,6 +69,11 @@ angular.module("FICApp") 'update': {method: 'PUT'}, }) }) + .factory("Scene", function($resource) { + return $resource("/api/public.json", null, { + 'update': {method: 'PUT'}, + }) + }) .factory("Team", function($resource) { return $resource("/api/teams/:teamId", { teamId: '@id' }, { 'update': {method: 'PUT'}, @@ -228,6 +237,77 @@ angular.module("FICApp") } }) + .controller("PublicController", function($scope, Scene, Theme, Teams, Exercice) { + $scope.scenes = Scene.query(); + $scope.themes = Theme.query(); + $scope.teams = Teams.get(); + + $scope.types = { + "welcome": "Messages de bienvenue", + "message": "Message", + "panel": "Boîte", + "exercice": "Exercice", + "table": "Tableau", + "rank": "Classement", + }; + $scope.welcome_types = { + "init": "Accueil des équipes", + "public": "Accueil du public", + "countdown": "Compte à rebours lancement", + }; + $scope.panel_types = { + "panel-default": "Default", + "panel-info": "Info", + "panel-success": "Success", + "panel-warning": "Warning", + "panel-danger": "Danger", + }; + $scope.rank_types = { + "general": "Classement général", + }; + $scope.table_types = { + "levels": "Niveaux d'exercices", + "teams": "Équipes", + }; + $scope.exercices = Exercice.query(); + + $scope.clearScene = function() { + Scene.delete(function() { + $scope.scenes = []; + }); + }; + $scope.saveScenes = function() { + Scene.update($scope.scenes); + }; + $scope.addScene = function() { + $scope.scenes.push({params: {}}); + }; + $scope.delScene = function(s) { + angular.forEach($scope.scenes, function(scene, k) { + if (scene == s) + $scope.scenes.splice(k, 1); + }); + }; + $scope.upScene = function(s) { + angular.forEach($scope.scenes, function(scene, k) { + if (scene == s && k > 0) { + $scope.scenes.splice(k, 1); + $scope.scenes.splice(k - 1, 0, scene); + } + }); + }; + $scope.downScene = function(s) { + var move = true; + angular.forEach($scope.scenes, function(scene, k) { + if (move && scene == s) { + $scope.scenes.splice(k, 1); + $scope.scenes.splice(k + 1, 0, scene); + move = false; + } + }); + }; + }) + .controller("EventsListController", function($scope, Event, $location) { $scope.events = Event.query(); $scope.fields = ["id", "kind", "txt", "time"]; diff --git a/admin/static/views/public.html b/admin/static/views/public.html new file mode 100644 index 00000000..435d30bd --- /dev/null +++ b/admin/static/views/public.html @@ -0,0 +1,129 @@ +
    +

    Interface publique Vider la scène Ajouter un élément +

    + +
    +
    +
    +
    + +
    +
    +
    + Up + Down +
    + +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    From 544bbb745c7289fd8fe367d8861fe011651e7608 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 20 Jan 2017 20:52:31 +0100 Subject: [PATCH 0465/2585] admin: new route /members/ --- admin/api/team.go | 22 ++++++++++++++++++++++ libfic/member.go | 9 +++++++++ 2 files changed, 31 insertions(+) diff --git a/admin/api/team.go b/admin/api/team.go index 828ff18b..5ae6ddee 100644 --- a/admin/api/team.go +++ b/admin/api/team.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "fmt" + "strconv" "strings" "srs.epita.fr/fic-server/libfic" @@ -62,6 +63,9 @@ func init() { router.GET("/api/teams/:tid/name", apiHandler(teamHandler( func(team fic.Team, _ []byte) (interface{}, error) { return team.InitialName, nil }))) + + router.GET("/api/members/:mid/team", apiHandler(dispMemberTeam)) + router.GET("/api/members/:mid/team/name", apiHandler(dispMemberTeamName)) } func nginxGenMember() (string, error) { @@ -149,3 +153,21 @@ func addTeamMember(team fic.Team, body []byte) (interface{}, error) { return team.GetMembers() } + +func dispMemberTeam(ps httprouter.Params, body []byte) (interface{}, error) { + if mid, err := strconv.Atoi(string(ps.ByName("mid"))); err != nil { + return fic.Team{}, err + } else { + return fic.GetMember(mid) + } +} + +func dispMemberTeamName(ps httprouter.Params, body []byte) (interface{}, error) { + if mid, err := strconv.Atoi(string(ps.ByName("mid"))); err != nil { + return nil, err + } else if team, err := fic.GetMember(mid); err != nil { + return nil, err + } else { + return team.InitialName, nil + } +} diff --git a/libfic/member.go b/libfic/member.go index 7dad3c4c..0b4ce660 100644 --- a/libfic/member.go +++ b/libfic/member.go @@ -10,6 +10,15 @@ type Member struct { Company string `json:"company"` } +func GetMember(cnt int) (Team, error) { + var t Team + if err := DBQueryRow("SELECT T.id_team, T.initial_name, T.name, T.color FROM team_members M RIGHT OUTER JOIN teams T ON T.id_team = M.id_team LIMIT ?, 1", cnt - 1).Scan(&t.Id, &t.InitialName, &t.Name, &t.Color); err != nil { + return t, err + } + + return t, nil +} + func (t Team) GetMembers() ([]Member, error) { if rows, err := DBQuery("SELECT id_member, firstname, lastname, nickname, company FROM team_members WHERE id_team = ?", t.Id); err != nil { return nil, err From 318bc4bc4d616907f164ae6f198d8760515ee7c5 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 20 Jan 2017 20:53:32 +0100 Subject: [PATCH 0466/2585] Update openssl settings --- admin/pki/openssl.cnf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/pki/openssl.cnf b/admin/pki/openssl.cnf index 495674f9..1848365b 100644 --- a/admin/pki/openssl.cnf +++ b/admin/pki/openssl.cnf @@ -101,7 +101,7 @@ emailAddress = optional #################################################################### [ req ] -default_bits = 2048 +default_bits = 4096 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes From 17f51f5e7b45821d0f59135b05b39cf4a410c1d5 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 24 Jan 2017 02:14:28 +0100 Subject: [PATCH 0467/2585] admin: can force page regeneration --- admin/api/settings.go | 2 +- admin/static/js/app.js | 4 ++++ admin/static/views/settings.html | 4 +++- backend/main.go | 6 +++++- settings/settings.go | 1 + 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/admin/api/settings.go b/admin/api/settings.go index 31bc7446..40afef56 100644 --- a/admin/api/settings.go +++ b/admin/api/settings.go @@ -22,7 +22,7 @@ func getSettings(_ httprouter.Params, body []byte) (interface{}, error) { if settings.ExistsSettings(path.Join(TeamsDir, settings.SettingsFile)) { return settings.ReadSettings(path.Join(TeamsDir, settings.SettingsFile)) } else { - return settings.FICSettings{time.Unix(0,0), time.Unix(0,0), fic.FirstBlood, fic.SubmissionCostBase, false, false, false, true, true}, nil + return settings.FICSettings{time.Unix(0,0), time.Unix(0,0), time.Unix(0,0), fic.FirstBlood, fic.SubmissionCostBase, false, false, false, true, true}, nil } } diff --git a/admin/static/js/app.js b/admin/static/js/app.js index 458e49f8..34366490 100644 --- a/admin/static/js/app.js +++ b/admin/static/js/app.js @@ -228,6 +228,10 @@ angular.module("FICApp") $location.url("/"); }); } + $scope.regenerate = function() { + this.config.generation = (new Date()).toISOString(); + $scope.saveSettings(); + } $scope.launchChallenge = function() { var ts = Date.now() - Date.now() % 60000; var d = new Date(ts + 120000); diff --git a/admin/static/views/settings.html b/admin/static/views/settings.html index fe15a1dc..97aebc06 100644 --- a/admin/static/views/settings.html +++ b/admin/static/views/settings.html @@ -1,7 +1,9 @@ -

    Paramètres

    +

    Paramètres Regénérer les fichiers statiques

    + +
    diff --git a/backend/main.go b/backend/main.go index b0d660ee..6b458107 100644 --- a/backend/main.go +++ b/backend/main.go @@ -43,8 +43,12 @@ func watchsubdir(watcher *fsnotify.Watcher, pathname string) error { } } +var lastRegeneration time.Time + func reloadSettings(config settings.FICSettings) { - if fic.PartialValidation != config.PartialValidation || fic.UnlockedChallenges != !config.EnableExerciceDepend || fic.FirstBlood != config.FirstBlood || fic.SubmissionCostBase != config.SubmissionCostBase { + if lastRegeneration != config.Generation || fic.PartialValidation != config.PartialValidation || fic.UnlockedChallenges != !config.EnableExerciceDepend || fic.FirstBlood != config.FirstBlood || fic.SubmissionCostBase != config.SubmissionCostBase { + lastRegeneration = config.Generation + fic.PartialValidation = config.PartialValidation fic.UnlockedChallenges = !config.EnableExerciceDepend diff --git a/settings/settings.go b/settings/settings.go index 6775c03c..d327663c 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -15,6 +15,7 @@ const SettingsFile = "settings.json" type FICSettings struct { Start time.Time `json:"start"` End time.Time `json:"end"` + Generation time.Time `json:"generation"` FirstBlood float64 `json:"firstBlood"` SubmissionCostBase float64 `json:"submissionCostBase"` From 4fe641a9f5183a028a39b02cb2893293bac15fa5 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 24 Jan 2017 02:17:21 +0100 Subject: [PATCH 0468/2585] change the way themes are stored in stats --- admin/static/js/app.js | 6 +++++- libfic/team_stats.go | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/admin/static/js/app.js b/admin/static/js/app.js index 34366490..34d64d68 100644 --- a/admin/static/js/app.js +++ b/admin/static/js/app.js @@ -480,7 +480,11 @@ angular.module("FICApp") $scope.teamstats = TeamStats.get({ teamId: $routeParams.teamId }); $scope.teamstats.$promise.then(function(res) { solvedByLevelPie("#pieLevels", res.levels); - solvedByThemesPie("#pieThemes", res.themes); + var themes = []; + angular.forEach(res.themes, function(theme, tid) { + themes.push(theme); + }) + solvedByThemesPie("#pieThemes", themes); }); }) .controller("TeamExercicesController", function($scope, Teams, Themes, TeamMy, Exercice, $routeParams) { diff --git a/libfic/team_stats.go b/libfic/team_stats.go index a9ef4112..300dbe7b 100644 --- a/libfic/team_stats.go +++ b/libfic/team_stats.go @@ -13,8 +13,8 @@ type statLine struct { } type teamStats struct { - Levels []statLine `json:"levels"` - Themes []statLine `json:"themes"` + Levels []statLine `json:"levels"` + Themes map[int64]statLine `json:"themes"` } func (s *teamStats) GetLevel(level int) *statLine { @@ -38,7 +38,10 @@ func (t Team) GetStats() (interface{}, error) { } func GetTeamsStats(t *Team) (interface{}, error) { - stat := teamStats{} + stat := teamStats{ + []statLine{}, + map[int64]statLine{}, + } if themes, err := GetThemes(); err != nil { return nil, err @@ -84,13 +87,13 @@ func GetTeamsStats(t *Team) (interface{}, error) { } } - stat.Themes = append(stat.Themes, statLine{ + stat.Themes[theme.Id] = statLine{ theme.Name, total, solved, tried, tries, - }) + } } return stat, nil From cab95b79856b3a03586fbb56fb167151b415493b Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 24 Jan 2017 02:18:05 +0100 Subject: [PATCH 0469/2585] libfic: new function to retrieve exercices from a hint --- libfic/hint.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libfic/hint.go b/libfic/hint.go index a47b3501..d329c692 100644 --- a/libfic/hint.go +++ b/libfic/hint.go @@ -84,3 +84,12 @@ func (h EHint) Delete() (int64, error) { return nb, err } } + +func (h EHint) GetExercice() (Exercice, error) { + var eid int64 + if err := DBQueryRow("SELECT id_exercice FROM exercice_hints WHERE id_hint = ?", h.Id).Scan(&eid); err != nil { + return Exercice{}, err + } + + return GetExercice(eid) +} From cb1fe0847b1f9ad99496bf8e643aeceefddb0a82 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 24 Jan 2017 02:19:49 +0100 Subject: [PATCH 0470/2585] frontend: move file (on the same partition) instead of open, write, close the final file --- frontend/main.go | 6 ++++-- frontend/save.go | 46 +++++++++++++++++----------------------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/frontend/main.go b/frontend/main.go index 30c6cb31..3c939ef4 100644 --- a/frontend/main.go +++ b/frontend/main.go @@ -17,6 +17,7 @@ const startedFile = "started" var TeamsDir string var SubmissionDir string +var TmpSubmissionDir string var touchTimer *time.Timer = nil @@ -70,10 +71,11 @@ func main() { log.SetPrefix("[frontend] ") SubmissionDir = path.Clean(SubmissionDir) + TmpSubmissionDir = path.Join(SubmissionDir, ".tmp") log.Println("Creating submission directory...") - if _, err := os.Stat(SubmissionDir); os.IsNotExist(err) { - if err := os.MkdirAll(SubmissionDir, 0777); err != nil { + if _, err := os.Stat(TmpSubmissionDir); os.IsNotExist(err) { + if err := os.MkdirAll(TmpSubmissionDir, 0777); err != nil { log.Fatal("Unable to create submission directory: ", err) } } diff --git a/frontend/save.go b/frontend/save.go index 8e87cbc4..bb2009b9 100644 --- a/frontend/save.go +++ b/frontend/save.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "io/ioutil" "log" "net/http" @@ -42,40 +43,27 @@ func saveFile(dirname string, filename string, r *http.Request) error { } } - var f *os.File + // Write content to temp file + tmpfile, err := ioutil.TempFile(TmpSubmissionDir, "") + if err != nil { + return err + } + + writer := bufio.NewWriter(tmpfile) + reader := bufio.NewReader(r.Body) + if _, err := reader.WriteTo(writer); err != nil { + return err + } + writer.Flush() + tmpfile.Close() if filename == "" { - if fd, err := ioutil.TempFile(dirname, ""); err != nil { - return err - } else { - defer f.Close() - f = fd - } - } else { - if fd, err := os.Create(path.Join(dirname, filename)); err != nil { - return err - } else { - defer f.Close() - f = fd - } + filename = path.Base(tmpfile.Name()) } - // Read request body - var body []byte - if r.ContentLength > 0 { - tmp := make([]byte, 1024) - for { - n, err := r.Body.Read(tmp) - for j := 0; j < n; j++ { - body = append(body, tmp[j]) - } - if err != nil || n <= 0 { - break - } - } + if err := os.Rename(tmpfile.Name(), path.Join(dirname, filename)); err != nil { + log.Println("[ERROR] Unable to move file: ", err) } - f.Write(body) - return nil } From c1c84ba3d1b31c4d8f6a1db814ca16166ee8fe59 Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 24 Jan 2017 02:20:20 +0100 Subject: [PATCH 0471/2585] backend: generate an event when a team open an hint --- backend/hint.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/hint.go b/backend/hint.go index 17124f5b..2a074a31 100644 --- a/backend/hint.go +++ b/backend/hint.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "fmt" "log" "io/ioutil" "os" @@ -28,6 +29,17 @@ func treatOpeningHint(pathname string, team fic.Team) { } else if err := team.OpenHint(hint); err != nil { log.Println("[ERR]", err) } else { + // Write event + if exercice, err := hint.GetExercice(); err != nil { + log.Println("[WRN]", err) + } else if lvl, err := exercice.GetLevel(); err != nil { + log.Println("[WRN]", err) + } else if theme, err := exercice.GetTheme(); err != nil { + log.Println("[WRN]", err) + } else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a dévoilé un indice pour le %de challenge %s !", team.Name, lvl, theme.Name), "alert-info"); err != nil { + log.Println("[WRN] Unable to create event:", err) + } + genTeamMyFile(team) if err := os.Remove(pathname); err != nil { log.Println("[ERR]", err) From da0e7facfddaf5380d56e09bad33f250ecd5bb8a Mon Sep 17 00:00:00 2001 From: nemunaire Date: Tue, 24 Jan 2017 02:21:21 +0100 Subject: [PATCH 0472/2585] frontend: improve 401 page thank to initial guide --- frontend/static/css/fic.css | 32 ++++++++ frontend/static/welcome.html | 137 ++++++++++++++++++++++++++++++----- 2 files changed, 151 insertions(+), 18 deletions(-) diff --git a/frontend/static/css/fic.css b/frontend/static/css/fic.css index 0c186d5f..14d20d4f 100644 --- a/frontend/static/css/fic.css +++ b/frontend/static/css/fic.css @@ -1,10 +1,42 @@ +@font-face { + font-family: "Linux Biolinum"; + src: url('../fonts/LinBiolinum_R.woff') format('woff'); +} +@font-face { + font-family: "Linux Biolinum"; + src: url('../fonts/LinBiolinum_RB.woff') format('woff'); + font-weight: bold; +} +@font-face { + font-family: "Linux Biolinum"; + src: url('../fonts/LinBiolinum_RI.woff') format('woff'); + font-style: italic; +} + +[ng-cloak] { + display:none !important; +} + body { overflow-y: scroll; } +.beautiful { + font-family: "Linux Biolinum",Helvetica,Arial,sans-serif; +} +.beautiful ol { + font-size: 133%; +} +.beautiful ol ol { + font-size: 90%; +} + .text-bold { font-weight: bolder; } +.text-indent p { + text-indent: 1em; +} .navbar { margin-bottom: 0; diff --git a/frontend/static/welcome.html b/frontend/static/welcome.html index 20ccbbe1..8455c639 100644 --- a/frontend/static/welcome.html +++ b/frontend/static/welcome.html @@ -1,5 +1,5 @@ - + Challenge Forensic @@ -18,22 +18,22 @@ - +

    -
    +
    {{ team.id }}
    -
    +
    - +

    -
    +
    diff --git a/admin/static/views/team-new.html b/admin/static/views/team-new.html deleted file mode 100644 index 8f1f14ee..00000000 --- a/admin/static/views/team-new.html +++ /dev/null @@ -1,11 +0,0 @@ -

    New team

    - -
    - -
    -
    - -
    -
    - -
    From 4a97b065203784da2a55bf22951a50d791beabca Mon Sep 17 00:00:00 2001 From: nemunaire Date: Sat, 4 Nov 2017 15:15:54 +0100 Subject: [PATCH 0498/2585] Set SQL_MODES, waiting https://jira.mariadb.org/browse/MDEV-10426 to be solved --- libfic/db.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfic/db.go b/libfic/db.go index a08dfc00..e10967ea 100644 --- a/libfic/db.go +++ b/libfic/db.go @@ -38,6 +38,9 @@ func DBInit(dsn string) error { if db, err = sql.Open("mysql", dsn + "?parseTime=true&foreign_key_checks=1"); err != nil { return err } + if _, err := db.Exec(`SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';`); err != nil { + return err + } return nil } From 510e25e3515649d6b4c2b4fdee6ed90a120a3fad Mon Sep 17 00:00:00 2001 From: nemunaire Date: Fri, 10 Nov 2017 20:23:08 +0100 Subject: [PATCH 0499/2585] frontend: fix timer location --- frontend/static/public.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/static/public.html b/frontend/static/public.html index 8833201d..4040831f 100644 --- a/frontend/static/public.html +++ b/frontend/static/public.html @@ -179,8 +179,8 @@
    -